From 7f5a7f9fcd7e4f36b0ac18ebff0b475480117638 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Tue, 15 Jul 2025 15:57:18 -0400 Subject: [PATCH 1/4] remove utils and test --- business_rules/utils.py | 177 ---------------------------------------- tests/test_utils.py | 30 ------- 2 files changed, 207 deletions(-) delete mode 100644 tests/test_utils.py diff --git a/business_rules/utils.py b/business_rules/utils.py index 8371516..f9d44e7 100644 --- a/business_rules/utils.py +++ b/business_rules/utils.py @@ -1,12 +1,5 @@ -from decimal import Decimal, Inexact, Context -from datetime import datetime, tzinfo -import re import inspect -import numpy as np from dateutil.parser import parse, isoparse -import pytz - -date_regex = re.compile(r'^((-?[0-9]{4}|-)(-(1[0-2]|0[1-9]|-)(-(3[01]|0[1-9]|[12][0-9]|-)(T(2[0-3]|[01][0-9]|-)(:([0-5][0-9]|-)((:([0-5][0-9]|-))?(\.[0-9]+)?((Z|[+-](:2[0-3]|[01][0-9]):[0-5][0-9]))?)?)?)?)?)?)(\/((-?[0-9]{4}|-)(-(1[0-2]|0[1-9]|-)(-(3[01]|0[1-9]|[12][0-9]|-)(T(2[0-3]|[01][0-9]|-)(:([0-5][0-9]|-)((:([0-5][0-9]|-))?(\.[0-9]+)?((Z|[+-](:2[0-3]|[01][0-9]):[0-5][0-9]))?)?)?)?)?)?))?$') def fn_name_to_pretty_label(name): return ' '.join([w.title() for w in name.split('_')]) @@ -30,173 +23,3 @@ def export_rule_data(variables, actions): return {"variables": variables_data, "actions": actions_data, "variable_type_operators": variable_type_operators} - -def float_to_decimal(f): - """ - Convert a floating point number to a Decimal with - no loss of information. Intended for Python 2.6 where - casting float to Decimal does not work. - """ - n, d = f.as_integer_ratio() - numerator, denominator = Decimal(n), Decimal(d) - ctx = Context(prec=60) - result = ctx.divide(numerator, denominator) - while ctx.flags[Inexact]: - ctx.flags[Inexact] = False - ctx.prec *= 2 - result = ctx.divide(numerator, denominator) - return result - -def is_valid_date(date_string: str) -> bool: - if date_string is None: - return False - try: - isoparse(date_string) - except: - uncertainty_substrings = ["/", "--", "-:"] - if any([substr in date_string for substr in uncertainty_substrings]): - # date_string contains uncertainty - # will not parse with isoparse - return date_regex.match(date_string) is not None - else: - return False - return date_regex.match(date_string) is not None - -def is_valid_duration(duration: str, negative) -> bool: - if not isinstance(duration, str): - duration = str(duration) - if negative: - pattern = r'^[-]?P(?!$)(?:(?:(\d+(?:[.,]\d*)?Y)?[,]?(\d+(?:[.,]\d*)?M)?[,]?(\d+(?:[.,]\d*)?D)?[,]?(T(?=\d)(?:(\d+(?:[.,]\d*)?H)?[,]?(\d+(?:[.,]\d*)?M)?[,]?(\d+(?:[.,]\d*)?S)?)?)?)|(\d+(?:[.,]\d*)?W))$' - else: - pattern = r'^P(?!$)(?:(?:(\d+(?:[.,]\d*)?Y)?[,]?(\d+(?:[.,]\d*)?M)?[,]?(\d+(?:[.,]\d*)?D)?[,]?(T(?=\d)(?:(\d+(?:[.,]\d*)?H)?[,]?(\d+(?:[.,]\d*)?M)?[,]?(\d+(?:[.,]\d*)?S)?)?)?)|(\d+(?:[.,]\d*)?W))$' - match = re.match(pattern, duration) - if not match: - return False - - years, months, days, time_designator, hours, minutes, seconds, weeks = match.groups() - - if time_designator and not any([hours, minutes, seconds]): - return False - - components = [c for c in [years, months, weeks, days, hours, minutes, seconds] if c is not None] - - # Check if decimal is only in the smallest unit - decimal_found = False - for i, component in enumerate(components): - if '.' in component or ',' in component: - if decimal_found or i != len(components) - 1: - return False - decimal_found = True - - return True - -def get_year(date_string: str): - timestamp = get_date(date_string) - return timestamp.year - -def get_month(date_string: str): - timestamp = get_date(date_string) - return timestamp.month - -def get_day(date_string: str): - timestamp = get_date(date_string) - return timestamp.day - -def get_hour(date_string: str): - timestamp = get_date(date_string) - return timestamp.hour - -def get_minute(date_string: str): - timestamp = get_date(date_string) - return timestamp.minute - -def get_second(date_string: str): - timestamp = get_date(date_string) - return timestamp.second - -def get_microsecond(date_string: str): - timestamp = get_date(date_string) - return timestamp.microsecond - -def get_date_component(component: str, date_string: str): - component_func_map = { - "year": get_year, - "month": get_month, - "day": get_day, - "hour": get_hour, - "minute": get_minute, - "microsecond": get_microsecond, - "second": get_second - } - component_function = component_func_map.get(component) - if component_function: - return component_function(date_string) - else: - return get_date(date_string) - -def get_date(date_string: str): - """ - Returns a utc timestamp for comparison - """ - date = parse(date_string) - utc = pytz.UTC - if date.tzinfo is not None and date.tzinfo.utcoffset(date) is not None: - # timezone aware - return date.astimezone(utc) - else: - return utc.localize(date) - -def is_complete_date(date_string: str) -> bool: - try: - datetime.fromisoformat(date_string) - except: - try: - datetime.fromisoformat(date_string.replace('Z', '+00:00')) - except: - return False - return True - return True - -def get_dict_key_val(dict_to_get: dict, key): - return dict_to_get.get(key) - -def is_in(value, values): - if values is None: - return False - return value in values - -def case_insensitive_is_in(value, values): - return str(value).lower() in str(values).lower() - -def compare_dates(component, target, comparator, operator): - if not target or not comparator: - # Comparison should return false if either is empty or None - return False - else: - return operator(get_date_component(component, target), get_date_component(component, comparator)) - -def apply_regex(regex: str, val: str): - result = re.findall(regex, val) - if result: - return result[0] - else: - return None -def flatten_list(data, l): - for item in l: - if isinstance(item, list): - yield from flatten_list(data, item) - elif item in data and isinstance(data[item].iloc[0], list): - for val in data[item].iloc[0]: - yield val - else: - yield item - -vectorized_apply_regex = np.vectorize(apply_regex) -vectorized_is_complete_date = np.vectorize(is_complete_date) -vectorized_compare_dates = np.vectorize(compare_dates) -vectorized_is_valid = np.vectorize(is_valid_date) -vectorized_is_valid_duration = np.vectorize(is_valid_duration) -vectorized_get_dict_key = np.vectorize(get_dict_key_val) -vectorized_is_in = np.vectorize(is_in) -vectorized_case_insensitive_is_in = np.vectorize(case_insensitive_is_in) -vectorized_len = np.vectorize(len) diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index a88253e..0000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,30 +0,0 @@ -from . import TestCase -from business_rules.utils import flatten_list -import pandas as pd - -class UtilitiyTests(TestCase): - """ Test utility functions - """ - def test_flatten_list_array_in_dataframe(self): - """ Flatten list should return the array values if a value in the list argument is: - 1. A column in the dataset - 2. The column in is a column of arrays - """ - data = pd.DataFrame.from_dict({ - "ARRAYDATA": [[1,2,4], [1,2,4], [1,2,4]], - "STRINGDATA": ["A", "B", "C"] - }) - - assert list(flatten_list(data, ["ARRAYDATA"])) == [1,2,4] - - def test_flatten_list(self): - """ Flatten list should return the column name, if a value in the list argument is: - 1. A column in the dataset - 2. Not a column of arrays - """ - data = pd.DataFrame.from_dict({ - "ARRAYDATA": [[1,2,4], [1,2,4], [1,2,4]], - "STRINGDATA": ["A", "B", "C"] - }) - - assert list(flatten_list(data, ["STRINGDATA"])) == ["STRINGDATA"] From 2c0e306e1d7d42d91a27de07bbcf969649164fec Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Tue, 15 Jul 2025 17:51:23 -0400 Subject: [PATCH 2/4] moved to engine, removed tests --- business_rules/__init__.py | 2 +- business_rules/operators.py | 1274 +---------------- business_rules/six.py | 2 +- business_rules/utils.py | 1 - business_rules/variables.py | 32 +- tests/test_dataframe_type/__init__.py | 6 - tests/test_dataframe_type/test_contains.py | 208 --- .../test_dataframe_type/test_is_unique_set.py | 136 -- .../test_dataframe_type/test_length_checks.py | 94 -- .../test_numeric_comparison.py | 197 --- .../test_prefix_contained_by_operators.py | 93 -- .../test_present_on_multiple_rows_within.py | 93 -- .../test_string_part_comparison.py | 36 - tests/test_dataframe_type/test_valid_date.py | 62 - .../test_value_has_multiple_references.py | 32 - .../test_variable_metadata_equality.py | 34 - tests/test_variables.py | 147 -- tests/test_variables_class.py | 31 - 18 files changed, 5 insertions(+), 2475 deletions(-) delete mode 100644 tests/test_dataframe_type/__init__.py delete mode 100644 tests/test_dataframe_type/test_contains.py delete mode 100644 tests/test_dataframe_type/test_is_unique_set.py delete mode 100644 tests/test_dataframe_type/test_length_checks.py delete mode 100644 tests/test_dataframe_type/test_numeric_comparison.py delete mode 100644 tests/test_dataframe_type/test_prefix_contained_by_operators.py delete mode 100644 tests/test_dataframe_type/test_present_on_multiple_rows_within.py delete mode 100644 tests/test_dataframe_type/test_string_part_comparison.py delete mode 100644 tests/test_dataframe_type/test_valid_date.py delete mode 100644 tests/test_dataframe_type/test_value_has_multiple_references.py delete mode 100644 tests/test_dataframe_type/test_variable_metadata_equality.py delete mode 100644 tests/test_variables.py diff --git a/business_rules/__init__.py b/business_rules/__init__.py index 55b4868..2e028c0 100644 --- a/business_rules/__init__.py +++ b/business_rules/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.4.7" +__version__ = "1.4.8" from .engine import run_all from .utils import export_rule_data diff --git a/business_rules/operators.py b/business_rules/operators.py index 4f63340..f57c06a 100644 --- a/business_rules/operators.py +++ b/business_rules/operators.py @@ -1,23 +1,6 @@ import inspect -import re from functools import wraps -from typing import Union, Any, List, Tuple -from uuid import uuid4 -import pandas -from pandas.api.types import is_integer_dtype -import sys - -from .six import string_types, integer_types - -from .fields import (FIELD_DATAFRAME, FIELD_TEXT, FIELD_NUMERIC, FIELD_NO_INPUT, - FIELD_SELECT, FIELD_SELECT_MULTIPLE) -from .utils import flatten_list, fn_name_to_pretty_label, float_to_decimal, vectorized_is_valid, vectorized_compare_dates, \ - vectorized_is_complete_date, vectorized_len, vectorized_get_dict_key, vectorized_is_in, vectorized_case_insensitive_is_in, \ - vectorized_apply_regex, apply_regex -from decimal import Decimal, Inexact, Context -import operator -import numpy as np -import pandas as pd +from .utils import fn_name_to_pretty_label class BaseType(object): def __init__(self, value): @@ -62,1257 +45,4 @@ def inner(self, *args, **kwargs): for k, v in kwargs.items()) return func(self, *args, **kwargs) return inner - return wrapper - - -@export_type -class StringType(BaseType): - - name = "string" - - def _assert_valid_value_and_cast(self, value): - value = value or "" - if not isinstance(value, string_types): - raise AssertionError("{0} is not a valid string type.". - format(value)) - return value - - @type_operator(FIELD_TEXT) - def equal_to(self, other_string): - return self.value == other_string - - @type_operator(FIELD_TEXT) - def not_equal_to(self, other_string): - return self.value != other_string - - @type_operator(FIELD_TEXT, label="Equal To (case insensitive)") - def equal_to_case_insensitive(self, other_string): - return self.value.lower() == other_string.lower() - - @type_operator(FIELD_TEXT) - def starts_with(self, other_string): - return self.value.startswith(other_string) - - @type_operator(FIELD_TEXT) - def ends_with(self, other_string): - return self.value.endswith(other_string) - - @type_operator(FIELD_TEXT) - def contains(self, other_string): - return other_string in self.value - - @type_operator(FIELD_TEXT) - def matches_regex(self, regex): - return re.search(regex, self.value) - - @type_operator(FIELD_NO_INPUT) - def non_empty(self): - return bool(self.value) - - -@export_type -class NumericType(BaseType): - EPSILON = Decimal('0.000001') - - name = "numeric" - - @staticmethod - def _assert_valid_value_and_cast(value): - if isinstance(value, float): - # In python 2.6, casting float to Decimal doesn't work - return float_to_decimal(value) - if isinstance(value, integer_types): - return Decimal(value) - if isinstance(value, Decimal): - return value - else: - raise AssertionError("{0} is not a valid numeric type.". - format(value)) - - @type_operator(FIELD_NUMERIC) - def equal_to(self, other_numeric): - return abs(self.value - other_numeric) <= self.EPSILON - - @type_operator(FIELD_NUMERIC) - def not_equal_to(self, other_numeric): - return abs(self.value - other_numeric) > self.EPSILON - - @type_operator(FIELD_NUMERIC) - def greater_than(self, other_numeric): - return (self.value - other_numeric) > self.EPSILON - - @type_operator(FIELD_NUMERIC) - def greater_than_or_equal_to(self, other_numeric): - return self.greater_than(other_numeric) or self.equal_to(other_numeric) - - @type_operator(FIELD_NUMERIC) - def less_than(self, other_numeric): - return (other_numeric - self.value) > self.EPSILON - - @type_operator(FIELD_NUMERIC) - def less_than_or_equal_to(self, other_numeric): - return self.less_than(other_numeric) or self.equal_to(other_numeric) - - -@export_type -class BooleanType(BaseType): - - name = "boolean" - - def _assert_valid_value_and_cast(self, value): - if type(value) != bool: - raise AssertionError("{0} is not a valid boolean type". - format(value)) - return value - - @type_operator(FIELD_NO_INPUT) - def is_true(self): - return self.value - - @type_operator(FIELD_NO_INPUT) - def is_false(self): - return not self.value - -@export_type -class SelectType(BaseType): - - name = "select" - - def _assert_valid_value_and_cast(self, value): - if not hasattr(value, '__iter__'): - raise AssertionError("{0} is not a valid select type". - format(value)) - return value - - @staticmethod - def _case_insensitive_equal_to(value_from_list, other_value): - if isinstance(value_from_list, string_types) and \ - isinstance(other_value, string_types): - return value_from_list.lower() == other_value.lower() - else: - return value_from_list == other_value - - @type_operator(FIELD_SELECT, assert_type_for_arguments=False) - def contains(self, other_value): - for val in self.value: - if self._case_insensitive_equal_to(val, other_value): - return True - return False - - @type_operator(FIELD_SELECT, assert_type_for_arguments=False) - def does_not_contain(self, other_value): - for val in self.value: - if self._case_insensitive_equal_to(val, other_value): - return False - return True - - -@export_type -class SelectMultipleType(BaseType): - - name = "select_multiple" - - def _assert_valid_value_and_cast(self, value): - if not hasattr(value, '__iter__'): - raise AssertionError("{0} is not a valid select multiple type". - format(value)) - return value - - @type_operator(FIELD_SELECT_MULTIPLE) - def contains_all(self, other_value): - select = SelectType(self.value) - for other_val in other_value: - if not select.contains(other_val): - return False - return True - - @type_operator(FIELD_SELECT_MULTIPLE) - def is_contained_by(self, other_value): - other_select_multiple = SelectMultipleType(other_value) - return other_select_multiple.contains_all(self.value) - - @type_operator(FIELD_SELECT_MULTIPLE) - def is_not_contained_by(self, other_value): - return not self.is_contained_by(other_value) - - @type_operator(FIELD_SELECT_MULTIPLE) - def shares_at_least_one_element_with(self, other_value): - select = SelectType(self.value) - for other_val in other_value: - if select.contains(other_val): - return True - return False - - @type_operator(FIELD_SELECT_MULTIPLE) - def shares_exactly_one_element_with(self, other_value): - found_one = False - select = SelectType(self.value) - for other_val in other_value: - if select.contains(other_val): - if found_one: - return False - found_one = True - return found_one - - @type_operator(FIELD_SELECT_MULTIPLE) - def shares_no_elements_with(self, other_value): - return not self.shares_at_least_one_element_with(other_value) - -@export_type -class DataframeType(BaseType): - - name = "dataframe" - - def __init__(self, data): - self.value: pd.DataFrame = self._assert_valid_value_and_cast(data["value"]) - self.column_prefix_map = data.get("column_prefix_map", {}) - self.relationship_data = data.get("relationship_data", {}) - self.value_level_metadata = data.get("value_level_metadata", []) - self.column_codelist_map = data.get("column_codelist_map", {}) - self.codelist_term_maps = data.get("codelist_term_maps", []) - - def _assert_valid_value_and_cast(self, value): - if not hasattr(value, '__iter__'): - raise AssertionError("{0} is not a valid select multiple type". - format(value)) - return value - - def convert_string_data_to_lower(self, data): - if isinstance(data, pd.core.series.Series): - data = data.str.lower() - else: - data = data.lower() - return data - - def replace_prefix(self, value: str) -> Union[str, Any]: - if isinstance(value, str): - for prefix, replacement in self.column_prefix_map.items(): - if value.startswith(prefix): - return value.replace(prefix, replacement, 1) - return value - - def replace_all_prefixes(self, values: List[str]) -> List[str]: - for i in range(len(values)): - values[i] = self.replace_prefix(values[i]) - return values - - def get_comparator_data(self, comparator, value_is_literal: bool = False) -> Union[str, int, pd.Series]: - if value_is_literal: - return comparator - else: - return self.value.get(comparator, comparator) - - def is_column_of_iterables(self, column): - return isinstance(column, pandas.core.series.Series) and (isinstance(column.iloc[0], list) or isinstance(column.iloc[0], set)) - - @type_operator(FIELD_DATAFRAME) - def exists(self, other_value) -> pd.Series: - target_column = self.replace_prefix(other_value.get("target")) - return pd.Series([target_column in self.value] * len(self.value)) - - @type_operator(FIELD_DATAFRAME) - def not_exists(self, other_value): - return ~self.exists(other_value) - - def _check_equality(self, row, target, comparator, value_is_literal: bool = False, case_insensitive: bool = False) -> bool: - """ - Equality checks work slightly differently for clinical datasets. See truth table below: - Operator --A --B Outcome - equal_to "" or null "" or null False - equal_to "" or null Populated False - equal_to Populated "" or null False - equal_to Populated Populated A == B - """ - comparison_data = comparator if comparator not in row or value_is_literal else row[comparator] - both_null = (comparison_data == "" or comparison_data is None) & (row[target] == "" or row[target] is None) - if both_null: - return False - if case_insensitive: - target_val = row[target].lower() if row[target] else None - comparison_val = comparison_data.lower() if comparison_data else None - return target_val == comparison_val - return row[target] == comparison_data - - def _check_inequality(self, row, target, comparator, value_is_literal: bool = False, case_insensitive: bool = False) -> bool: - """ - Equality checks work slightly differently for clinical datasets. See truth table below: - Operator --A --B Outcome - not_equal_to "" or null "" or null False - not_equal_to "" or null Populated True - not_equal_to Populated "" or null True - not_equal_to Populated Populated A != B - """ - comparison_data = comparator if comparator not in row or value_is_literal else row[comparator] - both_null = (comparison_data == "" or comparison_data is None) & (row[target] == "" or row[target] is None) - if both_null: - return False - if case_insensitive: - target_val = row[target].lower() if row[target] else None - comparison_val = comparison_data.lower() if comparison_data else None - return target_val != comparison_val - return row[target] != comparison_data - - @type_operator(FIELD_DATAFRAME) - def equal_to(self, other_value) -> pd.Series: - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - return self.value.apply(lambda row: self._check_equality(row, target, comparator, value_is_literal), axis=1) - - @type_operator(FIELD_DATAFRAME) - def equal_to_case_insensitive(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - return self.value.apply(lambda row: self._check_equality(row, target, comparator, value_is_literal, case_insensitive=True), axis=1) - - @type_operator(FIELD_DATAFRAME) - def not_equal_to_case_insensitive(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - return self.value.apply(lambda row: self._check_inequality(row, target, comparator, value_is_literal, case_insensitive=True), axis=1) - - @type_operator(FIELD_DATAFRAME) - def not_equal_to(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - return self.value.apply(lambda row: self._check_inequality(row, target, comparator, value_is_literal), axis=1) - - @type_operator(FIELD_DATAFRAME) - def suffix_equal_to(self, other_value: dict) -> pd.Series: - """ - Checks if target suffix is equal to comparator. - """ - target: str = self.replace_prefix(other_value.get("target")) - value_is_literal: bool = other_value.get("value_is_literal", False) - comparator: Union[str, Any] = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - suffix: int = self.replace_prefix(other_value.get("suffix")) - return self._check_equality_of_string_part(target, comparison_data, "suffix", suffix) - - @type_operator(FIELD_DATAFRAME) - def suffix_not_equal_to(self, other_value: dict) -> pd.Series: - """ - Checks if target suffix is not equal to comparator. - """ - return ~self.suffix_equal_to(other_value) - - @type_operator(FIELD_DATAFRAME) - def prefix_equal_to(self, other_value: dict) -> pd.Series: - """ - Checks if target prefix is equal to comparator. - """ - target: str = self.replace_prefix(other_value.get("target")) - value_is_literal: bool = other_value.get("value_is_literal", False) - comparator: Union[str, Any] = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - prefix: int = self.replace_prefix(other_value.get("prefix")) - return self._check_equality_of_string_part(target, comparison_data, "prefix", prefix) - - @type_operator(FIELD_DATAFRAME) - def prefix_not_equal_to(self, other_value: dict) -> pd.Series: - """ - Checks if target prefix is not equal to comparator. - """ - return ~self.prefix_equal_to(other_value) - - @type_operator(FIELD_DATAFRAME) - def prefix_is_contained_by(self, other_value: dict) -> pd.Series: - """ - Checks if target prefix is contained by the comparator. - """ - target: str = self.replace_prefix(other_value.get("target")) - value_is_literal: bool = other_value.get("value_is_literal", False) - comparator: Union[str, Any] = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - prefix_length: int = other_value.get("prefix") - series_to_validate: pd.Series = self._get_string_part_series("prefix", prefix_length, target) - return self._value_is_contained_by(series_to_validate, comparison_data) - - @type_operator(FIELD_DATAFRAME) - def prefix_is_not_contained_by(self, other_value: dict) -> pd.Series: - return ~self.prefix_is_contained_by(other_value) - - @type_operator(FIELD_DATAFRAME) - def suffix_is_contained_by(self, other_value: dict) -> pd.Series: - """ - Checks if target prefix is equal to comparator. - """ - target: str = self.replace_prefix(other_value.get("target")) - value_is_literal: bool = other_value.get("value_is_literal", False) - comparator: Union[str, Any] = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - suffix_length: int = other_value.get("suffix") - series_to_validate: pd.Series = self._get_string_part_series("suffix", suffix_length, target) - return self._value_is_contained_by(series_to_validate, comparison_data) - - @type_operator(FIELD_DATAFRAME) - def suffix_is_not_contained_by(self, other_value: dict) -> pd.Series: - return ~self.suffix_is_contained_by(other_value) - - def _get_string_part_series(self, part_to_validate: str, length: int, target: str): - if not self.value[target].apply(type).eq(str).all(): - raise ValueError("The operator can't be used with non-string values") - - if part_to_validate == "suffix": - series_to_validate: pd.Series = self.value[target].str.slice(-length) - elif part_to_validate == "prefix": - series_to_validate: pd.Series = self.value[target].str.slice(stop=length) - else: - raise ValueError(f"Invalid part to validate: {part_to_validate}. Valid values are: suffix, prefix") - - return series_to_validate - - def _value_is_contained_by(self, series: pd.Series, comparison_data) -> pd.Series: - if self.is_column_of_iterables(comparison_data): - results = vectorized_is_in(series, comparison_data) - else: - results = series.isin(comparison_data) - return pd.Series(results) - - def _check_equality_of_string_part( - self, - target: str, - comparison_data: Union[str, pd.Series], - part_to_validate: str, - length: int - ) -> pd.Series: - """ - Checks if the given string part is equal to comparison data. - """ - series_to_validate = self._get_string_part_series(part_to_validate, length, target) - return series_to_validate.eq(comparison_data) - - @type_operator(FIELD_DATAFRAME) - def less_than(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data = self.get_comparator_data(comparator, value_is_literal) - target_column = pd.to_numeric(self.value[target], errors="coerce") - if isinstance(comparison_data, pd.Series): - comparison_data = pd.to_numeric(comparison_data, errors="coerce") - results = np.where(target_column < comparison_data, True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def less_than_or_equal_to(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data = self.get_comparator_data(comparator, value_is_literal) - target_column = pd.to_numeric(self.value[target], errors="coerce") - if isinstance(comparison_data, pd.Series): - comparison_data = pd.to_numeric(comparison_data, errors="coerce") - results = np.where(target_column <= comparison_data, True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def greater_than_or_equal_to(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data = self.get_comparator_data(comparator, value_is_literal) - target_column = pd.to_numeric(self.value[target], errors="coerce") - if isinstance(comparison_data, pd.Series): - comparison_data = pd.to_numeric(comparison_data, errors="coerce") - results = np.where(target_column >= comparison_data, True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def greater_than(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data = self.get_comparator_data(comparator, value_is_literal) - target_column = pd.to_numeric(self.value[target], errors="coerce") - if isinstance(comparison_data, pd.Series): - comparison_data = pd.to_numeric(comparison_data, errors="coerce") - results = np.where(target_column > comparison_data, True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def contains(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data = self.get_comparator_data(comparator, value_is_literal) - if self.is_column_of_iterables(self.value[target]) or isinstance(comparison_data, str): - results = vectorized_is_in(comparison_data, self.value[target]) - elif isinstance(comparator, pandas.core.series.Series): - results = np.where(comparison_data.isin(self.value[target]), True, False) - else: - # Handles numeric case. This case should never occur - results = np.where(self.value[target] == comparison_data, True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def does_not_contain(self, other_value): - return ~self.contains(other_value) - - @type_operator(FIELD_DATAFRAME) - def contains_case_insensitive(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = self.replace_prefix(other_value.get("comparator")) if not value_is_literal else other_value.get("comparator") - comparison_data = self.get_comparator_data(comparator, value_is_literal) - comparison_data = self.convert_string_data_to_lower(comparison_data) - if self.is_column_of_iterables(self.value[target]): - results = vectorized_case_insensitive_is_in(comparison_data, self.value[target]) - elif isinstance(comparator, pandas.core.series.Series) or isinstance(comparison_data, pandas.core.series.Series): - results = np.where(comparison_data.isin(self.value[target].str.lower()), True, False) - else: - results = vectorized_is_in(comparison_data.lower(), self.value[target].str.lower()) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def does_not_contain_case_insensitive(self, other_value): - return ~self.contains_case_insensitive(other_value) - - @type_operator(FIELD_DATAFRAME) - def is_contained_by(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_is_literal = other_value.get("value_is_literal", False) - comparator = other_value.get("comparator") - if isinstance(comparator, str) and not value_is_literal: - # column name provided - comparator = self.replace_prefix(comparator) - comparison_data = self.get_comparator_data(comparator, value_is_literal) - if self.is_column_of_iterables(comparison_data): - results = vectorized_is_in(self.value[target], comparison_data) - else: - results = self.value[target].isin(comparison_data) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def is_not_contained_by(self, other_value): - return ~self.is_contained_by(other_value) - - @type_operator(FIELD_DATAFRAME) - def is_contained_by_case_insensitive(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator", []) - value_is_literal = other_value.get("value_is_literal", False) - if isinstance(comparator, list): - comparator = [val.lower() for val in comparator] - elif isinstance(comparator, str) and not value_is_literal: - # column name provided - comparator = self.replace_prefix(comparator) - comparison_data = self.get_comparator_data(comparator, value_is_literal) - if self.is_column_of_iterables(comparison_data): - results = vectorized_case_insensitive_is_in(self.value[target].str.lower(), comparison_data) - return pd.Series(results) - elif isinstance(comparison_data, pd.core.series.Series): - results = self.value[target].str.lower().isin(comparison_data.str.lower()) - else: - results = self.value[target].str.lower().isin(comparison_data) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def is_not_contained_by_case_insensitive(self, other_value): - return ~self.is_contained_by_case_insensitive(other_value) - - def _custom_str_conversion(self, x): - if pd.notna(x): - if isinstance(x, int): - return str(x).strip() - elif isinstance(x, float): - return f"{x:.0f}" if x.is_integer() else str(x).strip() - return x - - @type_operator(FIELD_DATAFRAME) - def prefix_matches_regex(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - prefix = other_value.get("prefix") - self.value[target] = self.value[target].apply(lambda x: self._custom_str_conversion(x)) - results = self.value[target].notna() & self.value[target].astype(str).map(lambda x: re.search(comparator, x[:prefix]) is not None) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def not_prefix_matches_regex(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - prefix = other_value.get("prefix") - self.value[target] = self.value[target].apply(lambda x: self._custom_str_conversion(x)) - results = self.value[target].notna() & ~self.value[target].astype(str).map(lambda x: re.search(comparator, x[:prefix]) is not None) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def suffix_matches_regex(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - suffix = other_value.get("suffix") - self.value[target] = self.value[target].apply(lambda x: self._custom_str_conversion(x)) - results = self.value[target].notna() & self.value[target].astype(str).apply(lambda x: re.search(comparator, x[-suffix:]) is not None) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def not_suffix_matches_regex(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - suffix = other_value.get("suffix") - self.value[target] = self.value[target].apply(lambda x: self._custom_str_conversion(x)) - results = self.value[target].notna() & ~self.value[target].astype(str).apply(lambda x: re.search(comparator, x[-suffix:]) is not None) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def matches_regex(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - self.value[target] = self.value[target].apply(lambda x: self._custom_str_conversion(x)) - results = self.value[target].notna() & self.value[target].astype(str).str.match(comparator) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def not_matches_regex(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - self.value[target] = self.value[target].apply(lambda x: self._custom_str_conversion(x)) - results = self.value[target].notna() & ~self.value[target].astype(str).str.match(comparator) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def equals_string_part(self, other_value): - """ - Checks that the values in the target column - equal the result of parsing the value in the comparison - column with a regex - """ - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - regex = other_value.get("regex") - value_is_literal: bool = other_value.get("value_is_literal", False) - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - if isinstance(comparison_data, str): - parsed_data = apply_regex(regex, comparison_data) - else: - parsed_data = pd.Series(vectorized_apply_regex(regex, comparison_data)) - print(parsed_data) - parsed_id = str(uuid4()) - self.value[parsed_id] = parsed_data - return self.value.apply(lambda row: self._check_equality(row, target, parsed_id, value_is_literal), axis=1) - - @type_operator(FIELD_DATAFRAME) - def does_not_equal_string_part(self, other_value): - return ~self.equals_string_part(other_value) - - - @type_operator(FIELD_DATAFRAME) - def starts_with(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - value_is_literal: bool = other_value.get("value_is_literal", False) - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - if isinstance(comparison_data, pd.Series): - # need to convert series to tuple to make startswith operator work correctly - comparison_data: Tuple[str] = tuple(comparison_data) - results = self.value[target].str.startswith(comparison_data) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def ends_with(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - value_is_literal: bool = other_value.get("value_is_literal", False) - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - if isinstance(comparison_data, pd.Series): - # need to convert series to tuple to make endswith operator work correctly - comparison_data: Tuple[str] = tuple(comparison_data) - results = self.value[target].str.endswith(comparison_data) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def has_equal_length(self, other_value: dict): - """ - Checks that the target length is the same as comparator. - If comparing two columns (value_is_literal is False), the operator - compares lengths of values in these columns. - """ - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - value_is_literal: bool = other_value.get("value_is_literal", False) - comparison_data: Union[int, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - if isinstance(comparison_data, pd.Series): - if is_integer_dtype(comparison_data): - results = self.value[target].str.len().eq(comparison_data) - else: - results = self.value[target].str.len().eq(comparison_data.str.len()) - else: - results = self.value[target].str.len().eq(comparator) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def has_not_equal_length(self, other_value: dict): - return ~self.has_equal_length(other_value) - - @type_operator(FIELD_DATAFRAME) - def longer_than(self, other_value: dict): - """ - Checks if the target is longer than the comparator. - If comparing two columns (value_is_literal is False), the operator - compares lengths of values in these columns. - """ - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - value_is_literal: bool = other_value.get("value_is_literal", False) - comparison_data: Union[int, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - if isinstance(comparison_data, pd.Series): - if is_integer_dtype(comparison_data): - results = self.value[target].str.len().gt(comparison_data) - else: - results = self.value[target].str.len().gt(comparison_data.str.len()) - else: - results = self.value[target].str.len().gt(comparison_data) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def longer_than_or_equal_to(self, other_value: dict): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - value_is_literal: bool = other_value.get("value_is_literal", False) - comparison_data: Union[int, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - if isinstance(comparison_data, pd.Series): - if is_integer_dtype(comparison_data): - results = self.value[target].str.len().ge(comparison_data) - else: - results = self.value[target].str.len().ge(comparison_data.str.len()) - else: - results = self.value[target].str.len().ge(comparator) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def shorter_than(self, other_value: dict): - return ~self.longer_than_or_equal_to(other_value) - - @type_operator(FIELD_DATAFRAME) - def shorter_than_or_equal_to(self, other_value: dict): - return ~self.longer_than(other_value) - - @type_operator(FIELD_DATAFRAME) - def empty(self, other_value: dict): - target = self.replace_prefix(other_value.get("target")) - results = np.where(self.value[target].isin(["", None]), True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def empty_within_except_last_row(self, other_value: dict): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - # group all targets by comparator - grouped_target = self.value.groupby(comparator)[target] - # validate all targets except the last one - results = grouped_target.apply(lambda x: x[:-1]).apply(lambda x: x in ["", None]) - # extract values with corresponding indexes from results - self.value[f"result_{uuid4()}"] = results.reset_index(level=0, drop=True) - return True in results.values - - @type_operator(FIELD_DATAFRAME) - def non_empty(self, other_value: dict): - return ~self.empty(other_value) - - @type_operator(FIELD_DATAFRAME) - def non_empty_within_except_last_row(self, other_value: dict): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - # group all targets by comparator - grouped_target = self.value.groupby(comparator)[target] - # validate all targets except the last one - results = ~grouped_target.apply(lambda x: x[:-1]).apply(lambda x: x in ["", None]) - # extract values with corresponding indexes from results - self.value[f"result_{uuid4()}"] = results.reset_index(level=0, drop=True) - return not(False in results.values) - - @type_operator(FIELD_DATAFRAME) - def contains_all(self, other_value: dict): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - if isinstance(comparator, list): - # get column as array of values - values = flatten_list(self.value, comparator) - else: - comparator = self.replace_prefix(comparator) - values = self.value[comparator].unique() - return set(values).issubset(set(self.value[target].unique())) - - @type_operator(FIELD_DATAFRAME) - def not_contains_all(self, other_value: dict): - return not self.contains_all(other_value) - - @type_operator(FIELD_DATAFRAME) - def invalid_date(self, other_value): - target = self.replace_prefix(other_value.get("target")) - results = ~vectorized_is_valid(self.value[target]) - return pd.Series(results) - - def date_comparison(self, other_value, operator): - target = self.replace_prefix(other_value.get("target")) - comparator = self.replace_prefix(other_value.get("comparator")) - value_is_literal: bool = other_value.get("value_is_literal", False) - comparison_data: Union[str, pd.Series] = self.get_comparator_data(comparator, value_is_literal) - component = other_value.get("date_component") - results = np.where(vectorized_compare_dates(component, self.value[target], comparison_data, operator), True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def date_equal_to(self, other_value): - return self.date_comparison(other_value, operator.eq) - - @type_operator(FIELD_DATAFRAME) - def date_not_equal_to(self, other_value): - return self.date_comparison(other_value, operator.ne) - - @type_operator(FIELD_DATAFRAME) - def date_less_than(self, other_value): - return self.date_comparison(other_value, operator.lt) - - @type_operator(FIELD_DATAFRAME) - def date_less_than_or_equal_to(self, other_value): - return self.date_comparison(other_value, operator.le) - - @type_operator(FIELD_DATAFRAME) - def date_greater_than_or_equal_to(self, other_value): - return self.date_comparison(other_value, operator.ge) - - @type_operator(FIELD_DATAFRAME) - def date_greater_than(self, other_value): - return self.date_comparison(other_value, operator.gt) - - @type_operator(FIELD_DATAFRAME) - def is_incomplete_date(self, other_value): - return ~self.is_complete_date(other_value) - - @type_operator(FIELD_DATAFRAME) - def is_complete_date(self, other_value): - target = self.replace_prefix(other_value.get("target")) - results = vectorized_is_complete_date(self.value[target]) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def is_unique_set(self, other_value): - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - values = [target, comparator] - target_data = flatten_list(self.value, values) - target_names = [] - for target_name in target_data: - target_name = self.replace_prefix(target_name) - if target_name in self.value.columns: - target_names.append(target_name) - target_names = list(set(target_names)) - counts = self.value[target_names].groupby(target_names)[target].transform('size') - results = np.where(counts <= 1, True, False) - return pd.Series(results) - - @type_operator(FIELD_DATAFRAME) - def is_not_unique_relationship(self, other_value) -> pd.Series: - """ - Validates one-to-one relationship between two columns (target and comparator) against a dataset. - One-to-one means that a pair of columns can be duplicated but its integrity must not be violated: - one value of target always corresponds to one value of comparator. Examples: - - Valid dataset: - STUDYID STUDYDESC - 1 A - 2 B - 3 C - 1 A - 2 B - - Invalid dataset: - STUDYID STUDYDESC - 1 A - 2 A - 3 C - """ - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") - if isinstance(comparator, list): - comparator = self.replace_all_prefixes(comparator) - else: - comparator = self.replace_prefix(comparator) - # remove repeating rows - df_without_duplicates: pd.DataFrame = self.value[[target, comparator]].drop_duplicates() - # we need to check if ANY of the columns (target or comparator) is duplicated - duplicated_comparator: pd.Series = df_without_duplicates[comparator].duplicated(keep=False) - duplicated_target: pd.Series = df_without_duplicates[target].duplicated(keep=False) - result = pd.Series([False] * len(self.value)) - if duplicated_comparator.any(): - duplicated_comparator_values = set(df_without_duplicates[duplicated_comparator][comparator]) - result += self.value[comparator].isin(duplicated_comparator_values) - if duplicated_target.any(): - duplicated_target_values = set(df_without_duplicates[duplicated_target][target]) - result += self.value[target].isin(duplicated_target_values) - return result - - @type_operator(FIELD_DATAFRAME) - def is_unique_relationship(self, other_value) -> pd.Series: - return ~self.is_not_unique_relationship(other_value) - - @type_operator(FIELD_DATAFRAME) - def is_not_unique_set(self, other_value): - return ~self.is_unique_set(other_value) - - @type_operator(FIELD_DATAFRAME) - def is_ordered_set(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value = other_value.get("comparator") - if not isinstance(value, str): - raise Exception('Comparator must be a single String value') - - return not (False in self.value.groupby(value).agg(lambda x : list(x))[target].map(lambda x: sorted(x) == x).tolist()) - - @type_operator(FIELD_DATAFRAME) - def is_not_ordered_set(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value = other_value.get("comparator") - if not isinstance(value, str): - raise Exception('Comparator must be a single String value') - - return False in self.value.groupby(value).agg(lambda x : list(x))[target].map(lambda x: sorted(x) == x).tolist() - - @type_operator(FIELD_DATAFRAME) - def is_valid_reference(self, other_value): - target = self.replace_prefix(other_value.get("target")) - context = self.replace_prefix(other_value.get("context")) - if context: - results = self.value.apply(lambda row: row[target] in self.relationship_data.get(row[context], {}), axis=1) - else: - results = self.value[target].isin(self.relationship_data) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def is_not_valid_reference(self, other_value): - return ~self.is_valid_reference(other_value) - - @type_operator(FIELD_DATAFRAME) - def is_valid_relationship(self, other_value): - target = self.replace_prefix(other_value.get("target")) - value_column = self.replace_prefix(other_value.get("comparator")) - context = self.replace_prefix(other_value.get("context")) - results = self.value.apply(lambda row: self.detect_reference(row, value_column, target, context), axis=1) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def is_not_valid_relationship(self, other_value): - return ~self.is_valid_relationship(other_value) - - @type_operator(FIELD_DATAFRAME) - def non_conformant_value_data_type(self, other_value): - results = False - for vlm in self.value_level_metadata: - results |= self.value.apply(lambda row: vlm["filter"](row) and not vlm["type_check"](row), axis=1) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def non_conformant_value_length(self, other_value): - results = False - for vlm in self.value_level_metadata: - results |= self.value.apply(lambda row: vlm["filter"](row) and not vlm["length_check"](row), axis=1) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def conformant_value_data_type(self, other_value): - results = False - for vlm in self.value_level_metadata: - results |= self.value.apply(lambda row: vlm["filter"](row) and vlm["type_check"](row), axis=1) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def conformant_value_length(self, other_value): - results = False - for vlm in self.value_level_metadata: - results |= self.value.apply(lambda row: vlm["filter"](row) and vlm["length_check"](row), axis=1) - return pd.Series(results.values) - - @type_operator(FIELD_DATAFRAME) - def has_next_corresponding_record(self, other_value: dict): - """ - The operator ensures that value of target in current row - is the same as value of comparator in the next row. - In order to achieve this, we just remove last row from target - and first row from comparator and compare the resulting contents. - The result is reported for target. - """ - target = self.replace_prefix(other_value.get("target")) - comparator = self.replace_prefix(other_value.get("comparator")) - group_by_column: str = self.replace_prefix(other_value.get("within")) - order_by_column: str = self.replace_prefix(other_value.get("ordering")) - ordered_df = self.value.sort_values(by=[order_by_column]) - grouped_df = ordered_df.groupby(group_by_column) - results = grouped_df.apply(lambda x: self.compare_target_with_comparator_next_row(x, target, comparator)) - return pd.Series(results.explode().tolist()) - - @type_operator(FIELD_DATAFRAME) - def does_not_have_next_corresponding_record(self, other_value: dict): - return ~self.has_next_corresponding_record(other_value) - - def compare_target_with_comparator_next_row(self, df: pd.DataFrame, target: str, comparator: str): - """ - Compares current row of a target with the next row of comparator. - We can't compare last row of target with the next row of comparator - because there is no row after the last one. - """ - target_without_last_row = df[target].drop(df[target].tail(1).index) - comparator_without_first_row = df[comparator].drop(df[comparator].head(1).index) - results = np.where(target_without_last_row.values == comparator_without_first_row.values, True, False) - return [*results, pandas.NA] # appending NA here to make the length of results list the same as length of df - - @type_operator(FIELD_DATAFRAME) - def present_on_multiple_rows_within(self, other_value: dict): - """ - The operator ensures that the target is present on multiple rows - within a group_by column. The dataframe is grouped by a certain column - and the check is applied to each group. - """ - target = self.replace_prefix(other_value.get("target")) - min_count: int = other_value.get("comparator") or 1 - group_by_column = self.replace_prefix(other_value.get("within")) - grouped = self.value.groupby(group_by_column) - results = grouped.apply(lambda x: self.validate_series_length(x, target, min_count)) - return pd.Series(results.sort_index(level=1).tolist()) - - def validate_series_length(self, data: pd.DataFrame, target: str, min_length: int): - value_counts = data[target].value_counts().to_dict() - return data[target].apply(lambda x: value_counts.get(x, 0) > min_length) - - @type_operator(FIELD_DATAFRAME) - def not_present_on_multiple_rows_within(self, other_value: dict): - return ~self.present_on_multiple_rows_within(other_value) - - def detect_reference(self, row, value_column, target_column, context=None): - if context: - target_data = self.relationship_data.get(row[context], {}).get(row[target_column], pd.Series([]).values) - else: - target_data = self.relationship_data.get(row[target_column], pd.Series([]).values) - value = row[value_column] - return (value in target_data) or (value in target_data.astype(int).astype(str)) or (value in target_data.astype(str)) - - @type_operator(FIELD_DATAFRAME) - def additional_columns_empty(self, other_value: dict): - """ - The dataframe column might have some additional columns. - If the next additional column exists, the previous one cannot be empty. - Example: - column - TSVAL - additional columns - TSVAL1, TSVAL2, ... - If TSVAL2 exists -> TSVAL1 cannot be empty. - Original column (TSVAL) can be empty. - - The operator extracts these additional columns from the DF - and ensures they are not empty. - """ - target: str = self.replace_prefix(other_value.get("target")) - regex: str = rf"^{target}\d+$" # starting from target, ending with integers and nothing is between them - df: pd.DataFrame = self.value.filter(regex=regex) - # applying a function to each row - result: pd.Series = df.apply(lambda row: self.next_column_exists_and_previous_is_null(row), axis=1) - return result - - @type_operator(FIELD_DATAFRAME) - def additional_columns_not_empty(self, other_value: dict): - return ~self.additional_columns_empty(other_value) - - @type_operator(FIELD_DATAFRAME) - def references_correct_codelist(self, other_value: dict): - target: str = self.replace_prefix(other_value.get("target")) - comparator = self.replace_prefix(other_value.get("comparator")) - result: pd.Series = self.value.apply(lambda row: self.valid_codelist_reference(row[target], row[comparator]), axis=1) - return result - - @type_operator(FIELD_DATAFRAME) - def does_not_reference_correct_codelist(self, other_value: dict): - return ~self.references_correct_codelist(other_value) - - @type_operator(FIELD_DATAFRAME) - def uses_valid_codelist_terms(self, other_value: dict): - target: str = self.replace_prefix(other_value.get("target")) - comparator = self.replace_prefix(other_value.get("comparator")) - result: pd.Series = self.value.apply(lambda row: self.valid_terms(row[target], row[comparator]), axis=1) - return result - - @type_operator(FIELD_DATAFRAME) - def does_not_use_valid_codelist_terms(self, other_value: dict): - return ~self.uses_valid_codelist_terms(other_value) - - def next_column_exists_and_previous_is_null(self, row: pd.Series) -> bool: - row.reset_index(drop=True, inplace=True) - for index in row[row.isin([[], {}, "", None])].index: # leaving null values only - next_position: int = index + 1 - if next_position < len(row) and row[next_position] is not None: - return True - return False - - def valid_codelist_reference(self, column_name, codelist): - if column_name in self.column_codelist_map: - return codelist in self.column_codelist_map[column_name] - elif self.column_prefix_map: - # Check for generic versions of variables (i.e --DECOD) - for key in self.column_prefix_map: - if column_name.startswith(self.column_prefix_map[key]): - generic_column_name = column_name.replace(self.column_prefix_map[key], key, 1) - if generic_column_name in self.column_codelist_map: - return codelist in self.column_codelist_map.get(generic_column_name) - return True - - def valid_terms(self, codelist, terms_list): - if not codelist: - return True - valid_term = False - for codelist_term_map in self.codelist_term_maps: - if codelist in codelist_term_map: - valid_term = valid_term or (codelist_term_map[codelist].get("extensible") or set(terms_list).issubset(codelist_term_map[codelist].get("allowed_terms", []))) - return valid_term - - @type_operator(FIELD_DATAFRAME) - def has_different_values(self, other_value: dict): - """ - The operator ensures that the target column has different values. - """ - target: str = self.replace_prefix(other_value.get("target")) - is_valid: bool = len(self.value[target].unique()) > 1 - return pandas.Series([is_valid] * len(self.value[target])) - - @type_operator(FIELD_DATAFRAME) - def has_same_values(self, other_value: dict): - return ~self.has_different_values(other_value) - - @type_operator(FIELD_DATAFRAME) - def is_ordered_by(self, other_value: dict) -> pd.Series: - """ - Checking validity based on target order. - """ - target: str = self.replace_prefix(other_value.get("target")) - sort_order: str =other_value.get("order","asc") - if sort_order not in ["asc","dsc"]: - raise ValueError ("invalid sorting order") - sort_order_bool: bool = sort_order == "asc" - return self.value[target].eq(self.value[target].sort_values(ascending=sort_order_bool, ignore_index=True)) - - @type_operator(FIELD_DATAFRAME) - def is_not_ordered_by(self, other_value: dict) -> pd.Series: - return ~self.is_ordered_by(other_value) - - @type_operator(FIELD_DATAFRAME) - def value_has_multiple_references(self, other_value: dict) -> pd.Series: - """ - Requires a target column and a reference count column whose values - are a dictionary containing the number of times that value appears. - """ - target: str = self.replace_prefix(other_value.get("target")) - reference_count_column: str = self.replace_prefix(other_value.get("comparator")) - result = np.where(vectorized_get_dict_key(self.value[reference_count_column], self.value[target]) > 1, True, False) - return pd.Series(result) - - @type_operator(FIELD_DATAFRAME) - def value_does_not_have_multiple_references(self, other_value: dict) -> pd.Series: - return ~self.value_has_multiple_references(other_value) - - @type_operator(FIELD_DATAFRAME) - def target_is_sorted_by(self, other_value: dict) -> pd.Series: - """ - Checking the sort order based on comparators - """ - target: str = self.replace_prefix(other_value.get("target")) - within: str = self.replace_prefix(other_value.get("within")) - columns = other_value["comparator"] - for col in columns: - comparator: str = self.replace_prefix(col["name"]) - ascending: str = col["sort_order"] != "DESC" - na_pos: str = col["null_position"] - - grouped_df: pd.Series = self.value.sort_values( - by=[within, comparator], - na_position=na_pos - ).groupby([within]).apply(lambda x: x) - temp_target: pd.Series = grouped_df.groupby(within).cumcount().apply(lambda x: x+1) - if not ascending: - grouped_df = grouped_df.reset_index(drop=True) - temp_target = temp_target[::-1].reset_index(drop=True) - return temp_target.eq(grouped_df[target]).sort_index(axis=0) - - @type_operator(FIELD_DATAFRAME) - def target_is_not_sorted_by(self, other_value: dict) -> pd.Series: - return ~self.target_is_sorted_by(other_value) - - @type_operator(FIELD_DATAFRAME) - def variable_metadata_equal_to(self, other_value: dict) -> pd.Series: - """ - Validates the metadata for variables, provided in the metadata column, is equal to - the comparator. - Ex. - target: STUDYID - comparator: "Exp" - metadata_column: {"STUDYID": "Req", "DOMAIN": "Req"} - result: False - """ - target = self.replace_prefix(other_value.get("target")) - comparator = other_value.get("comparator") # Assumes the comparator is a value not a column - metadata_column = self.replace_prefix(other_value.get("metadata")) - result = np.where(vectorized_get_dict_key(self.value[metadata_column], target) == comparator, True, False) - return pd.Series(result) - - @type_operator(FIELD_DATAFRAME) - def variable_metadata_not_equal_to(self, other_value: dict) -> pd.Series: - return ~self.variable_metadata_equal_to(other_value) - -@export_type -class GenericType(SelectMultipleType, SelectType, StringType, NumericType, BooleanType): - - """ - This is meant to be a generic operator type to support all operations on a given value. Use this when you don't know the type of the value that will be returned. - """ - EPSILON = Decimal('0.000001') - name = "generic" - - def _assert_valid_value_and_cast(self, value): - if isinstance(value, string_types): - # String type - return str(value) - - elif isinstance(value, float): - # In python 2.6, casting float to Decimal doesn't work - return float_to_decimal(value) - elif isinstance(value, integer_types): - return Decimal(value) - else: - return value - - def equal_to(self, other): - if isinstance(self.value, Decimal): - return self.num_equal_to(other) - else: - return self.str_equal_to(other) - - def not_equal_to(self, other): - if isinstance(self.value, Decimal): - return self.num_not_equal_to(other) - else: - return self.str_not_equal_to(other) - - def is_contained_by(self, other_value): - if not isinstance(self.value, list): - self.value = [self.value] - return super().is_contained_by(other_value) - - @type_operator(FIELD_NUMERIC) - def num_equal_to(self, other_numeric): - return abs(self.value - other_numeric) <= self.EPSILON - - @type_operator(FIELD_TEXT) - def str_equal_to(self, other_string): - return self.value == other_string - - @type_operator(FIELD_NUMERIC) - def num_not_equal_to(self, other_numeric): - return abs(self.value - other_numeric) > self.EPSILON - - @type_operator(FIELD_TEXT) - def str_not_equal_to(self, other_string): - return self.value != other_string - - @type_operator(FIELD_TEXT) - def contains(self, other_string): - return other_string in self.value + return wrapper \ No newline at end of file diff --git a/business_rules/six.py b/business_rules/six.py index 8e1fd31..3842122 100644 --- a/business_rules/six.py +++ b/business_rules/six.py @@ -25,7 +25,7 @@ import types __author__ = "Benjamin Peterson " -__version__ = "1.4.7" +__version__ = "1.4.8" # Useful for very coarse version differentiation. diff --git a/business_rules/utils.py b/business_rules/utils.py index f9d44e7..f5f6cb5 100644 --- a/business_rules/utils.py +++ b/business_rules/utils.py @@ -1,5 +1,4 @@ import inspect -from dateutil.parser import parse, isoparse def fn_name_to_pretty_label(name): return ' '.join([w.title() for w in name.split('_')]) diff --git a/business_rules/variables.py b/business_rules/variables.py index 2e10e10..c6de3e5 100644 --- a/business_rules/variables.py +++ b/business_rules/variables.py @@ -1,14 +1,6 @@ import inspect -from functools import wraps from .utils import fn_name_to_pretty_label -from .operators import (BaseType, - NumericType, - StringType, - BooleanType, - SelectType, - SelectMultipleType, - GenericType, - DataframeType) +from .operators import BaseType class BaseVariables(object): """ Classes that hold a collection of variables to use with the rules @@ -40,28 +32,6 @@ def wrapper(func): return func return wrapper - -def _rule_variable_wrapper(field_type, label): - if callable(label): - # Decorator is being called with no args, label is actually the decorated func - return rule_variable(field_type)(label) - return rule_variable(field_type, label=label) - -def numeric_rule_variable(label=None): - return _rule_variable_wrapper(NumericType, label) - -def string_rule_variable(label=None): - return _rule_variable_wrapper(StringType, label) - -def boolean_rule_variable(label=None): - return _rule_variable_wrapper(BooleanType, label) - -def select_rule_variable(label=None, options=None): - return rule_variable(SelectType, label=label, options=options) - -def select_multiple_rule_variable(label=None, options=None): - return rule_variable(SelectMultipleType, label=label, options=options) - def generic_rule_variable(label=None, options=None): return rule_variable(GenericType, label=label, options=options) diff --git a/tests/test_dataframe_type/__init__.py b/tests/test_dataframe_type/__init__.py deleted file mode 100644 index 4813bbc..0000000 --- a/tests/test_dataframe_type/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -try: - from unittest2 import TestCase -except ImportError: - from unittest import TestCase - -assert TestCase \ No newline at end of file diff --git a/tests/test_dataframe_type/test_contains.py b/tests/test_dataframe_type/test_contains.py deleted file mode 100644 index 8661cce..0000000 --- a/tests/test_dataframe_type/test_contains.py +++ /dev/null @@ -1,208 +0,0 @@ -import pandas -from . import TestCase -from business_rules.operators import DataframeType - -class ContainsTests(TestCase): - def test_contains(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "string_var": ["h/j", "word", "c"], - "var5": [[1,3,5],[1,3,5], [1,3,5]] - }) - self.assertTrue(DataframeType({"value": df}).contains({ - "target": "var1", - "comparator": 2 - }).equals(pandas.Series([False, True, False]))) - self.assertTrue(DataframeType({"value": df}).contains({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).contains({ - "target": "var1", - "comparator": "--r3" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains({ - "target": "string_var", - "comparator": "string_var" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).contains({ - "target": "string_var", - "comparator": "string_var", - "value_is_literal": True - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains({ - "target": "var5", - "comparator": "var1" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains({ - "target": "string_var", - "comparator": "/", - "value_is_literal": True - }).equals(pandas.Series([True, False, False]))) - - def test_does_not_contain(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "string_var": ["hj", "word", "c"], - "var5": [[1,3,5],[1,3,5], [1,3,5]] - }) - self.assertTrue(DataframeType({"value": df}).does_not_contain({ - "target": "var1", - "comparator": 5 - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).does_not_contain({ - "target": "var1", - "comparator": "--r3" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain({ - "target": "string_var", - "comparator": "string_var", - "value_is_literal": True - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain({ - "target": "string_var", - "comparator": "string_var" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain({ - "target": "var5", - "comparator": "var1" - }).equals(pandas.Series([False, True, True]))) - - - def test_contains_case_insensitive(self): - df = pandas.DataFrame.from_dict({ - "var1": ["pikachu", "charmander", "squirtle"], - "var2": ["PIKACHU", "CHARIZARD", "BULBASAUR"], - "var3": ["POKEMON", "CHARIZARD", "BULBASAUR"], - "var4": [ - ["pikachu", "charizard", "bulbasaur"], - ["chikorita", "cyndaquil", "totodile"], - ["chikorita", "cyndaquil", "totodile"] - ] - }) - self.assertTrue(DataframeType({"value": df}).contains_case_insensitive({ - "target": "var1", - "comparator": "PIKACHU" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains_case_insensitive({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).contains_case_insensitive({ - "target": "--r1", - "comparator": "--r2" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains_case_insensitive({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains_case_insensitive({ - "target": "var3", - "comparator": "var3" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).contains_case_insensitive({ - "target": "var3", - "comparator": "var3", - "value_is_literal": True - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).contains_case_insensitive({ - "target": "var4", - "comparator": "var2" - }).equals(pandas.Series([True, False, False]))) - - def test_does_not_contain_case_insensitive(self): - df = pandas.DataFrame.from_dict({ - "var1": ["pikachu", "charmander", "squirtle"], - "var2": ["PIKACHU", "CHARIZARD", "BULBASAUR"], - "var3": ["pikachu", "charizard", "bulbasaur"], - "var4": [ - ["pikachu", "charizard", "bulbasaur"], - ["chikorita", "cyndaquil", "totodile"], - ["chikorita", "cyndaquil", "totodile"] - ] - }) - self.assertTrue(DataframeType({"value": df}).does_not_contain_case_insensitive({ - "target": "var1", - "comparator": "IVYSAUR" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain_case_insensitive({ - "target": "var3", - "comparator": "var2" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain_case_insensitive({ - "target": "var3", - "comparator": "var3", - "value_is_literal": True - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain_case_insensitive({ - "target": "var3", - "comparator": "var3" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).does_not_contain_case_insensitive({ - "target": "var4", - "comparator": "var2" - }).equals(pandas.Series([False, True, True]))) - - def test_contains_all(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['test', 'value', 'word'], - "var2": ["test", "value", "test"], - "variable_names": ["STUDYID", "USUBJID", "COOLVAR"], - "required_variables": [["STUDYID", "USUBJID"], ["STUDYID", "USUBJID"], ["STUDYID", "USUBJID"]] - } - ) - self.assertTrue(DataframeType({"value": df}).contains_all({ - "target": "var1", - "comparator": "var2", - })) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).contains_all({ - "target": "--r1", - "comparator": "--r2", - })) - self.assertFalse(DataframeType({"value": df}).contains_all({ - "target": "var2", - "comparator": "var1", - })) - self.assertTrue(DataframeType({"value": df}).contains_all({ - "target": "var2", - "comparator": ["test", "value"], - })) - - self.assertTrue(DataframeType({"value": df}).contains_all({ - "target": "variable_names", - "comparator": ["required_variables"] - })) - - def test_not_contains_all(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['test', 'value', 'word'], - "var2": ["test", "value", "test"], - "variable_names": ["STUDYID", "USUBJID", "COOLVAR"], - "required_variables": [["STUDYID", "USUBJID", "TEST"], ["STUDYID", "USUBJID", "TEST"], ["STUDYID", "USUBJID", "TEST"]] - } - ) - - self.assertTrue(DataframeType({"value": df}).not_contains_all({ - "target": "variable_names", - "comparator": ["required_variables"] - })) diff --git a/tests/test_dataframe_type/test_is_unique_set.py b/tests/test_dataframe_type/test_is_unique_set.py deleted file mode 100644 index c1e9483..0000000 --- a/tests/test_dataframe_type/test_is_unique_set.py +++ /dev/null @@ -1,136 +0,0 @@ -from business_rules.operators import DataframeType -import pandas -from . import TestCase - - -class IsUniqueSetTests(TestCase): - def test_is_unique_set(self): - df = pandas.DataFrame.from_dict( - { - "ARM": ["PLACEBO", "PLACEBO", "A", "A"], - "TAE": [1, 1, 1, 2], - "LAE": [1, 2, 1, 2], - "ARF": [1, 2, 3, 4], - } - ) - df_type = DataframeType({"value": df}) - self.assertTrue( - df_type.is_unique_set({"target": "ARM", "comparator": "LAE"}).equals( - pandas.Series([True, True, True, True]) - ) - ) - self.assertTrue( - df_type.is_unique_set({"target": "ARM", "comparator": ["ARF"]}).equals( - pandas.Series([True, True, True, True]) - ) - ) - self.assertTrue( - df_type.is_unique_set({"target": "ARM", "comparator": ["TAE"]}).equals( - pandas.Series([False, False, True, True]) - ) - ) - self.assertTrue( - df_type.is_unique_set( - {"target": "ARM", "comparator": ["TAE", "NOT_IN_DS"]} - ).equals(pandas.Series([False, False, True, True])) - ) - self.assertTrue( - df_type.is_unique_set( - {"target": "ARM", "comparator": ["TAE", ["NOT_IN_DS"]]} - ).equals(pandas.Series([False, False, True, True])) - ) - self.assertTrue( - df_type.is_unique_set( - {"target": "ARM", "comparator": ["TAE", ["LAE"]]} - ).equals(pandas.Series([True, True, True, True])) - ) - self.assertTrue( - df_type.is_unique_set( - {"target": "ARM", "comparator": [["LAE", "TAE"]]} - ).equals(pandas.Series([True, True, True, True])) - ) - self.assertTrue( - df_type.is_unique_set({"target": "ARM", "comparator": "TAE"}).equals( - pandas.Series([False, False, True, True]) - ) - ) - - df_type = DataframeType({"value": df, "column_prefix_map": {"--": "AR"}}) - self.assertTrue( - df_type.is_unique_set({"target": "--M", "comparator": "--F"}).equals( - pandas.Series([True, True, True, True]) - ) - ) - self.assertTrue( - df_type.is_unique_set({"target": "--M", "comparator": ["--F"]}).equals( - pandas.Series([True, True, True, True]) - ) - ) - - def test_is_not_unique_set(self): - df = pandas.DataFrame.from_dict( - { - "ARM": ["PLACEBO", "PLACEBO", "A", "A"], - "TAE": [1, 1, 1, 2], - "LAE": [1, 2, 1, 2], - "ARF": [1, 2, 3, 4], - } - ) - df_type = DataframeType({"value": df}) - self.assertTrue( - df_type.is_not_unique_set({"target": "ARM", "comparator": "LAE"}).equals( - pandas.Series([False, False, False, False]) - ) - ) - self.assertTrue( - df_type.is_not_unique_set({"target": "ARM", "comparator": ["ARF"]}).equals( - pandas.Series([False, False, False, False]) - ) - ) - self.assertTrue( - df_type.is_not_unique_set({"target": "ARM", "comparator": ["TAE"]}).equals( - pandas.Series([True, True, False, False]) - ) - ) - self.assertTrue( - df_type.is_not_unique_set( - {"target": "ARM", "comparator": ["TAE", "NOT_IN_DS"]} - ).equals(pandas.Series([True, True, False, False])) - ) - self.assertTrue( - df_type.is_not_unique_set( - {"target": "ARM", "comparator": ["TAE", ["NOT_IN_DS"]]} - ).equals(pandas.Series([True, True, False, False])) - ) - self.assertTrue( - df_type.is_not_unique_set( - {"target": "ARM", "comparator": ["TAE", ["NOT_IN_DS", "LAE"]]} - ).equals(pandas.Series([False, False, False, False])) - ) - self.assertTrue( - df_type.is_not_unique_set( - {"target": "ARM", "comparator": ["TAE", ["LAE"]]} - ).equals(pandas.Series([False, False, False, False])) - ) - self.assertTrue( - df_type.is_not_unique_set( - {"target": "ARM", "comparator": [["TAE", "LAE"]]} - ).equals(pandas.Series([False, False, False, False])) - ) - self.assertTrue( - df_type.is_not_unique_set({"target": "ARM", "comparator": "TAE"}).equals( - pandas.Series([True, True, False, False]) - ) - ) - - df_type = DataframeType({"value": df, "column_prefix_map": {"--": "AR"}}) - self.assertTrue( - df_type.is_not_unique_set({"target": "--M", "comparator": "--F"}).equals( - pandas.Series([False, False, False, False]) - ) - ) - self.assertTrue( - df_type.is_not_unique_set({"target": "--M", "comparator": ["--F"]}).equals( - pandas.Series([False, False, False, False]) - ) - ) diff --git a/tests/test_dataframe_type/test_length_checks.py b/tests/test_dataframe_type/test_length_checks.py deleted file mode 100644 index 9da72f6..0000000 --- a/tests/test_dataframe_type/test_length_checks.py +++ /dev/null @@ -1,94 +0,0 @@ -from . import TestCase -import pandas as pd -from business_rules.operators import DataframeType - -class LengthCheckTests(TestCase): - def test_has_equal_length(self): - df = pd.DataFrame.from_dict( - { - "var_1": ['test', 'value'], - "col": ["alex", "val"], - "int_col": [4, 5], - } - ) - df_operator = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}) - result = df_operator.has_equal_length({"target": "--r_1", "comparator": 4}) - self.assertTrue(result.equals(pd.Series([True, False]))) - - result = df_operator.has_equal_length({"target": "var_1", "comparator": "col"}) - self.assertTrue(result.equals(pd.Series([True, False]))) - - result = df_operator.has_equal_length({"target": "var_1", "comparator": "int_col"}) - self.assertTrue(result.equals(pd.Series([True, True]))) - - def test_has_not_equal_length(self): - df = pd.DataFrame.from_dict( - { - "var_1": ['test', 'value'], - "col": ["alex", "val"], - "int_col": [4, 7] - } - ) - df_operator = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}) - result = df_operator.has_not_equal_length({"target": "--r_1", "comparator": 4}) - self.assertTrue(result.equals(pd.Series([False, True]))) - - result = df_operator.has_not_equal_length({"target": "var_1", "comparator": "col"}) - self.assertTrue(result.equals(pd.Series([False, True]))) - - result = df_operator.has_not_equal_length({"target": "var_1", "comparator": "int_col"}) - self.assertTrue(result.equals(pd.Series([False, True]))) - - def test_longer_than(self): - df = pd.DataFrame.from_dict( - { - "var_1": ['test', 'value'], - "col": ["a", "long text"], - "int_col": [18, 2] - } - ) - df_operator = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}) - self.assertTrue(df_operator.longer_than({"target": "--r_1", "comparator": 3}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.longer_than({"target": "--r_1", "comparator": "col"}).equals(pd.Series([True, False]))) - self.assertTrue(df_operator.longer_than({"target": "--r_1", "comparator": "int_col"}).equals(pd.Series([False, True]))) - - def test_longer_than_or_equal_to(self): - df = pd.DataFrame.from_dict( - { - "var_1": ['test', 'alex'], - "col": ["sh", "test"], - "int_col": [4, 17] - } - ) - df_operator = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}) - self.assertTrue(df_operator.longer_than_or_equal_to({"target": "--r_1", "comparator": 3}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.longer_than_or_equal_to({"target": "var_1", "comparator": 4}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.longer_than_or_equal_to({"target": "var_1", "comparator": "col"}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.longer_than_or_equal_to({"target": "--r_1", "comparator": "int_col"}).equals(pd.Series([True, False]))) - - def test_shorter_than(self): - df = pd.DataFrame.from_dict( - { - "var_1": ['test', 'val'], - "col": ["longg", "abc"], - "int_col": [25, 3], - } - ) - df_operator = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}) - self.assertTrue(df_operator.shorter_than({"target": "--r_1", "comparator": 5}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.shorter_than({"target": "--r_1", "comparator": "col"}).equals(pd.Series([True, False]))) - self.assertTrue(df_operator.shorter_than({"target": "--r_1", "comparator": "int_col"}).equals(pd.Series([True, False]))) - - def test_shorter_than_or_equal_to(self): - df = pd.DataFrame.from_dict( - { - "var_1": ['test', 'alex'], - "col": ["longg", "test"], - "int_col": [25, 2], - } - ) - df_operator = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}) - self.assertTrue(df_operator.shorter_than_or_equal_to({"target": "--r_1", "comparator": 5}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.shorter_than_or_equal_to({"target": "var_1", "comparator": 4}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.shorter_than_or_equal_to({"target": "var_1", "comparator": "col"}).equals(pd.Series([True, True]))) - self.assertTrue(df_operator.shorter_than_or_equal_to({"target": "var_1", "comparator": "int_col"}).equals(pd.Series([True, False]))) diff --git a/tests/test_dataframe_type/test_numeric_comparison.py b/tests/test_dataframe_type/test_numeric_comparison.py deleted file mode 100644 index 6bbd1a9..0000000 --- a/tests/test_dataframe_type/test_numeric_comparison.py +++ /dev/null @@ -1,197 +0,0 @@ -import pandas -from . import TestCase -from business_rules.operators import DataframeType - -class NumericComparisonTests(TestCase): - def test_less_than(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "var5": ["1", "3", "5"], - "var6": ["ad", "ab", "al"] - }) - self.assertTrue(DataframeType({"value": df}).less_than({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).less_than({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df}).less_than({ - "target": "var4", - "comparator": "var5" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df}).less_than({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).less_than({ - "target": "--r1", - "comparator": "var3" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df}).less_than({ - "target": "var2", - "comparator": 2 - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).less_than({ - "target": "var1", - "comparator": 3 - }).equals(pandas.Series([True, True, False]))) - - another_df = pandas.DataFrame.from_dict( - { - "LBDY": [4, None, None, None, None] - } - ) - self.assertTrue(DataframeType({"value": another_df}).less_than({ - "target": "LBDY", - "comparator": 5 - }).equals(pandas.Series([True, False, False, False, False, ]))) - - def test_less_than_or_equal_to(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "var5": ["1", "3", "5"], - "var6": ["ad", "ab", "al"] - }) - self.assertTrue(DataframeType({"value": df}).less_than_or_equal_to({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).less_than_or_equal_to({ - "target": "--r1", - "comparator": "var4" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).less_than_or_equal_to({ - "target": "var2", - "comparator": "var1" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).less_than_or_equal_to({ - "target": "var2", - "comparator": 2 - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).less_than_or_equal_to({ - "target": "var2", - "comparator": "var3" - }).equals(pandas.Series([False, False, True]))) - - another_df = pandas.DataFrame.from_dict( - { - "LBDY": [4, 5, None, None, None] - } - ) - self.assertTrue(DataframeType({"value": another_df}).less_than_or_equal_to({ - "target": "LBDY", - "comparator": 5 - }).equals(pandas.Series([True, True, False, False, False, ]))) - self.assertTrue(DataframeType({"value": df}).less_than_or_equal_to({ - "target": "var4", - "comparator": "var5" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).less_than_or_equal_to({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, False]))) - - def test_greater_than(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "var5": ["1", "3", "5"], - "var6": ["ad", "ab", "al"] - }) - self.assertTrue(DataframeType({"value": df}).greater_than({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).greater_than({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).greater_than({ - "target": "var1", - "comparator": "--r3" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).greater_than({ - "target": "var2", - "comparator": 2 - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).greater_than({ - "target": "var1", - "comparator": 5000 - }).equals(pandas.Series([False, False, False]))) - - another_df = pandas.DataFrame.from_dict( - { - "LBDY": [4, None, None, None, None] - } - ) - self.assertTrue(DataframeType({"value": another_df}).greater_than({ - "target": "LBDY", - "comparator": 3 - }).equals(pandas.Series([True, False, False, False, False, ]))) - self.assertTrue(DataframeType({"value": df}).greater_than({ - "target": "var5", - "comparator": "var4" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df}).greater_than({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, False]))) - - def test_greater_than_or_equal_to(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "var5": ["1", "3", "5"], - "var6": ["ad", "ab", "al"] - }) - self.assertTrue(DataframeType({"value": df}).greater_than_or_equal_to({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).greater_than_or_equal_to({ - "target": "var1", - "comparator": "--r4" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).greater_than_or_equal_to({ - "target": "var2", - "comparator": "var3" - }).equals(pandas.Series([True, True, False]))) - self.assertTrue(DataframeType({"value": df}).greater_than_or_equal_to({ - "target": "var2", - "comparator": 2 - }).equals(pandas.Series([True, True, True]))) - - another_df = pandas.DataFrame.from_dict( - { - "LBDY": [4, 3, None, None, None] - } - ) - self.assertTrue(DataframeType({"value": another_df}).greater_than_or_equal_to({ - "target": "LBDY", - "comparator": 3 - }).equals(pandas.Series([True, True, False, False, False, ]))) - - self.assertTrue(DataframeType({"value": df}).greater_than_or_equal_to({ - "target": "var5", - "comparator": "var4" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).greater_than_or_equal_to({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).greater_than_or_equal_to({ - "target": "var6", - "comparator": "var6" - }).equals(pandas.Series([False, False, False]))) diff --git a/tests/test_dataframe_type/test_prefix_contained_by_operators.py b/tests/test_dataframe_type/test_prefix_contained_by_operators.py deleted file mode 100644 index 2286a70..0000000 --- a/tests/test_dataframe_type/test_prefix_contained_by_operators.py +++ /dev/null @@ -1,93 +0,0 @@ -import pandas -from . import TestCase -from business_rules.operators import DataframeType - -class PrefixSuffixContainedByTests(TestCase): - def test_prefix_is_contained_by(self): - df = pandas.DataFrame.from_dict({ - "var1": ["AETEST", "AETESTCD", "LBTEST"], - "var2": ["AETEST", "AFTESTCD", "RRTEST"], - "study_domains": [ - ["DM","AE","LB","TV"], - ["DM","AE","LB","TV"], - ["DM","AE","LB","TV"], - ] - }) - self.assertTrue(DataframeType({"value": df}).prefix_is_contained_by({ - "target": "var1", - "comparator": "study_domains", - "prefix": 2 - }).equals(pandas.Series([True, True, True]))) - - self.assertTrue(DataframeType({"value": df}).prefix_is_contained_by({ - "target": "var2", - "comparator": "study_domains", - "prefix": 2 - }).equals(pandas.Series([True, False, False]))) - - def test_suffix_is_contained_by(self): - df = pandas.DataFrame.from_dict({ - "var1": ["AETEST", "AETESTCD", "LBTEGG"], - "var2": ["AETEST", "AFTESTCD", "RRTELE"], - "study_domains": [ - ["ST","CD","GG","TV"], - ["ST","CD","GG","TV"], - ["ST","CD","GG","TV"], - ] - }) - self.assertTrue(DataframeType({"value": df}).suffix_is_contained_by({ - "target": "var1", - "comparator": "study_domains", - "suffix": 2 - }).equals(pandas.Series([True, True, True]))) - - self.assertTrue(DataframeType({"value": df}).suffix_is_contained_by({ - "target": "var2", - "comparator": "study_domains", - "suffix": 2 - }).equals(pandas.Series([True, True, False]))) - - def test_suffix_is_not_contained_by(self): - df = pandas.DataFrame.from_dict({ - "var1": ["AETEST", "AETESTCD", "LBTEGG"], - "var2": ["AETEST", "AFTESTCD", "RRTELE"], - "study_domains": [ - ["ST","CD","GG","TV"], - ["ST","CD","GG","TV"], - ["ST","CD","GG","TV"], - ] - }) - self.assertTrue(DataframeType({"value": df}).suffix_is_not_contained_by({ - "target": "var1", - "comparator": "study_domains", - "suffix": 2 - }).equals(pandas.Series([False, False, False]))) - - self.assertTrue(DataframeType({"value": df}).suffix_is_not_contained_by({ - "target": "var2", - "comparator": "study_domains", - "suffix": 2 - }).equals(pandas.Series([False, False, True]))) - - def test_prefix_is_not_contained_by(self): - df = pandas.DataFrame.from_dict({ - "var1": ["AETEST", "AETESTCD", "LBTEST"], - "var2": ["AETEST", "AFTESTCD", "RRTEST"], - "study_domains": [ - ["DM","AE","LB","TV"], - ["DM","AE","LB","TV"], - ["DM","AE","LB","TV"], - ] - }) - self.assertTrue(DataframeType({"value": df}).prefix_is_not_contained_by({ - "target": "var1", - "comparator": "study_domains", - "prefix": 2 - }).equals(pandas.Series([False, False, False]))) - - self.assertTrue(DataframeType({"value": df}).prefix_is_not_contained_by({ - "target": "var2", - "comparator": "study_domains", - "prefix": 2 - }).equals(pandas.Series([False, True, True]))) - diff --git a/tests/test_dataframe_type/test_present_on_multiple_rows_within.py b/tests/test_dataframe_type/test_present_on_multiple_rows_within.py deleted file mode 100644 index 5ea2e8d..0000000 --- a/tests/test_dataframe_type/test_present_on_multiple_rows_within.py +++ /dev/null @@ -1,93 +0,0 @@ -import pandas -from . import TestCase -from business_rules.operators import DataframeType - -class PresentOnMultipleRowsWithin(TestCase): - def test_present_on_multiple_rows_within(self): - """ - Unit test for present_on_multiple_rows_within operator. - """ - valid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 2, 2, 2, ], - "SEQ": [1, 2, 3, 4, 5, 6], - "RELID": ["AEHOSP1", "AEHOSP1", "AEHOSP1", "AEHOSP2", "AEHOSP2", "AEHOSP2"] - } - ) - result = DataframeType({"value": valid_df}).present_on_multiple_rows_within( - {"target": "RELID", "within": "USUBJID", "comparator": 1} - ) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, True]))) - - valid_df_1 = pandas.DataFrame.from_dict( - { - "USUBJID": [5, 5, 5, 7, 7, 7, ], - "SEQ": [1, 2, 3, 4, 5, 6], - "RELID": ["AEHOSP1", "AEHOSP1", "AEHOSP1", "AEHOSP2", "AEHOSP2", "AEHOSP2"] - } - ) - result = DataframeType({"value": valid_df_1}).present_on_multiple_rows_within( - {"target": "RELID", "within": "USUBJID", "comparator": 2} - ) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, True]))) - - invalid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 2, 2, 2, 3], - "SEQ": [1, 2, 3, 4, 5, 6, 7], - "RELID": ["AEHOSP1", "AEHOSP1", "AEHOSP1", "AEHOSP2", "AEHOSP2", "AEHOSP2", "AEHOSP3"] - } - ) - result = DataframeType({"value": invalid_df}).present_on_multiple_rows_within( - {"target": "RELID", "within": "USUBJID", "comparator": 1} - ) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, True, False]))) - - def test_present_on_multiple_rows_within_mixed_group(self): - df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 2, 2, 2, 3, 3, 3], - "DSDECOD": ["ICO", "ICO", "COMPLETE", "RANDOM", "RANDOM", "COMPLETE", "A", "B", "C"] - } - ) - result = DataframeType({"value": df}).present_on_multiple_rows_within( - {"target": "DSDECOD", "within": "USUBJID"} - ) - self.assertTrue(result.equals(pandas.Series([True, True, False, True, True, False, False, False, False]))) - - # Comparator determines the max number of rows with the same value before an error is flagged. - # In this case, comparator: 5 means that if a value is present on more than 5 rows within the grouping target an error should be raised. Since no values appear more than 5 times within a USUBJID no error should be raised. - result = DataframeType({"value": df}).present_on_multiple_rows_within( - {"target": "DSDECOD", "within": "USUBJID", "comparator": 5} - ) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, False, False, False, False]))) - - def test_not_present_on_multiple_rows_within(self): - """ - Unit test for not_present_on_multiple_rows_within operator. - """ - valid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 2, 2, 2, ], - "SEQ": [1, 2, 3, 4, 5, 6], - "RELID": ["AEHOSP1", "AEHOSP1", "AEHOSP1", "AEHOSP2", "AEHOSP2", "AEHOSP2"] - } - ) - result = DataframeType({"value": valid_df}).not_present_on_multiple_rows_within( - {"target": "RELID", "within": "USUBJID", "comparator": 1} - ) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, False]))) - - invalid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 2, 2, 2, 3], - "SEQ": [1, 2, 3, 4, 5, 6, 7], - "RELID": ["AEHOSP1", "AEHOSP1", "AEHOSP1", "AEHOSP2", "AEHOSP2", "AEHOSP2", "AEHOSP3"] - } - ) - result = DataframeType({"value": invalid_df}).not_present_on_multiple_rows_within( - {"target": "RELID", "within": "USUBJID", "comparator": 1} - ) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, False, True]))) - - diff --git a/tests/test_dataframe_type/test_string_part_comparison.py b/tests/test_dataframe_type/test_string_part_comparison.py deleted file mode 100644 index 1df5b63..0000000 --- a/tests/test_dataframe_type/test_string_part_comparison.py +++ /dev/null @@ -1,36 +0,0 @@ -import pandas -from . import TestCase -from business_rules.operators import DataframeType - -class StringPartTests(TestCase): - def test_equals_string_part(self): - df = pandas.DataFrame.from_dict({ - "RDOMAIN": ["AE", "AE", "DX"], - "dataset_name": ["SUPPAEQUAL","SUPPAEQUAL","SUPPAEQUAL"], - }) - self.assertTrue(DataframeType({"value": df}).equals_string_part({ - "target": "RDOMAIN", - "comparator": "dataset_name", - "regex": ".{4}(..).*" # Get characters five and six of dataset name - }).equals(pandas.Series([True, True, False]))) - self.assertTrue(DataframeType({"value": df}).equals_string_part({ - "target": "RDOMAIN", - "comparator": "SUDXLL", - "regex": ".{2}(..).*" # Get characters five and six of dataset name - }).equals(pandas.Series([False, False, True]))) - - def test_does_not_equal_string_part(self): - df = pandas.DataFrame.from_dict({ - "RDOMAIN": ["AE", "AE", "DX"], - "dataset_name": ["SUPPAEQUAL","SUPPAEQUAL","SUPPAEQUAL"], - }) - self.assertTrue(DataframeType({"value": df}).does_not_equal_string_part({ - "target": "RDOMAIN", - "comparator": "dataset_name", - "regex": ".{4}(..).*" # Get characters five and six of dataset name - }).equals(pandas.Series([False, False, True]))) - self.assertTrue(DataframeType({"value": df}).does_not_equal_string_part({ - "target": "RDOMAIN", - "comparator": "SUDXLL", - "regex": ".{2}(..).*" # Get characters five and six of dataset name - }).equals(pandas.Series([True, True, False]))) diff --git a/tests/test_dataframe_type/test_valid_date.py b/tests/test_dataframe_type/test_valid_date.py deleted file mode 100644 index 874fb76..0000000 --- a/tests/test_dataframe_type/test_valid_date.py +++ /dev/null @@ -1,62 +0,0 @@ -import pandas -from . import TestCase -from business_rules.operators import DataframeType - -class ValidDateTests(TestCase): - def test_invalid_date(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['2021', '2021', '2021', '2021', '2099', "2022", "2023"], - "var2": ["2099", "2022", "2034", "90999", "20999", "2022", "2023"], - "var2.1": ["20220311", "2022", "20121123", "2022-03-11T09", "2099", "2022", "2023"], - "times_without_colons": ["2022-03-11T09-20-30", "2022-03-11T092030", "2022-03-11T09,20,30", "2022-03-11T09@20@30", "2022-03-11T09!20:30", "2022-03-11T09:20:30", "2022-03-11T09:20:30"], - "var3": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00", "2022-05-08T13:44:a", "2022-05-08T13:44:66"], - } - ) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).invalid_date({"target": "--r1"}) - .equals(pandas.Series([False, False, False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).invalid_date({"target": "var3"}) - .equals(pandas.Series([False, False, False, False, False, True, True]))) - self.assertTrue(DataframeType({"value": df}).invalid_date({"target": "var2"}) - .equals(pandas.Series([False, False, False, True, True, False, False]))) - - # Test date string can be parsed into a date - # Ex: 20121123 cannot be parsed into a date so it is invalid - self.assertTrue(DataframeType({"value": df}).invalid_date({"target": "var2.1"}) - .equals(pandas.Series([True, False, True, False, False, False, False]))) - - def test_invalid_date_times_without_colons(self): - df = pandas.DataFrame.from_dict( - { - "times_without_colons": ["2022-03-11T09-20-30", "2022-03-11T092030", "2022-03-11T09,20,30", "2022-03-11T09@20@30", "2022-03-11T09!20:30", "2022-03-11T09:20:30", "2022-03-11T09:20:30"], - } - ) - self.assertTrue(DataframeType({"value": df}).invalid_date({"target": "times_without_colons"}) - .equals(pandas.Series([True, True, True, True, True, False, False]))) - - def test_invalid_date_missing_components(self): - df = pandas.DataFrame.from_dict( - { - "missing_components": ["2003---15", "2003-12-15T-:15", "--12-15", "-----T07:15", "2003-07--T-:15"] - } - ) - self.assertTrue(DataframeType({"value": df}).invalid_date({"target": "missing_components"}) - .equals(pandas.Series([False, False, False, False, False]))) - - def test_invalid_date_intervals_of_uncertainty(self): - df = pandas.DataFrame.from_dict( - { - "intervals_of_uncertainty": ["2003-01-01/2003-02-15", "2003-12-14/2003-12-15T10:30"] - } - ) - self.assertTrue(DataframeType({"value": df}).invalid_date({"target": "intervals_of_uncertainty"}) - .equals(pandas.Series([False, False]))) - - def test_invalid_date_incorrect_month_day_values(self): - df = pandas.DataFrame.from_dict( - { - "var3": ["1997-23", "1997-07-44", "1997-00-16T19:20:30+01:00", "1997-07-32T19:20:30+01:00", "1997-02-30"], - } - ) - self.assertTrue(DataframeType({"value": df}).invalid_date({"target": "var3"}) - .equals(pandas.Series([True, True, True, True, True]))) diff --git a/tests/test_dataframe_type/test_value_has_multiple_references.py b/tests/test_dataframe_type/test_value_has_multiple_references.py deleted file mode 100644 index 19e5b9e..0000000 --- a/tests/test_dataframe_type/test_value_has_multiple_references.py +++ /dev/null @@ -1,32 +0,0 @@ -import pandas as pd -from . import TestCase -from business_rules.operators import DataframeType - -class ValueHasMultipleReferencesTests(TestCase): - def test_value_has_multiple_references(self): - df = pd.DataFrame.from_dict({ - "LNKGRP": ["A", "B", "A", "A", "A"], - "$VALUE_COUNTS": [ - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - ] - }) - result = DataframeType({"value": df}).value_has_multiple_references({"target": "LNKGRP", "comparator": "$VALUE_COUNTS"}) - self.assertTrue(result.equals(pd.Series([True, False, True, True, True]))) - - def test_value_does_not_have_multiple_references(self): - df = pd.DataFrame.from_dict({ - "LNKGRP": ["A", "B", "A", "A", "A"], - "$VALUE_COUNTS": [ - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - {"A": 2, "B": 1}, - ] - }) - result = DataframeType({"value": df}).value_does_not_have_multiple_references({"target": "LNKGRP", "comparator": "$VALUE_COUNTS"}) - self.assertTrue(result.equals(pd.Series([False, True, False, False, False]))) \ No newline at end of file diff --git a/tests/test_dataframe_type/test_variable_metadata_equality.py b/tests/test_dataframe_type/test_variable_metadata_equality.py deleted file mode 100644 index 36c150a..0000000 --- a/tests/test_dataframe_type/test_variable_metadata_equality.py +++ /dev/null @@ -1,34 +0,0 @@ -import pandas as pd -from . import TestCase -from business_rules.operators import DataframeType - -class VariableMetadataEqualityTests(TestCase): - def test_variable_metadata_equal_to(self): - df = pd.DataFrame.from_dict({ - "STUDYID": [1, 1, 1, 1], - "$CORE_VALUES": [ - {"STUDYID": "Req", "DOMAIN": "Req"}, - {"STUDYID": "Req", "DOMAIN": "Req"}, - {"STUDYID": "Req", "DOMAIN": "Req"}, - {"STUDYID": "Req", "DOMAIN": "Req"} - ] - }) - result = DataframeType({"value": df}).variable_metadata_equal_to({"target": "STUDYID", "comparator": "Exp", "metadata": "$CORE_VALUES"}) - self.assertTrue(result.equals(pd.Series([False, False, False, False]))) - result = DataframeType({"value": df}).variable_metadata_equal_to({"target": "STUDYID", "comparator": "Req", "metadata": "$CORE_VALUES"}) - self.assertTrue(result.equals(pd.Series([True, True, True, True]))) - - def test_variable_metadata_equal_to(self): - df = pd.DataFrame.from_dict({ - "STUDYID": [1, 1, 1, 1], - "$CORE_VALUES": [ - {"STUDYID": "Req", "DOMAIN": "Req"}, - {"STUDYID": "Req", "DOMAIN": "Req"}, - {"STUDYID": "Req", "DOMAIN": "Req"}, - {"STUDYID": "Req", "DOMAIN": "Req"} - ] - }) - result = DataframeType({"value": df}).variable_metadata_not_equal_to({"target": "STUDYID", "comparator": "Exp", "metadata": "$CORE_VALUES"}) - self.assertTrue(result.equals(pd.Series([True, True, True, True]))) - result = DataframeType({"value": df}).variable_metadata_not_equal_to({"target": "STUDYID", "comparator": "Req", "metadata": "$CORE_VALUES"}) - self.assertTrue(result.equals(pd.Series([False, False, False, False]))) \ No newline at end of file diff --git a/tests/test_variables.py b/tests/test_variables.py deleted file mode 100644 index 7a452ca..0000000 --- a/tests/test_variables.py +++ /dev/null @@ -1,147 +0,0 @@ -from . import TestCase -from business_rules.utils import fn_name_to_pretty_label -from business_rules.variables import (rule_variable, - numeric_rule_variable, - string_rule_variable, - boolean_rule_variable, - select_rule_variable, - select_multiple_rule_variable, - generic_rule_variable, - dataframe_rule_variable) - -from business_rules.operators import (DataframeType, NumericType, - StringType, - BooleanType, - SelectType, - SelectMultipleType, - GenericType) - -class RuleVariableTests(TestCase): - """ Tests for the base rule_variable decorator. - """ - - def test_pretty_label(self): - self.assertEqual( - fn_name_to_pretty_label('some_name_Of_a_thing'), - 'Some Name Of A Thing') - self.assertEqual(fn_name_to_pretty_label('hi'), 'Hi') - - def test_rule_variable_requires_instance_of_base_type(self): - err_string = "a_string is not instance of BaseType in rule_variable "\ - "field_type" - with self.assertRaisesRegexp(AssertionError, err_string): - @rule_variable('a_string') - def some_test_function(self): pass - - def test_rule_variable_decorator_internals(self): - """ Make sure that the expected attributes are attached to a function - by the variable decorators. - """ - def some_test_function(self): pass - wrapper = rule_variable(StringType, 'Foo Name', options=['op1', 'op2']) - func = wrapper(some_test_function) - self.assertTrue(func.is_rule_variable) - self.assertEqual(func.label, 'Foo Name') - self.assertEqual(func.field_type, StringType) - self.assertEqual(func.options, ['op1', 'op2']) - - def test_rule_variable_works_as_decorator(self): - @rule_variable(StringType, 'Blah') - def some_test_function(self): pass - self.assertTrue(some_test_function.is_rule_variable) - - def test_rule_variable_decorator_auto_fills_label(self): - @rule_variable(StringType) - def some_test_function(self): pass - self.assertTrue(some_test_function.label, 'Some Test Function') - - ### - ### rule_variable wrappers for each variable type - ### - - def test_numeric_rule_variable(self): - - @numeric_rule_variable('My Label') - def numeric_var(): pass - - self.assertTrue(getattr(numeric_var, 'is_rule_variable')) - self.assertEqual(getattr(numeric_var, 'field_type'), NumericType) - self.assertEqual(getattr(numeric_var, 'label'), 'My Label') - - def test_numeric_rule_variable_no_parens(self): - - @numeric_rule_variable - def numeric_var(): pass - - self.assertTrue(getattr(numeric_var, 'is_rule_variable')) - self.assertEqual(getattr(numeric_var, 'field_type'), NumericType) - - def test_string_rule_variable(self): - - @string_rule_variable(label='My Label') - def string_var(): pass - - self.assertTrue(getattr(string_var, 'is_rule_variable')) - self.assertEqual(getattr(string_var, 'field_type'), StringType) - self.assertEqual(getattr(string_var, 'label'), 'My Label') - - def test_string_rule_variable_no_parens(self): - - @string_rule_variable - def string_var(): pass - - self.assertTrue(getattr(string_var, 'is_rule_variable')) - self.assertEqual(getattr(string_var, 'field_type'), StringType) - - def test_boolean_rule_variable(self): - - @boolean_rule_variable(label='My Label') - def boolean_var(): pass - - self.assertTrue(getattr(boolean_var, 'is_rule_variable')) - self.assertEqual(getattr(boolean_var, 'field_type'), BooleanType) - self.assertEqual(getattr(boolean_var, 'label'), 'My Label') - - def test_boolean_rule_variable_no_parens(self): - - @boolean_rule_variable - def boolean_var(): pass - - self.assertTrue(getattr(boolean_var, 'is_rule_variable')) - self.assertEqual(getattr(boolean_var, 'field_type'), BooleanType) - - def test_select_rule_variable(self): - - options = {'foo':'bar'} - @select_rule_variable(options=options) - def select_var(): pass - - self.assertTrue(getattr(select_var, 'is_rule_variable')) - self.assertEqual(getattr(select_var, 'field_type'), SelectType) - self.assertEqual(getattr(select_var, 'options'), options) - - def test_select_multiple_rule_variable(self): - - options = {'foo':'bar'} - @select_multiple_rule_variable(options=options) - def select_multiple_var(): pass - - self.assertTrue(getattr(select_multiple_var, 'is_rule_variable')) - self.assertEqual(getattr(select_multiple_var, 'field_type'), SelectMultipleType) - self.assertEqual(getattr(select_multiple_var, 'options'), options) - - def test_generic_rule_variable(self): - - @generic_rule_variable() - def get_var(): pass - - self.assertTrue(getattr(get_var, 'is_rule_variable')) - self.assertEqual(getattr(get_var, 'field_type'), GenericType) - - def test_dataframe_rule_variable(self): - - @dataframe_rule_variable() - def get_var(): pass - - self.assertTrue(getattr(get_var, 'is_rule_variable')) - self.assertEqual(getattr(get_var, 'field_type'), DataframeType) diff --git a/tests/test_variables_class.py b/tests/test_variables_class.py index 1a4bf7d..139597f 100644 --- a/tests/test_variables_class.py +++ b/tests/test_variables_class.py @@ -1,33 +1,2 @@ -from business_rules.variables import BaseVariables, rule_variable -from business_rules.operators import StringType -from . import TestCase -class VariablesClassTests(TestCase): - """ Test methods on classes that inherit from BaseVariables - """ - def test_base_has_no_variables(self): - self.assertEqual(len(BaseVariables.get_all_variables()), 0) - - def test_get_all_variables(self): - """ Returns a dictionary listing all the functions on the class that - have been decorated as variables, with some of the data about them. - """ - class SomeVariables(BaseVariables): - - @rule_variable(StringType) - def this_is_rule_1(self): - return "blah" - - def non_rule(self): - return "baz" - - vars = SomeVariables.get_all_variables() - self.assertEqual(len(vars), 1) - self.assertEqual(vars[0]['name'], 'this_is_rule_1') - self.assertEqual(vars[0]['label'], 'This Is Rule 1') - self.assertEqual(vars[0]['field_type'], 'string') - self.assertEqual(vars[0]['options'], []) - - # should work on an instance of the class too - self.assertEqual(len(SomeVariables().get_all_variables()), 1) From 206da69c50e16f2c142db43fb9b8023418d466ab Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Tue, 15 Jul 2025 17:55:26 -0400 Subject: [PATCH 3/4] more test removal --- tests/test_engine_logic.py | 375 ----- tests/test_operators.py | 2427 --------------------------------- tests/test_variables_class.py | 2 - 3 files changed, 2804 deletions(-) delete mode 100644 tests/test_engine_logic.py delete mode 100644 tests/test_operators.py delete mode 100644 tests/test_variables_class.py diff --git a/tests/test_engine_logic.py b/tests/test_engine_logic.py deleted file mode 100644 index 70faacc..0000000 --- a/tests/test_engine_logic.py +++ /dev/null @@ -1,375 +0,0 @@ -import pandas as pd - -from business_rules import engine -from business_rules.variables import BaseVariables, dataframe_rule_variable -from business_rules.operators import StringType -from business_rules.actions import BaseActions - -from mock import patch, MagicMock -from . import TestCase - - -class EngineTests(TestCase): - - ### - ### Run - ### - - @patch.object(engine, 'run') - def test_run_all_some_rule_triggered(self, *args): - """ By default, does not stop on first triggered rule. Returns True if - any rule was triggered, otherwise False - """ - rule1 = {'conditions': 'condition1', 'actions': 'action name 1'} - rule2 = {'conditions': 'condition2', 'actions': 'action name 2'} - variables = BaseVariables() - actions = BaseActions() - - def return_action1(rule, *args, **kwargs): - return rule['actions'] == 'action name 1' - engine.run.side_effect = return_action1 - - result = engine.run_all([rule1, rule2], variables, actions) - self.assertTrue(result) - self.assertEqual(engine.run.call_count, 2) - - # switch order and try again - engine.run.reset_mock() - - result = engine.run_all([rule2, rule1], variables, actions) - self.assertTrue(result) - self.assertEqual(engine.run.call_count, 2) - - @patch.object(engine, 'run', return_value=True) - def test_run_all_stop_on_first(self, *args): - rule1 = {'conditions': 'condition1', 'actions': 'action name 1'} - rule2 = {'conditions': 'condition2', 'actions': 'action name 2'} - variables = BaseVariables() - actions = BaseActions() - - result = engine.run_all([rule1, rule2], variables, actions, - stop_on_first_trigger=True) - self.assertEqual(result, True) - self.assertEqual(engine.run.call_count, 1) - engine.run.assert_called_once_with(rule1, variables, actions) - - @patch.object(engine, 'check_conditions_recursively', return_value=True) - @patch.object(engine, 'do_actions') - def test_run_that_triggers_rule(self, *args): - rule = {'conditions': 'blah', 'actions': 'blah2'} - variables = BaseVariables() - actions = BaseActions() - - result = engine.run(rule, variables, actions) - self.assertEqual(result, True) - engine.check_conditions_recursively.assert_called_once_with( - rule['conditions'], variables) - engine.do_actions.assert_called_once_with(rule['actions'], actions, results=True) - - - @patch.object(engine, 'check_conditions_recursively', return_value=False) - @patch.object(engine, 'do_actions') - def test_run_that_doesnt_trigger_rule(self, *args): - rule = {'conditions': 'blah', 'actions': 'blah2'} - variables = BaseVariables() - actions = BaseActions() - - result = engine.run(rule, variables, actions) - self.assertEqual(result, False) - engine.check_conditions_recursively.assert_called_once_with( - rule['conditions'], variables) - self.assertEqual(engine.do_actions.call_count, 0) - - - @patch.object(engine, 'check_condition', return_value=True) - def test_check_all_conditions_with_all_true(self, *args): - conditions = {'all': [{'thing1': ''}, {'thing2': ''}]} - variables = BaseVariables() - - result = engine.check_conditions_recursively(conditions, variables) - self.assertEqual(result, True) - # assert call count and most recent call are as expected - self.assertEqual(engine.check_condition.call_count, 2) - engine.check_condition.assert_called_with({'thing2': ''}, variables) - - - ### - ### Check conditions - ### - @patch.object(engine, 'check_condition', return_value=False) - def test_check_all_conditions_with_all_false(self, *args): - conditions = {'all': [{'thing1': ''}, {'thing2': ''}]} - variables = BaseVariables() - - result = engine.check_conditions_recursively(conditions, variables) - self.assertEqual(result, False) - - def test_check_all_condition_with_no_items_fails(self): - with self.assertRaises(AssertionError): - engine.check_conditions_recursively({'all': []}, BaseVariables()) - - @patch.object(engine, 'check_condition', return_value=pd.Series([True, True, False])) - def test_check_all_conditions_series_results_single_condition(self, mock_check_condition): - conditions = {'all': [{'thing1': ''}, {'thing2': ''}]} - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([True, True, False]))) - - @patch.object(engine, 'check_condition') - def test_check_all_conditions_series_results_multiple_conditions(self, mock_check_condition): - condition_results = { - 1: pd.Series([True, False, True, True, ]), - 2: pd.Series([True, False, False, True, ]), - } - conditions = {'all': [{'id': 1}, {'id': 2}]} - mock_check_condition.side_effect = lambda condition, defined_variables: condition_results[condition["id"]] - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([True, False, False, True, ]))) - - @patch.object(engine, 'check_condition', return_value=pd.Series([True, True, False])) - def test_check_not_all_conditions_series_results_single_condition(self, mock_check_condition): - conditions = {'not': {'all': [{'thing1': ''}, {'thing2': ''}]}} - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([False, False, True]))) - - @patch.object(engine, 'check_condition', return_value=pd.Series([True, True, False])) - def test_check_not_all_conditions_series_results_single_condition_nested_not(self, mock_check_condition): - conditions = {'not': {'not': {'all': [{'thing1': ''}, {'thing2': ''}]}}} - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([True, True, False]))) - - @patch.object(engine, 'check_condition') - def test_check_not_all_conditions_series_results_multiple_conditions(self, mock_check_condition): - condition_results = { - 1: pd.Series([False, False, True, True]), - 2: pd.Series([False, False, True, False]), - } - conditions = {'not': {'all': [{'id': 1}, {'id': 2}]}} - mock_check_condition.side_effect = lambda condition, defined_variables: condition_results[condition["id"]] - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([True, True, False, True, ]))) - - @patch.object(engine, 'check_condition', return_value=True) - def test_check_any_conditions_with_all_true(self, *args): - conditions = {'any': [{'thing1': ''}, {'thing2': ''}]} - variables = BaseVariables() - - result = engine.check_conditions_recursively(conditions, variables) - self.assertEqual(result, True) - - @patch.object(engine, 'check_condition', return_value=False) - def test_check_any_conditions_with_all_false(self, *args): - conditions = {'any': [{'thing1': ''}, {'thing2': ''}]} - variables = BaseVariables() - - result = engine.check_conditions_recursively(conditions, variables) - self.assertEqual(result, False) - # assert call count and most recent call are as expected - self.assertEqual(engine.check_condition.call_count, 2) - engine.check_condition.assert_called_with({'thing2': ''}, variables) - - @patch.object(engine, 'check_condition', return_value=pd.Series([True, True, True, ])) - def test_check_any_condition_series_results_single_condition(self, mock_check_condition): - conditions = {'any': [{'thing1': ''}, {'thing2': ''}]} - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([True, True, True, ]))) - - @patch.object(engine, 'check_condition') - def test_check_any_condition_series_results_multiple_conditions(self, mock_check_condition): - condition_results = { - 1: pd.Series([False, False, True, False]), - 2: pd.Series([True, False, False, False]), - } - conditions = {'any': [{'id': 1}, {'id': 2}]} - mock_check_condition.side_effect = lambda condition, defined_variables: condition_results[condition["id"]] - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([True, False, True, False]))) - - @patch.object(engine, 'check_condition', return_value=pd.Series([True, True, True, False, ])) - def test_check_not_any_condition_series_results_single_condition(self, mock_check_condition): - conditions = {'not': {'any': [{'thing1': ''}, ]}} - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([False, False, False, True, ]))) - - @patch.object(engine, 'check_condition') - def test_check_not_any_condition_series_results_multiple_conditions(self, mock_check_condition): - condition_results = { - 1: pd.Series([False, False, True, False]), - 2: pd.Series([True, False, False, False]), - } - conditions = {'not': {'any': [{'id': 1}, {'id': 2}]}} - mock_check_condition.side_effect = lambda condition, defined_variables: condition_results[condition["id"]] - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result: pd.Series = engine.check_conditions_recursively(conditions, variables) - self.assertTrue(result.equals(pd.Series([False, True, False, True]))) - - def test_check_any_condition_with_no_items_fails(self): - with self.assertRaises(AssertionError): - engine.check_conditions_recursively({'any': []}, BaseVariables()) - - - def test_check_all_and_any_together(self): - conditions = {'any': [], 'all': []} - variables = BaseVariables() - with self.assertRaises(AssertionError): - engine.check_conditions_recursively(conditions, variables) - - @patch.object(engine, 'check_condition') - def test_nested_all_and_any(self, *args): - conditions = {'all': [ - {'any': [{'name': 1}, {'name': 2}]}, - {'name': 3}]} - bv = BaseVariables() - - def side_effect(condition, _): - return condition['name'] in [2,3] - engine.check_condition.side_effect = side_effect - - engine.check_conditions_recursively(conditions, bv) - self.assertEqual(engine.check_condition.call_count, 3) - engine.check_condition.assert_any_call({'name': 1}, bv) - engine.check_condition.assert_any_call({'name': 2}, bv) - engine.check_condition.assert_any_call({'name': 3}, bv) - - - ### - ### Operator comparisons - ### - def test_check_operator_comparison(self): - string_type = StringType('yo yo') - with patch.object(string_type, 'contains', return_value=True): - result = engine._do_operator_comparison( - string_type, 'contains', 'its mocked') - self.assertTrue(result) - string_type.contains.assert_called_once_with('its mocked') - - - ### - ### Actions - ### - def test_do_actions(self): - actions = [ {'name': 'action1'}, - {'name': 'action2', - 'params': {'param1': 'foo', 'param2': 10}}] - defined_actions = BaseActions() - defined_actions.action1 = MagicMock() - defined_actions.action2 = MagicMock() - - engine.do_actions(actions, defined_actions) - - defined_actions.action1.assert_called_once_with(results=None) - defined_actions.action2.assert_called_once_with(param1='foo', param2=10, results=None) - - def test_do_with_invalid_action(self): - actions = [{'name': 'fakeone'}] - err_string = "Action fakeone is not defined in class BaseActions" - with self.assertRaisesRegexp(AssertionError, err_string): - engine.do_actions(actions, BaseActions()) - - def test_any_condition_missing_columns(self): - conditions = {'any': [ - { - 'name': "get_dataset", - "operator": "starts_with", - "value": { - "target": "invalid", - "comparator": "HE" - } - }, - { - 'name': "get_dataset", - "operator": "less_than", - "value": { - "target": "TEST", - "comparator": 1 - } - } - ]} - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - result = engine.check_conditions_recursively(conditions, variables) - assert result[0] == False - - def test_any_condition_all_conditions_reference_missing_columns(self): - conditions = {'any': [ - { - 'name': "get_dataset", - "operator": "starts_with", - "value": { - "target": "invalid", - "comparator": "HE" - } - }, - { - 'name': "get_dataset", - "operator": "less_than", - "value": { - "target": "invalid", - "comparator": 1 - } - } - ]} - - class DatasetVariables(BaseVariables): - @dataframe_rule_variable() - def get_dataset(self): return {"value": {"TEST": 2}} - - variables = DatasetVariables() - with self.assertRaisesRegexp(KeyError, "invalid"): - result = engine.check_conditions_recursively(conditions, variables) \ No newline at end of file diff --git a/tests/test_operators.py b/tests/test_operators.py deleted file mode 100644 index 269f319..0000000 --- a/tests/test_operators.py +++ /dev/null @@ -1,2427 +0,0 @@ -import pandas as pd - -from business_rules.operators import (DataframeType, StringType, - NumericType, BooleanType, SelectType, - SelectMultipleType, GenericType) - -from . import TestCase -from decimal import Decimal -import sys -import pandas - -class StringOperatorTests(TestCase): - - def test_operator_decorator(self): - self.assertTrue(StringType("foo").equal_to.is_operator) - - def test_string_equal_to(self): - self.assertTrue(StringType("foo").equal_to("foo")) - self.assertFalse(StringType("foo").equal_to("Foo")) - - def test_string_not_equal_to(self): - self.assertTrue(StringType("foo").not_equal_to("Foo")) - self.assertTrue(StringType("foo").not_equal_to("boo")) - self.assertFalse(StringType("foo").not_equal_to("foo")) - - def test_string_equal_to_case_insensitive(self): - self.assertTrue(StringType("foo").equal_to_case_insensitive("FOo")) - self.assertTrue(StringType("foo").equal_to_case_insensitive("foo")) - self.assertFalse(StringType("foo").equal_to_case_insensitive("blah")) - - def test_string_starts_with(self): - self.assertTrue(StringType("hello").starts_with("he")) - self.assertFalse(StringType("hello").starts_with("hey")) - self.assertFalse(StringType("hello").starts_with("He")) - - def test_string_ends_with(self): - self.assertTrue(StringType("hello").ends_with("lo")) - self.assertFalse(StringType("hello").ends_with("boom")) - self.assertFalse(StringType("hello").ends_with("Lo")) - - def test_string_contains(self): - self.assertTrue(StringType("hello").contains("ell")) - self.assertTrue(StringType("hello").contains("he")) - self.assertTrue(StringType("hello").contains("lo")) - self.assertFalse(StringType("hello").contains("asdf")) - self.assertFalse(StringType("hello").contains("ElL")) - - def test_string_matches_regex(self): - self.assertTrue(StringType("hello").matches_regex(r"^h")) - self.assertFalse(StringType("hello").matches_regex(r"^sh")) - - def test_non_empty(self): - self.assertTrue(StringType("hello").non_empty()) - self.assertFalse(StringType("").non_empty()) - self.assertFalse(StringType(None).non_empty()) - - -class NumericOperatorTests(TestCase): - - def test_instantiate(self): - err_string = "foo is not a valid numeric type" - with self.assertRaisesRegexp(AssertionError, err_string): - NumericType("foo") - - def test_numeric_type_validates_and_casts_decimal(self): - ten_dec = Decimal(10) - ten_int = 10 - ten_float = 10.0 - if sys.version_info[0] == 2: - ten_long = long(10) - else: - ten_long = int(10) # long and int are same in python3 - ten_var_dec = NumericType(ten_dec) # this should not throw an exception - ten_var_int = NumericType(ten_int) - ten_var_float = NumericType(ten_float) - ten_var_long = NumericType(ten_long) - self.assertTrue(isinstance(ten_var_dec.value, Decimal)) - self.assertTrue(isinstance(ten_var_int.value, Decimal)) - self.assertTrue(isinstance(ten_var_float.value, Decimal)) - self.assertTrue(isinstance(ten_var_long.value, Decimal)) - - def test_numeric_equal_to(self): - self.assertTrue(NumericType(10).equal_to(10)) - self.assertTrue(NumericType(10).equal_to(10.0)) - self.assertTrue(NumericType(10).equal_to(10.000001)) - self.assertTrue(NumericType(10.000001).equal_to(10)) - self.assertTrue(NumericType(Decimal('10.0')).equal_to(10)) - self.assertTrue(NumericType(10).equal_to(Decimal('10.0'))) - self.assertFalse(NumericType(10).equal_to(10.00001)) - self.assertFalse(NumericType(10).equal_to(11)) - - def test_numeric_not_equal_to(self): - self.assertTrue(NumericType(10).not_equal_to(10.00001)) - self.assertTrue(NumericType(10).not_equal_to(11)) - self.assertTrue(NumericType(Decimal('10.0')).not_equal_to(Decimal('10.1'))) - - self.assertFalse(NumericType(10).not_equal_to(10)) - self.assertFalse(NumericType(10).not_equal_to(10.0)) - self.assertFalse(NumericType(Decimal('10.0')).not_equal_to(Decimal('10.0'))) - - def test_other_value_not_numeric(self): - error_string = "10 is not a valid numeric type" - with self.assertRaisesRegexp(AssertionError, error_string): - NumericType(10).equal_to("10") - - def test_numeric_greater_than(self): - self.assertTrue(NumericType(10).greater_than(1)) - self.assertFalse(NumericType(10).greater_than(11)) - self.assertTrue(NumericType(10.1).greater_than(10)) - self.assertFalse(NumericType(10.000001).greater_than(10)) - self.assertTrue(NumericType(10.000002).greater_than(10)) - - def test_numeric_greater_than_or_equal_to(self): - self.assertTrue(NumericType(10).greater_than_or_equal_to(1)) - self.assertFalse(NumericType(10).greater_than_or_equal_to(11)) - self.assertTrue(NumericType(10.1).greater_than_or_equal_to(10)) - self.assertTrue(NumericType(10.000001).greater_than_or_equal_to(10)) - self.assertTrue(NumericType(10.000002).greater_than_or_equal_to(10)) - self.assertTrue(NumericType(10).greater_than_or_equal_to(10)) - - def test_numeric_less_than(self): - self.assertTrue(NumericType(1).less_than(10)) - self.assertFalse(NumericType(11).less_than(10)) - self.assertTrue(NumericType(10).less_than(10.1)) - self.assertFalse(NumericType(10).less_than(10.000001)) - self.assertTrue(NumericType(10).less_than(10.000002)) - - def test_numeric_less_than_or_equal_to(self): - self.assertTrue(NumericType(1).less_than_or_equal_to(10)) - self.assertFalse(NumericType(11).less_than_or_equal_to(10)) - self.assertTrue(NumericType(10).less_than_or_equal_to(10.1)) - self.assertTrue(NumericType(10).less_than_or_equal_to(10.000001)) - self.assertTrue(NumericType(10).less_than_or_equal_to(10.000002)) - self.assertTrue(NumericType(10).less_than_or_equal_to(10)) - - -class BooleanOperatorTests(TestCase): - - def test_instantiate(self): - err_string = "foo is not a valid boolean type" - with self.assertRaisesRegexp(AssertionError, err_string): - BooleanType("foo") - err_string = "None is not a valid boolean type" - with self.assertRaisesRegexp(AssertionError, err_string): - BooleanType(None) - - def test_boolean_is_true_and_is_false(self): - self.assertTrue(BooleanType(True).is_true()) - self.assertFalse(BooleanType(True).is_false()) - self.assertFalse(BooleanType(False).is_true()) - self.assertTrue(BooleanType(False).is_false()) - - -class SelectOperatorTests(TestCase): - - def test_contains(self): - self.assertTrue(SelectType([1, 2]).contains(2)) - self.assertFalse(SelectType([1, 2]).contains(3)) - self.assertTrue(SelectType([1, 2, "a"]).contains("A")) - - def test_does_not_contain(self): - self.assertTrue(SelectType([1, 2]).does_not_contain(3)) - self.assertFalse(SelectType([1, 2]).does_not_contain(2)) - self.assertFalse(SelectType([1, 2, "a"]).does_not_contain("A")) - - -class SelectMultipleOperatorTests(TestCase): - - def test_contains_all(self): - self.assertTrue(SelectMultipleType([1, 2]). - contains_all([2, 1])) - self.assertFalse(SelectMultipleType([1, 2]). - contains_all([2, 3])) - self.assertTrue(SelectMultipleType([1, 2, "a"]). - contains_all([2, 1, "A"])) - - def test_is_contained_by(self): - self.assertTrue(SelectMultipleType([1, 2]). - is_contained_by([2, 1, 3])) - self.assertFalse(SelectMultipleType([1, 2]). - is_contained_by([2, 3, 4])) - self.assertTrue(SelectMultipleType([1, 2, "a"]). - is_contained_by([2, 1, "A"])) - - def test_shares_at_least_one_element_with(self): - self.assertTrue(SelectMultipleType([1, 2]). - shares_at_least_one_element_with([2, 3])) - self.assertFalse(SelectMultipleType([1, 2]). - shares_at_least_one_element_with([4, 3])) - self.assertTrue(SelectMultipleType([1, 2, "a"]). - shares_at_least_one_element_with([4, "A"])) - - def test_shares_exactly_one_element_with(self): - self.assertTrue(SelectMultipleType([1, 2]). - shares_exactly_one_element_with([2, 3])) - self.assertFalse(SelectMultipleType([1, 2]). - shares_exactly_one_element_with([4, 3])) - self.assertTrue(SelectMultipleType([1, 2, "a"]). - shares_exactly_one_element_with([4, "A"])) - self.assertFalse(SelectMultipleType([1, 2, 3]). - shares_exactly_one_element_with([2, 3, "a"])) - - def test_shares_no_elements_with(self): - self.assertTrue(SelectMultipleType([1, 2]). - shares_no_elements_with([4, 3])) - self.assertFalse(SelectMultipleType([1, 2]). - shares_no_elements_with([2, 3])) - self.assertFalse(SelectMultipleType([1, 2, "a"]). - shares_no_elements_with([4, "A"])) - -class DataframeOperatorTests(TestCase): - def test_exists(self): - df = pandas.DataFrame.from_dict({ - "var1": [1, 2, 4, ], - "var2": [3, 5, 6, ], - }) - result: pd.Series = DataframeType({"value": df}).exists({"target": "var1"}) - self.assertTrue(result.equals(pd.Series([True, True, True, ]))) - - result: pd.Series = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).exists({"target": "--r1"}) - self.assertTrue(result.equals(pd.Series([True, True, True, ]))) - - result: pd.Series = DataframeType({"value": df}).exists({"target": "invalid"}) - self.assertTrue(result.equals(pd.Series([False, False, False, ]))) - - def test_not_exists(self): - df = pandas.DataFrame.from_dict({ - "var1": [1, 2, 4, ], - "var2": [3, 5, 6, ] - }) - result: pd.Series = DataframeType({"value": df}).not_exists({"target": "invalid"}) - self.assertTrue(result.equals(pd.Series([True, True, True, ]))) - - result: pd.Series = DataframeType({"value": df}).not_exists({"target": "var1"}) - self.assertTrue(result.equals(pd.Series([False, False, False, ]))) - - result: pd.Series = DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).not_exists({"target": "--r1"}) - self.assertTrue(result.equals(pd.Series([False, False, False, ]))) - - def test_equal_to(self): - df = pandas.DataFrame.from_dict({ - "var1": [1, 2, 4, "", 7, ], - "var2": [3, 5, 6, "", 2, ], - "var3": [1, 3, 8, "", 7, ], - "var4": ["test", "issue", "one", "", "two", ], - "var5": [None, None, "test", None, "B"], - "var6": ["", None, "test", "", "B"] - }) - self.assertTrue(DataframeType({"value": df}).equal_to({ - "target": "var1", - "comparator": "" - }).equals(pandas.Series([False, False, False, False, False, ]))) - self.assertTrue(DataframeType({"value": df}).equal_to({ - "target": "var1", - "comparator": 2 - }).equals(pandas.Series([False, True, False, False, False, ]))) - self.assertTrue(DataframeType({"value": df}).equal_to({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([True, False, False, False, True, ]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).equal_to({ - "target": "--r1", - "comparator": "--r3" - }).equals(pandas.Series([True, False, False, False, True, ]))) - self.assertTrue(DataframeType({"value": df}).equal_to({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([False, False, False, False, False, ]))) - self.assertTrue(DataframeType({"value": df}).equal_to({ - "target": "var1", - "comparator": 20 - }).equals(pandas.Series([False, False, False, False, False, ]))) - self.assertTrue(DataframeType({"value": df}).equal_to({ - "target": "var4", - "comparator": "var1", - "value_is_literal": True - }).equals(pandas.Series([False, False, False, False, False, ]))) - self.assertTrue(DataframeType({"value": df}).equal_to({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, True, False, True]))) - - def test_not_equal_to(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "var5": [None, None, None], - "var7": ["", "", ""], - "var6": ["", None, "test"] - }) - self.assertTrue(DataframeType({"value": df}).not_equal_to({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).not_equal_to({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).not_equal_to({ - "target": "--r1", - "comparator": "--r2" - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).not_equal_to({ - "target": "--r1", - "comparator": 20 - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).not_equal_to({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, True]))) - self.assertTrue(DataframeType({"value": df}).not_equal_to({ - "target": "var6", - "comparator": "var7" - }).equals(pandas.Series([False, False, True]))) - - def test_equal_to_case_insensitive(self): - df = pandas.DataFrame.from_dict({ - "var1": ["word", "", "new", "val"], - "var2": ["WORD", "", "test", "VAL"], - "var3": ["LET", "", "GO", "read"], - "var5": [None, None, None, None], - "var6": ["", None, "test", None] - }) - self.assertTrue(DataframeType({"value": df}).equal_to_case_insensitive({ - "target": "var1", - "comparator": "NEW" - }).equals(pandas.Series([False, False, True, False]))) - self.assertTrue(DataframeType({"value": df}).equal_to_case_insensitive({ - "target": "var1", - "comparator": "" - }).equals(pandas.Series([False, False, False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).equal_to_case_insensitive({ - "target": "--r1", - "comparator": "--r2" - }).equals(pandas.Series([True, False, False, True]))) - self.assertTrue(DataframeType({"value": df}).equal_to_case_insensitive({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([True, False, False, True]))) - self.assertTrue(DataframeType({"value": df}).equal_to_case_insensitive({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).equal_to_case_insensitive({ - "target": "var1", - "comparator": "var1", - "value_is_literal": True - }).equals(pandas.Series([False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).equal_to_case_insensitive({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, False, False]))) - - def test_not_equal_to_case_insensitive(self): - df = pandas.DataFrame.from_dict({ - "var1": ["word", "new", "val"], - "var2": ["WORD", "test", "VAL"], - "var3": ["LET", "GO", "read"], - "var4": ["WORD", "NEW", "VAL"], - "var5": [None, None, None], - "var7": ["", "", ""], - "var6": ["", None, "test"] - - }) - self.assertTrue(DataframeType({"value": df}).not_equal_to_case_insensitive({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).not_equal_to_case_insensitive({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([False, True, False]))) - self.assertTrue(DataframeType({"value": df}).not_equal_to_case_insensitive({ - "target": "var1", - "comparator": "var1", - "value_is_literal": True - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).not_equal_to_case_insensitive({ - "target": "var5", - "comparator": "var6" - }).equals(pandas.Series([False, False, True]))) - self.assertTrue(DataframeType({"value": df}).not_equal_to_case_insensitive({ - "target": "var6", - "comparator": "var7" - }).equals(pandas.Series([False, False, True]))) - - def test_is_contained_by(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "var5": [[1,2,3], [1,2], [17]] - }) - self.assertTrue(DataframeType({"value": df}).is_contained_by({ - "target": "var1", - "comparator": [4,5,6] - }).equals(pandas.Series([False, False, True]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).is_contained_by({ - "target": "var1", - "comparator": "--r3" - }).equals(pandas.Series([True, False, False]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by({ - "target": "var1", - "comparator": [9, 10, 11] - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by({ - "target": "var1", - "comparator": "var2" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by({ - "target": "var1", - "comparator": "var5" - }).equals(pandas.Series([True, True, False]))) - - - def test_is_not_contained_by(self): - df = pandas.DataFrame.from_dict({ - "var1": [1,2,4], - "var2": [3,5,6], - "var3": [1,3,8], - "var4": [1,2,4], - "var5": [[1,2,3], [1,2], [17]] - }) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).is_not_contained_by({ - "target": "var1", - "comparator": "--r3" - }).equals(pandas.Series([False, True, True]))) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by({ - "target": "var1", - "comparator": [9, 10, 11] - }).equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by({ - "target": "var1", - "comparator": "var1" - }).equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by({ - "target": "var1", - "comparator": "var5" - }).equals(pandas.Series([False, False, True]))) - - def test_is_contained_by_case_insensitive(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [set(["word"]), set(["test"])] - }) - self.assertTrue(DataframeType({"value": df}).is_contained_by_case_insensitive({ - "target": "var1", - "comparator": ["word", "TEST"] - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by_case_insensitive({ - "target": "var1", - "comparator": "var1" - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by_case_insensitive({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).is_contained_by_case_insensitive({ - "target": "var1", - "comparator": "--r3" - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by_case_insensitive({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).is_contained_by_case_insensitive({ - "target": "var3", - "comparator": "var4" - }).equals(pandas.Series([False, False]))) - - def test_is_not_contained_by_case_insensitive(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [set(["word"]), set(["test"])] - }) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by_case_insensitive({ - "target": "var1", - "comparator": ["word", "TEST"] - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by_case_insensitive({ - "target": "var1", - "comparator": "var3" - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).is_not_contained_by_case_insensitive({ - "target": "var1", - "comparator": "--r3" - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by_case_insensitive({ - "target": "var1", - "comparator": "var4" - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).is_not_contained_by_case_insensitive({ - "target": "var3", - "comparator": "var4" - }).equals(pandas.Series([True, True]))) - - def test_prefix_matches_regex(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [224, None], - "var5": [-25, 3.14] - }) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).prefix_matches_regex({ - "target": "--r2", - "comparator": "w.*", - "prefix": 2 - }).equals(pandas.Series([True, False]))) - self.assertTrue(DataframeType({"value": df}).prefix_matches_regex({ - "target": "var2", - "comparator": "[0-9].*", - "prefix": 2 - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).prefix_matches_regex({ - "target": "var4", - "comparator": "^[1-9]{1}\d*$", - "prefix": 2 - }).equals(pandas.Series([True, False]))) - self.assertTrue(DataframeType({"value": df}).prefix_matches_regex({ - "target": "var5", - "comparator": "^[1-9]{1}\d*$", - "prefix": 2 - }).equals(pandas.Series([False, False]))) - - def test_suffix_matches_regex(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [224, None], - "var5": [-25, 3.14] - }) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).suffix_matches_regex({ - "target": "--r1", - "comparator": "es.*", - "suffix": 3 - }).equals(pandas.Series([False, True]))) - self.assertTrue(DataframeType({"value": df}).suffix_matches_regex({ - "target": "var1", - "comparator": "[0-9].*", - "suffix": 3 - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).suffix_matches_regex({ - "target": "var4", - "comparator": "[1-9]{1}\d*", - "suffix": 2 - }).equals(pandas.Series([True, False]))) - self.assertTrue(DataframeType({"value": df}).suffix_matches_regex({ - "target": "var5", - "comparator": "[1-9]{1}\d*", - "suffix": 2 - }).equals(pandas.Series([True, True]))) - - def test_not_prefix_matches_suffix(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [224, None], - "var5": [-25, 3.14] - }) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).not_prefix_matches_regex({ - "target": "--r1", - "comparator": ".*", - "prefix": 2 - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).not_prefix_matches_regex({ - "target": "var2", - "comparator": "[0-9].*", - "prefix": 2 - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).not_prefix_matches_regex({ - "target": "var4", - "comparator": "^[1-9]{1}\d*$", - "prefix": 2 - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).not_prefix_matches_regex({ - "target": "var5", - "comparator": "^[1-9]{1}\d*$", - "prefix": 2 - }).equals(pandas.Series([True, True]))) - - def test_not_suffix_matches_regex(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [224, None], - "var5": [-25, 3.14] - }) - self.assertTrue(DataframeType({"value": df}).not_suffix_matches_regex({ - "target": "var1", - "comparator": ".*", - "suffix": 3 - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).not_suffix_matches_regex({ - "target": "--r1", - "comparator": "[0-9].*", - "suffix": 3 - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).not_suffix_matches_regex({ - "target": "var4", - "comparator": "[1-9]{1}\d*", - "suffix": 2 - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).not_suffix_matches_regex({ - "target": "var5", - "comparator": "[1-9]{1}\d*", - "suffix": 2 - }).equals(pandas.Series([False, False]))) - - def test_matches_regex(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [224, None], - "var5": [-25, 3.14] - }) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).matches_regex({ - "target": "--r1", - "comparator": ".*", - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).matches_regex({ - "target": "var2", - "comparator": "[0-9].*", - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).matches_regex({ - "target": "var4", - "comparator": "^-?[1-9]{1}\d*$", - }).equals(pandas.Series([True, False]))) - self.assertTrue(DataframeType({"value": df}).matches_regex({ - "target": "var5", - "comparator": "^-?[1-9]{1}\d*$", - }).equals(pandas.Series([True, False]))) - - def test_not_matches_regex(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": [224, None], - "var5": [-25, 3.14] - }) - self.assertTrue(DataframeType({"value": df}).not_matches_regex({ - "target": "var1", - "comparator": ".*", - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).not_matches_regex({ - "target": "--r1", - "comparator": "[0-9].*", - }).equals(pandas.Series([True, True]))) - self.assertTrue(DataframeType({"value": df}).not_matches_regex({ - "target": "var4", - "comparator": "^-?[1-9]{1}\d*$", - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).not_matches_regex({ - "target": "var5", - "comparator": "^-?[1-9]{1}\d*$", - }).equals(pandas.Series([False, True]))) - - def test_starts_with(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": ["WO", "abc"], - }) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).starts_with({ - "target": "--r1", - "comparator": "WO", - "value_is_literal": True, - }).equals(pandas.Series([True, False]))) - self.assertTrue(DataframeType({"value": df}).starts_with({ - "target": "var1", - "comparator": "var4", - }).equals(pandas.Series([True, False]))) - - def test_ends_with(self): - df = pandas.DataFrame.from_dict({ - "var1": ["WORD", "test"], - "var2": ["word", "TEST"], - "var3": ["another", "item"], - "var4": ["RD", "abc"], - }) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).ends_with({ - "target": "--r1", - "comparator": "abc", - "value_is_literal": True, - }).equals(pandas.Series([False, False]))) - self.assertTrue(DataframeType({"value": df}).ends_with({ - "target": "var1", - "comparator": "est", - "value_is_literal": True, - }).equals(pandas.Series([False, True]))) - self.assertTrue(DataframeType({"value": df}).ends_with({ - "target": "var1", - "comparator": "var4", - }).equals(pandas.Series([True, False]))) - - def test_date_equal_to(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['2021', '2021', '2021', '2021', '2021'], - "var2": ["2099", "2022", "2034", "90999", "20999"], - "var3": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var4": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var5": ["1997-08", "1997-08-16", "1997-08-16T19:20:30.45+01:00", "1997-08-16T19:20:30+01:00", "1997-08-16T19:20+01:00"], - "var6": ["1998-08", "1998-08-11", "1998-08-17T20:21:31.46+01:00", "1998-08-17T20:21:31+01:00", "1998-08-17T20:21+01:00"], - "var7": ["", None, "", "", ""] - } - ) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var1", "comparator": '2021'}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "1997-07-16T19:20:30.45+01:00"}) - .equals(pandas.Series([False, False, True, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var4"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df, "column_prefix_map": {"--": "va"}}).date_equal_to({"target": "--r3", "comparator": "--r4", "date_component": "year"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var5", "date_component": "hour"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var5", "date_component": "minute"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var5", "date_component": "second"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var5", "date_component": "microsecond"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var5", "date_component": "year"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var5", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var6", "date_component": "year"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var6", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var3", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_equal_to({"target": "var7", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - - def test_date_not_equal_to(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['2021', '2021', '2021', '2021', '2021'], - "var2": ["2099", "2022", "2034", "90999", "20999"], - "var3": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var4": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var5": ["1997-08", "1997-08-16", "1997-08-16T19:20:30.45+01:00", "1997-08-16T19:20:30+01:00", "1997-08-16T19:20+01:00"], - "var6": ["1998-08", "1998-08-11", "1998-08-17T20:21:31.46+01:00", "1998-08-17T20:21:31+01:00", "1998-08-17T20:21+01:00"], - "var7": ["", None, "", "", ""] - } - ) - self.assertTrue(DataframeType({"value": df}).date_not_equal_to({"target": "var1", "comparator": '2022'}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_not_equal_to({"target": "var3", "comparator": "1998-07-16T19:20:30.45+01:00"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_not_equal_to({"target": "var3", "comparator": "var4"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_not_equal_to({"target": "var3", "comparator": "var4", "date_component": "year"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_not_equal_to({"target": "var3", "comparator": "var6", "date_component": "hour"}) - .equals(pandas.Series([False, False, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_not_equal_to({"target": "var3", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_not_equal_to({"target": "var7", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - - def test_date_less_than(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['2021', '2021', '2021', '2021', '2021'], - "var2": ["2099", "2022", "2034", "90999", "20999"], - "var3": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var4": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var5": ["1997-08", "1997-08-16", "1997-08-16T19:20:30.45+01:00", "1997-08-16T19:20:30+01:00", "1997-08-16T19:20+01:00"], - "var6": ["1998-08", "1998-08-11", "1998-08-17T20:21:31.46+01:00", "1998-08-17T20:21:31+01:00", "1998-08-17T20:21+01:00"], - "var7": ["", None, "", "", ""] - } - ) - self.assertTrue(DataframeType({"value": df}).date_less_than({"target": "var1", "comparator": '2022'}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_less_than({"target": "var3", "comparator": "1998-07-16T19:20:30.45+01:00"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_less_than({"target": "var3", "comparator": "var4"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_less_than({"target": "var3", "comparator": "var4", "date_component": "year"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_less_than({"target": "var3", "comparator": "var6", "date_component": "hour"}) - .equals(pandas.Series([False, False, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_less_than({"target": "var3", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_less_than({"target": "var7", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - - def test_date_greater_than(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['2021', '2021', '2021', '2021', '2021'], - "var2": ["2099", "2022", "2034", "90999", "20999"], - "var3": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var4": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var5": ["1997-08", "1997-08-16", "1997-08-16T19:20:30.45+01:00", "1997-08-16T19:20:30+01:00", "1997-08-16T19:20+01:00"], - "var6": ["1998-08", "1998-08-11", "1998-08-17T20:21:31.46+01:00", "1998-08-17T20:21:31+01:00", "1998-08-17T20:21+01:00"], - "var7": ["", None, "", "", ""] - } - ) - self.assertTrue(DataframeType({"value": df}).date_greater_than({"target": "var1", "comparator": '2020'}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than({"target": "var3", "comparator": "1996-07-16T19:20:30.45+01:00"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than({"target": "var3", "comparator": "var4"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than({"target": "var3", "comparator": "var4", "date_component": "year"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than({"target": "var6", "comparator": "var3", "date_component": "hour"}) - .equals(pandas.Series([False, False, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than({"target": "var3", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than({"target": "var7", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - - def test_date_greater_than_or_equal_to(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['2021', '2021', '2021', '2021', '2021'], - "var2": ["2099", "2022", "2034", "90999", "20999"], - "var3": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var4": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var5": ["1997-08", "1997-08-16", "1997-08-16T19:20:30.45+01:00", "1997-08-16T19:20:30+01:00", "1997-08-16T19:20+01:00"], - "var6": ["1998-08", "1998-08-11", "1998-08-17T20:21:31.46+01:00", "1998-08-17T20:21:31+01:00", "1998-08-17T20:21+01:00"], - "var7": ["", None, "", "", ""] - } - ) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var1", "comparator": '2020'}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var1", "comparator": '2023'}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var3", "comparator": "1996-07-16T19:20:30.45+01:00"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var3", "comparator": "var4"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var3", "comparator": "var4", "date_component": "year"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var6", "comparator": "var3", "date_component": "hour"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var3", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_greater_than_or_equal_to({"target": "var7", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - - def test_date_less_than_or_equal_to(self): - df = pandas.DataFrame.from_dict( - { - "var1": ['2021', '2021', '2021', '2021', '2021'], - "var2": ["2099", "2022", "2034", "90999", "20999"], - "var3": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var4": ["1997-07", "1997-07-16", "1997-07-16T19:20:30.45+01:00", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - "var5": ["1997-08", "1997-08-16", "1997-08-16T19:20:30.45+01:00", "1997-08-16T19:20:30+01:00", "1997-08-16T19:20+01:00"], - "var6": ["1998-08", "1998-08-11", "1998-08-17T20:21:31.46+01:00", "1998-08-17T20:21:31+01:00", "1998-08-17T20:21+01:00"], - "var7": ["", None, "", "", ""] - } - ) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var1", "comparator": '2022'}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var1", "comparator": '2020'}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var3", "comparator": "1998-07-16T19:20:30.45+01:00"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var3", "comparator": "var4"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var3", "comparator": "var4", "date_component": "year"}) - .equals(pandas.Series([True, True, True, True, True]))) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var6", "comparator": "var3", "date_component": "hour"}) - .equals(pandas.Series([True, True, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var3", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - self.assertTrue(DataframeType({"value": df}).date_less_than_or_equal_to({"target": "var7", "comparator": "var7", "date_component": "month"}) - .equals(pandas.Series([False, False, False, False, False]))) - - def test_is_incomplete_date(self): - df = pandas.DataFrame.from_dict( - { - "var1": [ '2021', '2021', '2099'], - "var2": [ "1997-07-16", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - } - ) - self.assertTrue(DataframeType({"value": df}).is_incomplete_date({"target" : "var1"}) - .equals(pandas.Series([True, True, True]))) - self.assertTrue(DataframeType({"value": df}).is_incomplete_date({"target" : "var2"}) - .equals(pandas.Series([False, False, False]))) - - def test_is_complete_date(self): - df = pandas.DataFrame.from_dict( - { - "var1": ["2021", "2021", "2099"], - "var2": ["1997-07-16", "1997-07-16T19:20:30+01:00", "1997-07-16T19:20+01:00"], - } - ) - self.assertTrue(DataframeType({"value": df}).is_complete_date({"target": "var1"}) - .equals(pandas.Series([False, False, False]))) - self.assertTrue(DataframeType({"value": df}).is_complete_date({"target": "var2"}) - .equals(pandas.Series([True, True, True]))) - - def test_is_ordered_set(self): - df = pandas.DataFrame.from_dict( {"USUBJID": [1,2,1,2], "SESEQ": [1,1,2,2] }) - self.assertTrue(DataframeType({"value": df}).is_ordered_set({"target" : "SESEQ", "comparator": "USUBJID"})) - self.assertTrue(DataframeType({"value":df, "column_prefix_map": {"--": "SE"}}).is_ordered_set({"target" : "--SEQ", "comparator": "USUBJID"})) - - df2 = pandas.DataFrame.from_dict( {"USUBJID": [1,2,1,2], "SESEQ": [3,1,2,2] }) - self.assertFalse(DataframeType({"value": df2}).is_ordered_set({"target" : "SESEQ", "comparator": "USUBJID"})) - self.assertFalse(DataframeType({"value":df2, "column_prefix_map": {"--": "SE"}}).is_ordered_set({"target" : "--SEQ", "comparator": "USUBJID"})) - - def test_is_not_ordered_set(self): - df = pandas.DataFrame.from_dict( {"USUBJID": [1,2,1,2], "SESEQ": [3,1,2,2] }) - self.assertTrue(DataframeType({"value": df}).is_not_ordered_set({"target" : "SESEQ", "comparator": "USUBJID"})) - self.assertTrue(DataframeType({"value":df, "column_prefix_map": {"--": "SE"}}).is_not_ordered_set({"target" : "--SEQ", "comparator": "USUBJID"})) - - df2 = pandas.DataFrame.from_dict( {"USUBJID": [1,2,1,2], "SESEQ": [1,1,2,2] }) - self.assertFalse(DataframeType({"value": df2}).is_not_ordered_set({"target" : "SESEQ", "comparator": "USUBJID"})) - self.assertFalse(DataframeType({"value":df2, "column_prefix_map": {"--": "SE"}}).is_not_ordered_set({"target" : "--SEQ", "comparator": "USUBJID"})) - - def test_is_unique_relationship(self): - """ - Test validates one-to-one relationship against a dataset. - One-to-one means that a pair of columns can be duplicated - but its integrity should not be violated. - """ - one_to_one_related_df = pandas.DataFrame.from_dict( - { - "STUDYID": [1, 2, 3, 1, 2], - "USUBJID": ["TEST", "TEST-1", "TEST-2", "TEST-3", "TEST-4", ], - "STUDYDESC": ["Russia", "USA", "China", "Russia", "USA", ], - } - ) - self.assertTrue( - DataframeType({"value": one_to_one_related_df}).is_unique_relationship( - {"target": "STUDYID", "comparator": "STUDYDESC"} - ).equals(pandas.Series([True, True, True, True, True])) - ) - self.assertTrue( - DataframeType({"value": one_to_one_related_df}).is_unique_relationship( - {"target": "STUDYDESC", "comparator": "STUDYID"} - ).equals(pandas.Series([True, True, True, True, True])) - ) - self.assertTrue( - DataframeType({"value": one_to_one_related_df, "column_prefix_map":{"--": "STUDY"}}).is_unique_relationship( - {"target": "--ID", "comparator": "--DESC"} - ).equals(pandas.Series([True, True, True, True, True])) - ) - self.assertTrue( - DataframeType({"value": one_to_one_related_df, "column_prefix_map":{"--": "STUDY"}}).is_unique_relationship( - {"target": "--DESC", "comparator": "--ID"} - ).equals(pandas.Series([True, True, True, True, True])) - ) - - df_violates_one_to_one = pandas.DataFrame.from_dict( - { - "STUDYID": ["TEST", "TEST-1", "TEST-2", "TEST-3", ], - "TESTID": [1, 2, 1, 3], - "TESTNAME": ["Functional", "Stress", "Functional", "Stress", ], - } - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one}).is_unique_relationship( - {"target": "TESTID", "comparator": "TESTNAME"}).equals(pandas.Series([True, False, True, False])) - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one}).is_unique_relationship( - {"target": "TESTNAME", "comparator": "TESTID"}).equals(pandas.Series([True, False, True, False])) - ) - - def test_is_not_unique_relationship(self): - """ - Test validates one-to-one relationship against a dataset. - One-to-one means that a pair of columns can be duplicated - but its integrity should not be violated. - """ - valid_df = pandas.DataFrame.from_dict( - { - "STUDYID": ["TEST", "TEST-1", "TEST-2", "TEST-3", ], - "VISITNUM": [1, 2, 1, 3], - "VISIT": ["Consulting", "Surgery", "Consulting", "Treatment", ], - } - ) - self.assertTrue(DataframeType({"value": valid_df}).is_not_unique_relationship( - {"target": "VISITNUM", "comparator": "VISIT"}).equals(pandas.Series([False, False, False, False])) - ) - self.assertTrue(DataframeType({"value": valid_df}).is_not_unique_relationship( - {"target": "VISIT", "comparator": "VISITNUM"}).equals(pandas.Series([False, False, False, False])) - ) - - valid_df_1 = pandas.DataFrame.from_dict( - { - "STUDYID": ["TEST", "TEST-1", "TEST-2", "TEST-3", ], - "VISIT": ["Consulting", "Surgery", "Consulting", "Treatment", ], - "VISITDESC": [ - "Doctor Consultation", "Heart Surgery", "Doctor Consultation", "Long Lasting Treatment", - ], - } - ) - self.assertTrue(DataframeType({"value": valid_df_1}).is_not_unique_relationship( - {"target": "VISIT", "comparator": "VISITDESC"}).equals(pandas.Series([False, False, False, False])) - ) - self.assertTrue(DataframeType({"value": valid_df_1}).is_not_unique_relationship( - {"target": "VISITDESC", "comparator": "VISIT"}).equals(pandas.Series([False, False, False, False])) - ) - - df_violates_one_to_one = pandas.DataFrame.from_dict( - { - "STUDYID": ["TEST", "TEST-1", "TEST-2", "TEST-3", ], - "VISITNUM": [1, 2, 1, 3], - "VISIT": ["Consulting", "Surgery", "Consulting", "Consulting", ], - } - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one}).is_not_unique_relationship( - {"target": "VISITNUM", "comparator": "VISIT"}).equals(pandas.Series([True, False, True, True])) - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one}).is_not_unique_relationship( - {"target": "VISIT", "comparator": "VISITNUM"}).equals(pandas.Series([True, False, True, True])) - ) - - df_violates_one_to_one_1 = pandas.DataFrame.from_dict( - { - "STUDYID": ["TEST", "TEST-1", "TEST-2", "TEST-3", "TEST-4", ], - "VISIT": ["Consulting", "Consulting", "Surgery", "Consulting", "Treatment", ], - "VISITDESC": ["Doctor Consultation", "Doctor Consultation", "Heart Surgery", "Heart Surgery", "Long Lasting Treatment", ], - } - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one_1}).is_not_unique_relationship( - {"target": "VISIT", "comparator": "VISITDESC"}).equals(pandas.Series([True, True, True, True, False])) - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one_1}).is_not_unique_relationship( - {"target": "VISITDESC", "comparator": "VISIT"}).equals(pandas.Series([True, True, True, True, False])) - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one_1, "column_prefix_map": {"--": "VI"}}).is_not_unique_relationship( - {"target": "--SIT", "comparator": "--SITDESC"}).equals(pandas.Series([True, True, True, True, False])) - ) - self.assertTrue(DataframeType({"value": df_violates_one_to_one_1, "column_prefix_map": {"--": "VI"}}).is_not_unique_relationship( - {"target": "--SITDESC", "comparator": "--SIT"}).equals(pandas.Series([True, True, True, True, False])) - ) - - def test_empty_within_except_last_row(self): - df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 2, 2, 2], - "valid": ["2020-10-10", "2020-10-10", "2020-10-10", "2021", "2021", "2021", ], - "invalid": ["2020-10-10", None, None, "2020", "2020", None, ], - } - ) - self.assertFalse( - DataframeType({"value": df}).empty_within_except_last_row({"target": "valid", "comparator": "USUBJID"}) - ) - self.assertTrue( - DataframeType({"value": df}).empty_within_except_last_row({"target": "invalid", "comparator": "USUBJID"}) - ) - - def test_non_empty_within_except_last_row(self): - df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 2, 2, 2], - "valid": ["2020-10-10", "2020-10-10", "2020-10-10", "2021", "2021", "2021", ], - "invalid": ["2020-10-10", None, None, "2020", "2020", None, ], - } - ) - self.assertTrue( - DataframeType({"value": df}).non_empty_within_except_last_row({"target": "valid", "comparator": "USUBJID"}) - ) - self.assertFalse( - DataframeType({"value": df}).non_empty_within_except_last_row({"target": "invalid", "comparator": "USUBJID"}) - ) - - def test_is_valid_reference(self): - reference_data = { - "LB": { - "TEST": [], - "DATA": [1,2,3] - }, - "AE": { - "AETERM": [1,2,3] - } - } - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "DATA", "AETERM"], - "IDVAR2": ["TEST", "AETERM", "AETERM"] - } - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_valid_reference({"target": "IDVAR1", "context": "RDOMAIN"}) - .equals(pandas.Series([True, True, True])) - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_valid_reference({"target": "IDVAR2", "context": "RDOMAIN"}) - .equals(pandas.Series([True, False, True])) - ) - - def test_not_valid_reference(self): - reference_data = { - "LB": { - "TEST": [], - "DATA": [1,2,3] - }, - "AE": { - "AETERM": [1,2,3] - } - } - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "DATA", "AETERM"], - "IDVAR2": ["TEST", "AETERM", "AETERM"] - } - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_not_valid_reference({"target": "IDVAR1", "context": "RDOMAIN"}) - .equals(pandas.Series([False, False, False])) - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_not_valid_reference({"target": "IDVAR2", "context": "RDOMAIN"}) - .equals(pandas.Series([False, True, False])) - ) - - def test_is_valid_relationship(self): - reference_data = { - "LB": { - "TEST": pandas.Series([4,5,6]).values, - "DATA": pandas.Series([1,2,3]).values - }, - "AE": { - "AETERM": pandas.Series([31, 323, 33]).values - } - } - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "DATA", "AETERM"], - "IDVAR2": ["TEST", "DATA", "AETERM"], - "IDVARVAL1": [4, 1, 31], - "IDVARVAL2": [5, 1, 35] - } - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_valid_relationship({"target": "IDVAR1", "comparator": "IDVARVAL1", "context": "RDOMAIN"}) - .equals(pandas.Series([True, True, True])) - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_valid_relationship({"target": "IDVAR2", "comparator": "IDVARVAL2", "context": "RDOMAIN"}) - .equals(pandas.Series([True, True, False])) - ) - - def test_not_valid_relationship(self): - reference_data = { - "LB": { - "TEST": pandas.Series([4,5,6]).values, - "DATA": pandas.Series([1,2,3]).values - }, - "AE": { - "AETERM": pandas.Series([31, 323, 33]).values - } - } - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "DATA", "AETERM"], - "IDVAR2": ["TEST", "DATA", "AETERM"], - "IDVARVAL1": [4, 1, 31], - "IDVARVAL2": [5, 1, 35] - } - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_not_valid_relationship({"target": "IDVAR1", "comparator": "IDVARVAL1", "context": "RDOMAIN"}) - .equals(pandas.Series([False, False, False])) - ) - self.assertTrue( - DataframeType({"value": df, "relationship_data": reference_data}).is_not_valid_relationship({"target": "IDVAR2", "comparator": "IDVARVAL2", "context": "RDOMAIN"}) - .equals(pandas.Series([False, False, True])) - ) - - def test_non_conformant_value_length(self): - def filter_func(row): - return row["IDVAR1"] == "TEST" - - def length_check(row): - return len(row["IDVAR2"]) <= 4 - - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "TEST", "AETERM"], - "IDVAR2": ["TEST", "TOOLONG", "AETERM"], - } - ) - - vlm = [ - { - "filter": filter_func, - "length_check": length_check - } - ] - - result = DataframeType({"value": df, "value_level_metadata": vlm }).non_conformant_value_length({}) - self.assertTrue(result.equals(pandas.Series([False, True, False]))) - - def test_non_conformant_value_data_type(self): - def filter_func(row): - return row["IDVAR1"] == "TEST" - - def type_check(row): - return isinstance(row["IDVAR2"], str) - - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "TEST", "AETERM"], - "IDVAR2": ["TEST", 1, "AETERM"], - } - ) - - vlm = [ - { - "filter": filter_func, - "type_check": type_check - } - ] - - result = DataframeType({"value": df, "value_level_metadata": vlm }).non_conformant_value_data_type({}) - self.assertTrue(result.equals(pandas.Series([False, True, False]))) - - def test_conformant_value_length(self): - def filter_func(row): - return row["IDVAR1"] == "TEST" - - def length_check(row): - return len(row["IDVAR2"]) <= 4 - - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "TEST", "AETERM"], - "IDVAR2": ["TEST", "TOOLONG", "AETERM"], - } - ) - - vlm = [ - { - "filter": filter_func, - "length_check": length_check - } - ] - - result = DataframeType({"value": df, "value_level_metadata": vlm }).conformant_value_length({}) - self.assertTrue(result.equals(pandas.Series([True, False, False]))) - - def test_conformant_value_data_type(self): - def filter_func(row): - return row["IDVAR1"] == "TEST" - - def type_check(row): - return isinstance(row["IDVAR2"], str) - - df = pandas.DataFrame.from_dict( - { - "RDOMAIN": ["LB", "LB", "AE"], - "IDVAR1": ["TEST", "TEST", "AETERM"], - "IDVAR2": ["TEST", 1, "AETERM"], - } - ) - - vlm = [ - { - "filter": filter_func, - "type_check": type_check - } - ] - - result = DataframeType({"value": df, "value_level_metadata": vlm }).conformant_value_data_type({}) - self.assertTrue(result.equals(pandas.Series([True, False, False]))) - - def test_has_next_corresponding_record(self): - """ - Test for has_next_corresponding_record operator. - """ - valid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [789, 789, 789, 789, 790, 790, 790, 790, ], - "SESEQ": [1, 2, 3, 4, 5, 6, 7, 8, ], - "SEENDTC": ["2006-06-03T10:32", "2006-06-10T09:47", "2006-06-17", "2006-06-17", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17", "2006-06-17"], - "SESTDTC": ["2006-06-01", "2006-06-03T10:32", "2006-06-10T09:47", "2006-06-17", "2006-06-01", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17"], - } - ) - other_value: dict = {"target": "SEENDTC", "comparator": "SESTDTC", "within": "USUBJID", "ordering": "SESEQ"} - result = DataframeType({"value": valid_df}).has_next_corresponding_record(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, pandas.NA, True, True, True, pandas.NA]))) - - invalid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [789, 789, 789, 789, 790, 790, 790, 790, ], - "SESEQ": [1, 2, 3, 4, 5, 6, 7, 8, ], - "SEENDTC": ["2006-06-03T10:32", "2006-06-10T09:47", "2006-06-17", "2006-06-17", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17", "2006-06-17"], - "SESTDTC": ["2006-06-01", "2010-08-03", "2008-08", "2006-06-17T10:20", "2006-06-01", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17"], - } - ) - other_value: dict = {"target": "SEENDTC", "comparator": "SESTDTC", "within": "USUBJID", "ordering": "SESEQ"} - result = DataframeType({"value": invalid_df}).has_next_corresponding_record(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, pandas.NA, True, True, True, pandas.NA]))) - - def test_does_not_have_next_corresponding_record(self): - """ - Test for does_not_have_next_corresponding_record operator. - """ - valid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [789, 789, 789, 789, 790, 790, 790, 790, ], - "SESEQ": [1, 2, 3, 4, 5, 6, 7, 8, ], - "SEENDTC": ["2006-06-03T10:32", "2006-06-10T09:47", "2006-06-17", "2006-06-17", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17", "2006-06-17"], - "SESTDTC": ["2006-06-01", "2006-06-03T10:32", "2006-06-10T09:47", "2006-06-17", "2006-06-01", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17"], - } - ) - other_value: dict = {"target": "SEENDTC", "comparator": "SESTDTC", "within": "USUBJID", "ordering": "SESEQ"} - result = DataframeType({"value": valid_df}).does_not_have_next_corresponding_record(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, pandas.NA, False, False, False, pandas.NA]))) - - invalid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [789, 789, 789, 789, 790, 790, 790, 790, ], - "SESEQ": [1, 2, 3, 4, 5, 6, 7, 8, ], - "SEENDTC": ["2006-06-03T10:32", "2006-06-10T09:47", "2006-06-17", "2006-06-17", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17", "2006-06-17"], - "SESTDTC": ["2006-06-01", "2010-08-03", "2008-08", "2006-06-17T10:20", "2006-06-01", "2006-06-03T10:14", "2006-06-10T10:32", "2006-06-17"], - } - ) - other_value: dict = {"target": "SEENDTC", "comparator": "SESTDTC", "within": "USUBJID", "ordering": "SESEQ"} - result = DataframeType({"value": invalid_df}).does_not_have_next_corresponding_record(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, pandas.NA, False, False, False, pandas.NA]))) - - - def test_additional_columns_empty(self): - """ - Unit test for additional_columns_empty operator. - """ - valid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, ], - "TSVAL": [None, None, "another value", None], # original column may be empty - "TSVAL1": ["value", "value", "value", None], # valid since TSVAL2 is also null in the same row - "TSVAL2": [None, "value 2", "value 2", None], - } - ) - result = DataframeType({"value": valid_df, }).additional_columns_empty({"target": "TSVAL", }) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, ]))) - - invalid_df = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, ], - "TSVAL": ["value", None, "another value", None], # original column may be empty - "TSVAL1": ["value", None, "value", "value"], # invalid column - "TSVAL2": ["value 2", "value 2", "value 2", None], - "TSVAL3": ["value 3", "value 3", None, "value 3"], - } - ) - result = DataframeType({"value": invalid_df, }).additional_columns_empty({"target": "TSVAL", }) - self.assertTrue(result.equals(pandas.Series([False, True, False, True, ]))) - - def test_additional_columns_not_empty(self): - """ - Unit test for additional_columns_not_empty operator. - """ - df_with_empty_rows = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, ], - "TSVAL": ["value", None, "another value", None], # original column may be empty - "TSVAL1": ["value", None, "value", "value"], - "TSVAL2": ["value 2", "value 2", "value 2", "value 2"], - } - ) - result = DataframeType({"value": df_with_empty_rows, }).additional_columns_not_empty({"target": "TSVAL", }) - self.assertTrue(result.equals(pandas.Series([True, False, True, True, ]))) - - df_without_empty_rows = pandas.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, ], - "TSVAL": ["value", None, "another value", None], # original column may be empty - "TSVAL1": ["value", "value", "value", "value"], - "TSVAL2": ["value 2", "value 2", "value 2", "value 2"], - } - ) - result = DataframeType({"value": df_without_empty_rows, }).additional_columns_not_empty({"target": "TSVAL", }) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, ]))) - - def test_references_valid_codelist(self): - df = pandas.DataFrame.from_dict( - { - "define_variable_name": ["TEST", "COOLVAR", "ANOTHERVAR" ], - "define_variable_controlled_terms": ["C123", "C456", "C789"], - "define_variable_invalid_terms": ["C123", "C456", "C786"] - } - ) - - column_codelist_map = { - "TEST": ["C123", "C456"], - "COOLVAR": ["C123", "C456"], - "ANOTHERVAR": ["C789"] - } - dft = DataframeType({ - "value": df, - "column_codelist_map": column_codelist_map - }) - - result = dft.references_correct_codelist({"target": "define_variable_name", "comparator": "define_variable_controlled_terms"}) - self.assertTrue(result.equals(pandas.Series([True, True, True ]))) - - bad_result = dft.references_correct_codelist({"target": "define_variable_name", "comparator": "define_variable_invalid_terms"}) - self.assertTrue(bad_result.equals(pandas.Series([True, True, False]))) - - - def test_does_not_reference_valid_codelist(self): - df = pandas.DataFrame.from_dict( - { - "define_variable_name": ["TEST", "COOLVAR", "ANOTHERVAR" ], - "define_variable_controlled_terms": ["C123", "C456", "C789"], - "define_variable_invalid_terms": ["C123", "C456", "C786"] - } - ) - - column_codelist_map = { - "TEST": ["C123", "C456"], - "--OLVAR": ["C123", "C456"], - "ANOTHERVAR": ["C789"] - } - dft = DataframeType({ - "value": df, - "column_codelist_map": column_codelist_map, - "column_prefix_map": { - "--": "CO" - } - }) - - result = dft.does_not_reference_correct_codelist({"target": "define_variable_name", "comparator": "define_variable_controlled_terms"}) - self.assertTrue(result.equals(pandas.Series([False, False, False ]))) - - bad_result = dft.does_not_reference_correct_codelist({"target": "define_variable_name", "comparator": "define_variable_invalid_terms"}) - self.assertTrue(bad_result.equals(pandas.Series([False, False, True]))) - - def test_uses_valid_codelist_terms(self): - df = pandas.DataFrame.from_dict( - { - "define_variable_name": ["TEST", "COOLVAR", "ANOTHERVAR" ], - "define_variable_controlled_terms": ["C123", "C456", "C789"], - "define_variable_allowed_terms": [ - ["A", "B"], - ["C", "D"], - ["E", "F"] - ], - "define_variable_invalid_allowed_terms": [ - ["A", "L"], - ["C", "Z"], - ["E", "F"] - ] - } - ) - - extensible_codelist_term_map = [{ - "C123": { - "extensible": False, - "allowed_terms": ["A", "B", "b", "C"], - }, - "C456": { - "extensible": True, - "allowed_terms": ["A", "B", "b", "C", "D"] - }, - "C789": { - "extensible": False, - "allowed_terms": ["E", "F", "b", "C"] - } - }] - - codelist_term_map = [{ - "C123": { - "extensible": False, - "allowed_terms": ["A", "B", "b", "C"], - }, - "C456": { - "extensible": False, - "allowed_terms": ["A", "B", "b", "C", "D"] - }, - "C789": { - "extensible": False, - "allowed_terms": ["E", "F", "b", "C"] - } - }] - dft = DataframeType({ - "value": df, - "codelist_term_maps": codelist_term_map - }) - - result = dft.uses_valid_codelist_terms({"target": "define_variable_controlled_terms", "comparator": "define_variable_allowed_terms"}) - self.assertTrue(result.equals(pandas.Series([True, True, True]))) - - bad_result = dft.uses_valid_codelist_terms({"target": "define_variable_controlled_terms", "comparator": "define_variable_invalid_allowed_terms"}) - self.assertTrue(bad_result.equals(pandas.Series([False, False, True]))) - - # Test extensible flag - dft = DataframeType({ - "value": df, - "codelist_term_maps": extensible_codelist_term_map - }) - - result = dft.uses_valid_codelist_terms({"target": "define_variable_controlled_terms", "comparator": "define_variable_invalid_allowed_terms"}) - self.assertTrue(result.equals(pandas.Series([False, True, True]))) - - def test_does_not_use_valid_terms(self): - df = pandas.DataFrame.from_dict( - { - "define_variable_name": ["TEST", "COOLVAR", "ANOTHERVAR" ], - "define_variable_controlled_terms": ["C123", "C456", "C789"], - "define_variable_allowed_terms": [ - ["A", "B"], - ["C", "D"], - ["E", "F"] - ], - "define_variable_invalid_allowed_terms": [ - ["A", "L"], - ["C", "Z"], - ["E", "F"] - ] - } - ) - - extensible_codelist_term_map = [{ - "C123": { - "extensible": False, - "allowed_terms": ["A", "B", "b", "C"], - }, - "C456": { - "extensible": True, - "allowed_terms": ["A", "B", "b", "C", "D"] - }, - "C789": { - "extensible": False, - "allowed_terms": ["E", "F", "b", "C"] - } - }] - - codelist_term_map = [{ - "C123": { - "extensible": False, - "allowed_terms": ["A", "B", "b", "C"], - }, - "C456": { - "extensible": False, - "allowed_terms": ["A", "B", "b", "C", "D"] - }, - "C789": { - "extensible": False, - "allowed_terms": ["E", "F", "b", "C"] - } - }] - dft = DataframeType({ - "value": df, - "codelist_term_maps": codelist_term_map - }) - - result = dft.does_not_use_valid_codelist_terms({"target": "define_variable_controlled_terms", "comparator": "define_variable_allowed_terms"}) - self.assertTrue(result.equals(pandas.Series([False, False, False]))) - - bad_result = dft.does_not_use_valid_codelist_terms({"target": "define_variable_controlled_terms", "comparator": "define_variable_invalid_allowed_terms"}) - self.assertTrue(bad_result.equals(pandas.Series([True, True, False]))) - - # Test extensible flag - dft = DataframeType({ - "value": df, - "codelist_term_maps": extensible_codelist_term_map - }) - - result = dft.does_not_use_valid_codelist_terms({"target": "define_variable_controlled_terms", "comparator": "define_variable_invalid_allowed_terms"}) - self.assertTrue(result.equals(pandas.Series([True, False, False]))) - - def test_has_different_values(self): - valid_df = pandas.DataFrame.from_dict( - { - "MHCAT": [1, 2, 3, 1, 1, ] - } - ) - result = DataframeType({"value": valid_df, }).has_different_values({"target": "MHCAT", }) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - invalid_df = pandas.DataFrame.from_dict( - { - "MHCAT": [1, 1, 1, 1, 1, ] - } - ) - result = DataframeType({"value": invalid_df, }).has_different_values({"target": "MHCAT", }) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - def test_has_same_values(self): - valid_df = pandas.DataFrame.from_dict( - { - "MHCAT": [1, 2, 3, 1, 1, ] - } - ) - result = DataframeType({"value": valid_df, }).has_same_values({"target": "MHCAT", }) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - invalid_df = pandas.DataFrame.from_dict( - { - "MHCAT": [1, 1, 1, 1, 1, ] - } - ) - result = DataframeType({"value": invalid_df, }).has_same_values({"target": "MHCAT", }) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - def test_is_ordered_by(self): - """ - Unit test for is_ordered_by operator. - The test creates 2 dataframes: one is valid, one is not - and executes the operator against the dataframes. - """ - valid_df = pd.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, 1, ], - "AESEQ": [1, 2, 3, 4, 5, ], - } - ) - result = DataframeType({"value": valid_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by({"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_dsc_df = pd.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, 1, ], - "AESEQ": [5, 4, 3, 2, 1, ], - } - ) - result = DataframeType({"value": valid_dsc_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by( - {"target": "--SEQ", "order": "dsc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, 1, ], - "AESEQ": [1, 2, 5, 3, 0, ], - } - ) - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by({"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, True, False, ]))) - - # validating for strings - valid_df = pd.DataFrame.from_dict( - { - "USUBJID": ['a', 'a', 'a', 'a', 'a', ], - "AESEQ": ['a', 'b', 'c', 'd', 'e', ], - } - ) - result = DataframeType({"value": valid_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_dsc_df = pd.DataFrame.from_dict( - { - "USUBJID": ['a', 'a', 'a', 'a', 'a', ], - "AESEQ": ['e', 'd', 'c', 'b', 'a', ], - - } - ) - result = DataframeType({"value": valid_dsc_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by( - {"target": "--SEQ", "order": "dsc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": ['a', 'a', 'a', 'a', 'a', ], - "AESEQ": ['b', 'c', 'e', 'd', 'a', ], - } - ) - - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, True, False, ]))) - - # validating for date - valid_df = pd.DataFrame.from_dict( - { - "USUBJID": ["2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", ], - "AESEQ": ["2020-02-23", "2020-02-24", "2020-02-25", "2020-02-26", "2020-02-27", ], - } - ) - - result = DataframeType({"value": valid_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_dsc_df = pd.DataFrame.from_dict( - { - "USUBJID": ["2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", ], - "AESEQ": ["2020-02-27", "2020-02-26", "2020-02-25", "2020-02-24", "2020-02-23", ], - } - ) - result = DataframeType({"value": valid_dsc_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by( - {"target": "--SEQ", "order": "dsc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": ["2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", ], - "AESEQ": ["2020-02-24", "2020-02-25", "2020-02-27", "2020-02-26", "2020-02-23", ], - } - ) - - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "AE"}}).is_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, True, False, ]))) - - def test_is_not_ordered_by(self): - """ - Unit test for is_not_ordered_by operator. - The test creates 2 dataframes: one is valid, one is not - and executes the operator against the dataframes. - """ - - valid_df = pd.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, 1, ], - "AESEQ": [1, 2, 3, 4, 6, ], - } - ) - result = DataframeType({"value": valid_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by({"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_dsc_df = pd.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, 1, ], - "AESEQ": [5, 4, 3, 2, 1, ], - } - ) - result = DataframeType({"value": valid_dsc_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by( - {"target": "--SEQ", "order": "dsc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": [1, 1, 1, 1, 1, ], - "AESEQ": [1, 2, 5, 3, 0, ], - } - ) - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by({"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, False, True, ]))) - - # Checking validity for strings - valid_df = pd.DataFrame.from_dict( - { - "USUBJID": ['a', 'a', 'a', 'a', 'a', ], - "AESEQ": ['a', 'b', 'c', 'd', 'e', ], - } - ) - result = DataframeType({"value": valid_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_dsc_df = pd.DataFrame.from_dict( - { - "USUBJID": ['a', 'a', 'a', 'a', 'a', ], - "AESEQ": ['e', 'd', 'c', 'b', 'a', ], - - } - ) - result = DataframeType({"value": valid_dsc_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by( - {"target": "--SEQ", "order": "dsc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": ['a', 'a', 'a', 'a', 'a', ], - "AESEQ": ['b', 'c', 'e', 'd', 'a', ], - } - ) - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, False, True, ]))) - - # Checking validating for date - valid_df = pd.DataFrame.from_dict( - { - "USUBJID": ["2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", ], - "AESEQ": ["2020-02-23", "2020-02-24", "2020-02-25", "2020-02-26", "2020-02-27", ], - } - ) - result = DataframeType({"value": valid_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_dsc_df = pd.DataFrame.from_dict( - { - "USUBJID": ["2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", ], - "AESEQ": ["2020-02-27", "2020-02-26", "2020-02-25", "2020-02-24", "2020-02-23", ], - } - ) - result = DataframeType({"value": valid_dsc_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by( - {"target": "--SEQ", "order": "dsc"}) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": ["2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", "2020-02-23", ], - "AESEQ": ["2020-02-24", "2020-02-25", "2020-02-27", "2020-02-26", "2020-02-23", ], - } - ) - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "AE"}}).is_not_ordered_by( - {"target": "--SEQ","order": "asc"}) - self.assertTrue(result.equals(pandas.Series([True, True, True, False, True, ]))) - - def test_suffix_equal_to(self): - """ - Unit test for suffix_equal_to operator. - """ - valid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["EC", "EC", "EC", ], - "$dataset_name": ["SUPPEC", "SUPPEC", "SUPPEC", ], - } - ) - # check equality between 2 dataframe columns - result = DataframeType({"value": valid_df, }).suffix_equal_to( - {"target": "$dataset_name", "comparator": "RDOMAIN", "suffix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, True, ]))) - - # check equality between a dataframe column and a string - result = DataframeType({"value": valid_df, }).suffix_equal_to( - {"target": "$dataset_name", "comparator": "EC", "suffix": 2, "value_is_literal": True, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, True, ]))) - - # check equality between 2 dataframe columns - invalid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["EC", "EC", "AE", ], - "$dataset_name": ["SUPPEC", "SUPPEC", "SUPPEC", ], - } - ) - result = DataframeType({"value": invalid_df, }).suffix_equal_to( - {"target": "$dataset_name", "comparator": "RDOMAIN", "suffix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, False, ]))) - - # check equality between a dataframe column and a string - invalid_df_1 = pd.DataFrame.from_dict( - { - "RDOMAIN": ["EC", "EC", "EC", ], - "$dataset_name": ["SUPPEC", "SUPPEC", "SUPPAE", ], - } - ) - result = DataframeType({"value": invalid_df_1, }).suffix_equal_to( - {"target": "$dataset_name", "comparator": "EC", "suffix": 2, "value_is_literal": True, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, False, ]))) - - def test_suffix_not_equal_to(self): - """ - Unit test for suffix_not_equal_to operator. - """ - valid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["EC", "EC", "EC", ], - "$dataset_name": ["SUPPEC", "SUPPEC", "SUPPEC", ], - } - ) - # check equality between 2 dataframe columns - result = DataframeType({"value": valid_df, }).suffix_not_equal_to( - {"target": "$dataset_name", "comparator": "RDOMAIN", "suffix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, False, ]))) - - # check equality between a dataframe column and a string - result = DataframeType({"value": valid_df, }).suffix_not_equal_to( - {"target": "$dataset_name", "comparator": "EC", "suffix": 2, "value_is_literal": True, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, False, ]))) - - # check equality between 2 dataframe columns - invalid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["EC", "EC", "AE", ], - "$dataset_name": ["SUPPEC", "SUPPEC", "SUPPEC", ], - } - ) - result = DataframeType({"value": invalid_df, }).suffix_not_equal_to( - {"target": "$dataset_name", "comparator": "RDOMAIN", "suffix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, True, ]))) - - # check equality between a dataframe column and a string - invalid_df_1 = pd.DataFrame.from_dict( - { - "RDOMAIN": ["EC", "EC", "EC", ], - "$dataset_name": ["SUPPEC", "SUPPEC", "SUPPAE", ], - } - ) - result = DataframeType({"value": invalid_df_1, }).suffix_not_equal_to( - {"target": "$dataset_name", "comparator": "EC", "suffix": 2, "value_is_literal": True, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, True, ]))) - - def test_prefix_equal_to(self): - """ - Unit test for prefix_equal_to operator. - """ - valid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["AE", "AE", "AE", ], - "IDVAR": ["AESEQ", "AESEQ", "AESEQ", ] - } - ) - # check equality between 2 dataframe columns - result = DataframeType({"value": valid_df, }).prefix_equal_to( - {"target": "IDVAR", "comparator": "RDOMAIN", "prefix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, True, ]))) - - # check equality between a dataframe column and a string - result = DataframeType({"value": valid_df, }).prefix_equal_to( - {"target": "IDVAR", "comparator": "AE", "prefix": 2, "value_is_literal": True, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, True, ]))) - - # check equality between 2 dataframe columns - invalid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["AE", "AE", "EC", ], - "IDVAR": ["AESEQ", "AESEQ", "AESEQ", ] - } - ) - result = DataframeType({"value": invalid_df, }).prefix_equal_to( - {"target": "IDVAR", "comparator": "RDOMAIN", "prefix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, False, ]))) - - # check equality between a dataframe column and a string - invalid_df_1 = pd.DataFrame.from_dict( - { - "RDOMAIN": ["AE", "AE", "EC", ], - "IDVAR": ["AESEQ", "AESEQ", "ECSEQ", ] - } - ) - result = DataframeType({"value": invalid_df_1, }).prefix_equal_to( - {"target": "IDVAR", "comparator": "AE", "prefix": 2, "value_is_literal": True, } - ) - self.assertTrue(result.equals(pandas.Series([True, True, False, ]))) - - def test_prefix_not_equal_to(self): - """ - Unit test for prefix_not_equal_to operator. - """ - valid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["AE", "AE", "AE", ], - "IDVAR": ["AESEQ", "AESEQ", "AESEQ", ] - } - ) - # check equality between 2 dataframe columns - result = DataframeType({"value": valid_df, }).prefix_not_equal_to( - {"target": "IDVAR", "comparator": "RDOMAIN", "prefix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, False, ]))) - - # check equality between a dataframe column and a string - result = DataframeType({"value": valid_df, }).prefix_not_equal_to( - {"target": "IDVAR", "comparator": "AE", "prefix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, False, ]))) - - # check equality between 2 dataframe columns - invalid_df = pd.DataFrame.from_dict( - { - "RDOMAIN": ["AE", "AE", "EC", ], - "IDVAR": ["AESEQ", "AESEQ", "AESEQ", ] - } - ) - result = DataframeType({"value": invalid_df, }).prefix_not_equal_to( - {"target": "IDVAR", "comparator": "RDOMAIN", "prefix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, True, ]))) - - # check equality between a dataframe column and a string - invalid_df_1 = pd.DataFrame.from_dict( - { - "RDOMAIN": ["AE", "AE", "EC", ], - "IDVAR": ["AESEQ", "AESEQ", "ECSEQ", ] - } - ) - result = DataframeType({"value": invalid_df_1, }).prefix_not_equal_to( - {"target": "IDVAR", "comparator": "AE", "prefix": 2, } - ) - self.assertTrue(result.equals(pandas.Series([False, False, True, ]))) - - def test_target_is_sorted_by(self): - """ - Unit test for target_is_sorted_by operator. - The test verifies if --SEQ is sorted based on set of user-defined columns - """ - valid_asc_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": valid_asc_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_desc_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [2, 1, 2, 3, 1], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_desc_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_asc_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": valid_asc_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_desc_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [2, 1, 2, 3, 1], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_desc_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 3, 1, 2], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by( - other_value) - self.assertTrue(result.equals(pandas.Series([True, True, False, False, True, ]))) - - valid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID":["CDISC001","CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - "STUDYID": ["CDISCPILOT1","CDISCPILOT1","CDISCPILOT1","CDISCPILOT1","CDISCPILOT1"], - "SEENDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"},{"name": "--ENDTC", "sort_order": "ASC","null_position": "last"}]} - result = DataframeType({"value": valid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [2, 1, 2, 3, 1], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - "STUDYID": ["CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1"], - "SEENDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID","comparator": [{"name": "--STDTC", "sort_order": "DESC", "null_position": "last"}, - {"name": "--ENDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by( other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - valid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - "STUDYID": ["CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1"], - "SEENDTC": ['2006-06-03', '2006-06-01', '2006-06-04', '2006-06-05', '2006-06-02'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}, - {"name": "--ENDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by( other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, True, True, ]))) - - invalid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 3, 1, 2], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - "STUDYID": ["CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1"], - "SEENDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID","comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"},{"name": "--ENDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": invalid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, False, False, True, ]))) - - valid_na_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [1, 2, 1, None, None], - "SESTDTC": ['2006-06-02', None, '2006-06-01', None, '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": valid_na_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, True, False, False, ]))) - - invalid_na_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [1 ,2 ,3, None, None], - "SESTDTC": ['2006-06-02', None, '2006-06-01', None, '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID","comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value":invalid_na_df, "column_prefix_map": {"--": "SE"}}).target_is_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([True, True, False, False, False, ]))) - - - def test_target_is_not_sorted_by(self): - """ - Unit test for target_is_not_sorted_by operator. - The test verifies if --SEQ is not sorted based on a set of user defined columns - """ - - valid_asc_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": valid_asc_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_desc_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [2, 1, 2, 3, 1], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID","comparator": [{"name": "--STDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_desc_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_asc_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - other_value: dict = {"target": "--SEQ", "within": "USUBJID","comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": valid_asc_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_desc_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [2, 1, 2, 3, 1], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_desc_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - invalid_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 3, 1, 2], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID","comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": invalid_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, True, True, False, ]))) - - valid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - "STUDYID": ["CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1"], - "SEENDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}, - {"name": "--ENDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": valid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [2, 1, 2, 3, 1], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - "STUDYID": ["CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1"], - "SEENDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "DESC", "null_position": "last"}, - {"name": "--ENDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False, ]))) - - valid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 1, 3, 2], - "SESTDTC": ['2006-06-02', '2006-06-04', '2006-06-01', '2006-06-05', '2006-06-03'], - "STUDYID": ["CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1"], - "SEENDTC": ['2006-06-03', '2006-06-01', '2006-06-04', '2006-06-05', '2006-06-02'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", - "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}, - {"name": "--ENDTC", "sort_order": "DESC", "null_position": "last"}]} - result = DataframeType({"value": valid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by( - other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False, False, False,]))) - - invalid_mul_df = pd.DataFrame.from_dict( - { - "USUBJID": ["CDISC001", "CDISC002", "CDISC002", "CDISC001", "CDISC001"], - "SESEQ": [1, 2, 3, 1, 2], - "SESTDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - "STUDYID": ["CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1", "CDISCPILOT1"], - "SEENDTC": ["2006-06-02", "2006-06-04", "2006-06-01", "2006-06-05", "2006-06-03"], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}, - {"name": "--ENDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": invalid_mul_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by( other_value) - self.assertTrue(result.equals(pandas.Series([False, False, True, True, False, ]))) - - valid_na_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [1, 2, 1, None, None], - "SESTDTC": ['2006-06-02', None, '2006-06-01', None, '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID", "comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": valid_na_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False, False, False,True, True, ]))) - - invalid_na_df = pd.DataFrame.from_dict( - { - "USUBJID": [123, 456, 456, 123, 123], - "SESEQ": [1, 2, 3, None, None], - "SESTDTC": ['2006-06-02', None, '2006-06-01', None, '2006-06-03'], - } - ) - - other_value: dict = {"target": "--SEQ", "within": "USUBJID","comparator": [{"name": "--STDTC", "sort_order": "ASC", "null_position": "last"}]} - result = DataframeType({"value": invalid_na_df, "column_prefix_map": {"--": "SE"}}).target_is_not_sorted_by(other_value) - self.assertTrue(result.equals(pandas.Series([False,False,True,True,True ]))) - -class GenericOperatorTests(TestCase): - def test_shares_no_elements_with(self): - self.assertTrue(GenericType([1, 2]). - shares_no_elements_with([4, 3])) - self.assertFalse(GenericType([1, 2]). - shares_no_elements_with([2, 3])) - self.assertFalse(GenericType([1, 2, "a"]). - shares_no_elements_with([4, "A"])) - - def test_contains(self): - self.assertTrue(GenericType([1, 2]).contains(2)) - self.assertFalse(GenericType([1, 2]).contains(3)) - self.assertTrue(GenericType([1, 2, "a"]).contains("a")) - - def test_does_not_contain(self): - self.assertTrue(GenericType([1, 2]).does_not_contain(3)) - self.assertFalse(GenericType([1, 2]).does_not_contain(2)) - self.assertFalse(GenericType([1, 2, "a"]).does_not_contain("A")) - - def test_boolean_is_true_and_is_false(self): - self.assertTrue(GenericType(True).is_true()) - self.assertFalse(GenericType(True).is_false()) - self.assertFalse(GenericType(False).is_true()) - self.assertTrue(GenericType(False).is_false()) - - - def test_numeric_equal_to(self): - self.assertTrue(GenericType(10).equal_to(10)) - self.assertTrue(GenericType(10).equal_to(10.0)) - self.assertTrue(GenericType(10).equal_to(10.000001)) - self.assertTrue(GenericType(10.000001).equal_to(10)) - self.assertTrue(GenericType(Decimal('10.0')).equal_to(10)) - self.assertTrue(GenericType(10).equal_to(Decimal('10.0'))) - self.assertFalse(GenericType(10).equal_to(10.00001)) - self.assertFalse(GenericType(10).equal_to(11)) - - def test_numeric_not_equal_to(self): - self.assertFalse(GenericType(10).not_equal_to(10)) - self.assertFalse(GenericType(10).not_equal_to(10.0)) - self.assertFalse(GenericType(10).not_equal_to(10.000001)) - self.assertFalse(GenericType(10.000001).not_equal_to(10)) - self.assertFalse(GenericType(Decimal('10.0')).not_equal_to(10)) - self.assertFalse(GenericType(10).not_equal_to(Decimal('10.0'))) - self.assertTrue(GenericType(10).not_equal_to(10.00001)) - self.assertTrue(GenericType(10).not_equal_to(11)) - - def test_numeric_greater_than(self): - self.assertTrue(GenericType(10).greater_than(1)) - self.assertFalse(GenericType(10).greater_than(11)) - self.assertTrue(GenericType(10.1).greater_than(10)) - self.assertFalse(GenericType(10.000001).greater_than(10)) - self.assertTrue(GenericType(10.000002).greater_than(10)) - - def test_numeric_greater_than_or_equal_to(self): - self.assertTrue(GenericType(10).greater_than_or_equal_to(1)) - self.assertFalse(GenericType(10).greater_than_or_equal_to(11)) - self.assertTrue(GenericType(10.1).greater_than_or_equal_to(10)) - self.assertTrue(GenericType(10.000001).greater_than_or_equal_to(10)) - self.assertTrue(GenericType(10.000002).greater_than_or_equal_to(10)) - self.assertTrue(GenericType(10).greater_than_or_equal_to(10)) - - def test_numeric_less_than(self): - self.assertTrue(GenericType(1).less_than(10)) - self.assertFalse(GenericType(11).less_than(10)) - self.assertTrue(GenericType(10).less_than(10.1)) - self.assertFalse(GenericType(10).less_than(10.000001)) - self.assertTrue(GenericType(10).less_than(10.000002)) - - def test_numeric_less_than_or_equal_to(self): - self.assertTrue(GenericType(1).less_than_or_equal_to(10)) - self.assertFalse(GenericType(11).less_than_or_equal_to(10)) - self.assertTrue(GenericType(10).less_than_or_equal_to(10.1)) - self.assertTrue(GenericType(10).less_than_or_equal_to(10.000001)) - self.assertTrue(GenericType(10).less_than_or_equal_to(10.000002)) - self.assertTrue(GenericType(10).less_than_or_equal_to(10)) - - def test_string_equal_to(self): - self.assertTrue(GenericType("foo").equal_to("foo")) - self.assertFalse(GenericType("foo").equal_to("Foo")) - - def test_string_not_equal_to(self): - self.assertTrue(GenericType("foo").not_equal_to("POKEMON")) - self.assertFalse(GenericType("foo").not_equal_to("foo")) - - def test_string_equal_to_case_insensitive(self): - self.assertTrue(GenericType("foo").equal_to_case_insensitive("FOo")) - self.assertTrue(GenericType("foo").equal_to_case_insensitive("foo")) - self.assertFalse(GenericType("foo").equal_to_case_insensitive("blah")) - - def test_string_starts_with(self): - self.assertTrue(GenericType("hello").starts_with("he")) - self.assertFalse(GenericType("hello").starts_with("hey")) - self.assertFalse(GenericType("hello").starts_with("He")) - - def test_string_ends_with(self): - self.assertTrue(GenericType("hello").ends_with("lo")) - self.assertFalse(GenericType("hello").ends_with("boom")) - self.assertFalse(GenericType("hello").ends_with("Lo")) - - def test_string_contains(self): - self.assertTrue(GenericType("hello").contains("ell")) - self.assertTrue(GenericType("hello").contains("he")) - self.assertTrue(GenericType("hello").contains("lo")) - self.assertFalse(GenericType("hello").contains("asdf")) - self.assertFalse(GenericType("hello").contains("ElL")) - - def test_string_matches_regex(self): - self.assertTrue(GenericType("hello").matches_regex(r"^h")) - self.assertFalse(GenericType("hello").matches_regex(r"^sh")) - - def test_non_empty(self): - self.assertTrue(GenericType("hello").non_empty()) - self.assertFalse(GenericType("").non_empty()) - self.assertFalse(GenericType(None).non_empty()) - - def test_is_contained_by(self): - self.assertTrue(GenericType("hello").is_contained_by(["hello", "world"])) - self.assertFalse(GenericType("earth").is_contained_by(["hello", "world"])) - - def test_is_not_contained_by(self): - self.assertTrue(GenericType("rat").is_not_contained_by(["moose", "chicken"])) - self.assertFalse(GenericType("chicken").is_not_contained_by(["moose", "chicken"])) diff --git a/tests/test_variables_class.py b/tests/test_variables_class.py deleted file mode 100644 index 139597f..0000000 --- a/tests/test_variables_class.py +++ /dev/null @@ -1,2 +0,0 @@ - - From 7f8f6dcec7902350a0165a0a9c87fedd5f6b6671 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Tue, 15 Jul 2025 17:56:56 -0400 Subject: [PATCH 4/4] more test removal --- tests/test_integration.py | 114 -------------------------------------- 1 file changed, 114 deletions(-) delete mode 100644 tests/test_integration.py diff --git a/tests/test_integration.py b/tests/test_integration.py deleted file mode 100644 index e5e4bc6..0000000 --- a/tests/test_integration.py +++ /dev/null @@ -1,114 +0,0 @@ -from business_rules.engine import check_condition -from business_rules import export_rule_data -from business_rules.actions import rule_action, BaseActions -from business_rules.variables import BaseVariables, string_rule_variable, numeric_rule_variable, boolean_rule_variable -from business_rules.fields import FIELD_TEXT, FIELD_NUMERIC, FIELD_SELECT - -from . import TestCase - -class SomeVariables(BaseVariables): - - @string_rule_variable() - def foo(self): - return "foo" - - @numeric_rule_variable(label="Diez") - def ten(self): - return 10 - - @boolean_rule_variable() - def true_bool(self): - return True - -class SomeActions(BaseActions): - - @rule_action(params={"foo": FIELD_NUMERIC}) - def some_action(self, foo): pass - - @rule_action(label="woohoo", params={"bar": FIELD_TEXT}) - def some_other_action(self, bar): pass - - @rule_action(params=[{'fieldType': FIELD_SELECT, - 'name': 'baz', - 'label': 'Baz', - 'options': [ - {'label': 'Chose Me', 'name': 'chose_me'}, - {'label': 'Or Me', 'name': 'or_me'} - ]}]) - def some_select_action(self, baz): pass - - -class IntegrationTests(TestCase): - """ Integration test, using the library like a user would. - """ - def test_true_boolean_variable(self): - condition = { - 'name': 'true_bool', - 'operator': 'is_true', - 'value': '' - } - res = check_condition(condition, SomeVariables()) - self.assertTrue(res) - - def test_false_boolean_variable(self): - condition = { - 'name': 'true_bool', - 'operator': 'is_false', - 'value': '' - } - res = check_condition(condition, SomeVariables()) - self.assertFalse(res) - - def test_check_true_condition_happy_path(self): - condition = {'name': 'foo', - 'operator': 'contains', - 'value': 'o'} - self.assertTrue(check_condition(condition, SomeVariables())) - - def test_check_false_condition_happy_path(self): - condition = {'name': 'foo', - 'operator': 'contains', - 'value': 'm'} - self.assertFalse(check_condition(condition, SomeVariables())) - - def test_check_incorrect_method_name(self): - condition = {'name': 'food', - 'operator': 'equal_to', - 'value': 'm'} - err_string = 'Variable food is not defined in class SomeVariables' - with self.assertRaisesRegexp(AssertionError, err_string): - check_condition(condition, SomeVariables()) - - def test_check_incorrect_operator_name(self): - condition = {'name': 'foo', - 'operator': 'equal_tooooze', - 'value': 'foo'} - with self.assertRaises(AssertionError): - check_condition(condition, SomeVariables()) - - - def test_export_rule_data(self): - """ Tests that export_rule_data has the three expected keys - in the right format. - """ - all_data = export_rule_data(SomeVariables(), SomeActions()) - self.assertEqual(all_data.get("actions"), - [{"name": "some_action", - "label": "Some Action", - "params": [{'fieldType': 'numeric', 'label': 'Foo', 'name': 'foo'}]}, - {"name": "some_other_action", - "label": "woohoo", - "params": [{'fieldType': 'text', 'label': 'Bar', 'name': 'bar'}]}, - {"name": "some_select_action", - "label": "Some Select Action", - "params":[{'fieldType': FIELD_SELECT, - 'name': 'baz', - 'label': 'Baz', - 'options': [ - {'label': 'Chose Me', 'name': 'chose_me'}, - {'label': 'Or Me', 'name': 'or_me'} - ]}] - } - ]) - - # Removing for now until all operators are stable