Skip to content
Closed
7 changes: 7 additions & 0 deletions cdisc_rules_engine/models/library_metadata_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,10 @@ def build_ct_terms(self, ct_package_type: str, versions: str | Iterable[str]):
ct_terms["term_value"].append(term["submissionValue"])
ct_terms["term_pref_term"].append(term.get("preferredTerm"))
return ct_terms

def is_domain_custom(self, domain: str) -> bool:
standard_data = self._standard_metadata or {}
domains = standard_data.get("domains", set())
if not isinstance(domains, (set, list, tuple)):
domains = set()
return domain not in domains
3 changes: 1 addition & 2 deletions cdisc_rules_engine/operations/domain_is_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ def _execute_operation(self):
given domain is in standard domains.
If no -> the domain is custom.
"""
standard_data: dict = self.library_metadata.standard_metadata
return self.params.domain not in standard_data.get("domains", {})
return self.library_metadata.is_domain_custom(self.params.domain)
11 changes: 8 additions & 3 deletions cdisc_rules_engine/services/cdisc_library_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,7 @@ def get_standard_details(
domains: Set[str] = self._extract_domain_names_from_tabulation_standard(
standard_data
)
if domains:
standard_data["domains"] = domains
standard_data["domains"] = domains
return standard_data

def get_model_details(self, standard_details: dict) -> Optional[dict]:
Expand Down Expand Up @@ -679,5 +678,11 @@ def _extract_domain_names_from_tabulation_standard(
domain_names: Set[str] = set()
for cls in standard_data.get("classes", []):
for dataset in cls.get("datasets", []):
domain_names.add(dataset.get("name"))
domain_name = dataset.get("name")
if domain_name:
domain_names.add(domain_name)
for dataset in standard_data.get("datasets", []):
domain_name = dataset.get("name")
if domain_name:
domain_names.add(domain_name)
return domain_names
55 changes: 41 additions & 14 deletions cdisc_rules_engine/utilities/rule_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,44 @@ def rule_applies_to_class(
is_excluded = True
return is_included and not is_excluded

def _is_custom_domain(self, domain: str) -> bool:
if self.library_metadata is None:
return False
return self.library_metadata.is_domain_custom(domain)

def _get_allowed_domains_for_use_cases(
self, use_cases: List[str], substandard: str
) -> set:
allowed_domains = set()
for use_case in use_cases:
if use_case in USE_CASE_DOMAINS[substandard]:
allowed_domains.update(USE_CASE_DOMAINS[substandard][use_case])
return allowed_domains

def _get_domain_to_check(self, dataset_metadata: SDTMDatasetMetadata) -> str:
if dataset_metadata.is_supp and dataset_metadata.rdomain:
return dataset_metadata.rdomain
return dataset_metadata.domain

def _check_adam_domain(
self, domain: str, substandard: str, use_cases: List[str]
) -> bool:
if substandard == "ADAM" and domain.startswith("AD"):
return "ANALYSIS" in use_cases
return False

def _check_domain_in_use_case(
self, domain: str, use_cases: List[str], substandard: str
) -> bool:
allowed_domains = self._get_allowed_domains_for_use_cases(
use_cases, substandard
)
if domain in allowed_domains:
return True
if self._is_custom_domain(domain):
return True
return False

def rule_applies_to_use_case(
self,
dataset_metadata: SDTMDatasetMetadata,
Expand All @@ -285,21 +323,10 @@ def rule_applies_to_use_case(
if substandard not in USE_CASE_DOMAINS:
return False

domain_to_check = dataset_metadata.domain
if dataset_metadata.is_supp and dataset_metadata.rdomain:
domain_to_check = dataset_metadata.rdomain

# Handle ADaM datasets with AD prefix
if substandard == "ADAM" and domain_to_check.startswith("AD"):
return "ANALYSIS" in use_cases

allowed_domains = set()
for use_case in use_cases:
if use_case in USE_CASE_DOMAINS[substandard]:
allowed_domains.update(USE_CASE_DOMAINS[substandard][use_case])
if domain_to_check in allowed_domains:
domain_to_check = self._get_domain_to_check(dataset_metadata)
if self._check_adam_domain(domain_to_check, substandard, use_cases):
return True
return False
return self._check_domain_in_use_case(domain_to_check, use_cases, substandard)

@classmethod
def rule_applies_to_entity(
Expand Down
111 changes: 108 additions & 3 deletions tests/unit/test_operations/test_domain_is_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,106 @@
"3-4",
True,
),
(
DaskDataset.from_dict(
{
"STUDYID": [
"TEST_STUDY",
"TEST_STUDY",
"TEST_STUDY",
],
"BCTERM": [
"test",
"test",
"test",
],
}
),
"BC",
"sdtmig",
"3-4",
True,
),
(
PandasDataset.from_dict(
{
"STUDYID": [
"TEST_STUDY",
"TEST_STUDY",
"TEST_STUDY",
],
"AETERM": [
"test",
"test",
"test",
],
}
),
"AE",
"tig",
"1-0",
False,
),
(
DaskDataset.from_dict(
{
"STUDYID": [
"TEST_STUDY",
"TEST_STUDY",
"TEST_STUDY",
],
"AETERM": [
"test",
"test",
"test",
],
}
),
"AE",
"tig",
"1-0",
False,
),
(
PandasDataset.from_dict(
{
"STUDYID": [
"TEST_STUDY",
"TEST_STUDY",
"TEST_STUDY",
],
"XYTERM": [
"test",
"test",
"test",
],
}
),
"XY",
"tig",
"1-0",
True,
),
(
DaskDataset.from_dict(
{
"STUDYID": [
"TEST_STUDY",
"TEST_STUDY",
"TEST_STUDY",
],
"XYTERM": [
"test",
"test",
"test",
],
}
),
"XY",
"tig",
"1-0",
True,
),
],
)
def test_domain_is_custom(
Expand All @@ -85,9 +185,14 @@ def test_domain_is_custom(
standard_version: str,
expected: bool,
):
standard_metadata = {
"domains": {"AE"},
}
if standard == "tig":
standard_metadata = {
"domains": {"AE", "DM", "CM", "LB", "VS", "EX", "DS", "MH"},
}
else:
standard_metadata = {
"domains": {"AE"},
}
operation_params.dataframe = dataframe
operation_params.domain = domain
operation_params.standard = standard
Expand Down
Loading