Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c1fb1c6
initial commit tig use case
SFJohnson24 Jan 22, 2026
eef8a1e
validation arg
SFJohnson24 Jan 22, 2026
42a83e9
use case test
SFJohnson24 Jan 22, 2026
72e7165
last test failure
SFJohnson24 Jan 22, 2026
5fdc1a0
readme
SFJohnson24 Jan 22, 2026
19f0707
report tests, update
SFJohnson24 Jan 23, 2026
e95273e
use case ruletester
SFJohnson24 Jan 23, 2026
fffcd8c
fix parsing issue
SFJohnson24 Jan 23, 2026
c6e7d70
update
SFJohnson24 Jan 23, 2026
8d898dd
Auto-updated branch with latest changes from main
SFJohnson24 Jan 26, 2026
f9f0e6b
Auto-updated branch with latest changes from main
SFJohnson24 Jan 26, 2026
f6afe96
Auto-updated branch with latest changes from main
SFJohnson24 Jan 27, 2026
b6e5621
Auto-updated branch with latest changes from main
SFJohnson24 Jan 27, 2026
ba241ba
Auto-updated branch with latest changes from main
SFJohnson24 Jan 28, 2026
b68a851
Auto-updated branch with latest changes from main
SFJohnson24 Jan 28, 2026
6bfe3f1
Auto-updated branch with latest changes from main
SFJohnson24 Jan 30, 2026
ab04890
Auto-updated branch with latest changes from main
SFJohnson24 Jan 30, 2026
ed0c5dc
Auto-updated branch with latest changes from main
SFJohnson24 Jan 30, 2026
e28ee24
Auto-updated branch with latest changes from main
SFJohnson24 Jan 30, 2026
4e831ae
Auto-updated branch with latest changes from main
SFJohnson24 Feb 1, 2026
4fd72d1
Auto-updated branch with latest changes from main
SFJohnson24 Feb 2, 2026
78693db
Merge branch 'main' into tig_custom
SFJohnson24 Feb 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ This will show the list of validation options.
-v, --version TEXT Standard version to validate against
[required]
-ss, --substandard TEXT Substandard to validate against
"SDTM", "SEND", "ADaM", or "CDASH"
[required for TIG]
-uc, --use-case TEXT Use Case for TIG Validation
"INDH", "PROD", "NONCLIN", or "ANALYSIS"
[required for TIG]
-ct, --controlled-terminology-package TEXT
Controlled terminology package to validate
Expand Down
2 changes: 2 additions & 0 deletions TestRule/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: #
standard = standards_data.get("product")
standard_version = standards_data.get("version")
standard_substandard = standards_data.get("substandard")
use_case = standards_data.get("use_case")
standard, standard_version = normalize_adam_input(standard, standard_version)
codelists = json_data.get("codelists", [])
cache = InMemoryCacheService()
Expand Down Expand Up @@ -117,6 +118,7 @@ def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: #
standard,
standard_version,
standard_substandard,
use_case,
codelists,
)
result = convert_numpy_types(result)
Expand Down
108 changes: 0 additions & 108 deletions cdisc_rules_engine/constants/use_cases.py

This file was deleted.

1 change: 1 addition & 0 deletions cdisc_rules_engine/models/validation_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"standard",
"version",
"substandard",
"use_case",
"controlled_terminology_package",
"output",
"output_format",
Expand Down
2 changes: 2 additions & 0 deletions cdisc_rules_engine/rules_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def __init__(
self.standard = kwargs.get("standard")
self.standard_version = (kwargs.get("standard_version") or "").replace(".", "-")
self.standard_substandard = kwargs.get("standard_substandard") or None
self.use_case = kwargs.get("use_case") or None
self.library_metadata = kwargs.get("library_metadata")
self.max_dataset_size = kwargs.get("max_dataset_size")
self.dataset_paths = kwargs.get("dataset_paths")
Expand Down Expand Up @@ -220,6 +221,7 @@ def validate_single_dataset(
datasets,
self.standard,
self.standard_substandard,
self.use_case,
)
if is_suitable:
result: List[Union[dict, str]] = self.validate_rule(
Expand Down
26 changes: 16 additions & 10 deletions cdisc_rules_engine/services/reporting/sdtm_report_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,22 @@ def __init__(
substandard = (
self._args.substandard if hasattr(self._args, "substandard") else None
)
use_case = self._args.use_case if hasattr(self._args, "use_case") else None
self.data_sheets = {
"Conformance Details": self.get_conformance_details_data(
define_version,
controlled_terminology,
dictionary_versions,
substandard=substandard,
use_case=use_case,
),
"Dataset Details": self.get_dataset_details_data(),
"Issue Summary": self.get_summary_data(),
"Issue Details": self.get_detailed_data(),
"Rules Report": self.get_rules_report_data(),
}

def get_conformance_details_data(
def get_conformance_details_data( # noqa
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please mention the reason for skipping the lint check here now?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignoring complexity check to keep the conformance detail data as one function--it is not complex, it just needs to fill in each field of the conformance details

self,
define_version,
cdiscCt,
Expand Down Expand Up @@ -132,11 +134,15 @@ def get_conformance_details_data(
conformance_details.append(
ReportMetadataItem("Version", 11, f"V{self._version}")
)
if "use_case" in kwargs and kwargs["use_case"] is not None:
conformance_details.append(
ReportMetadataItem("TIG Use Case", 12, kwargs["use_case"])
)
if cdiscCt:
conformance_details.append(
ReportMetadataItem(
"CT Version",
12,
13,
(
", ".join(cdiscCt)
if isinstance(cdiscCt, (list, tuple, set))
Expand All @@ -145,41 +151,41 @@ def get_conformance_details_data(
)
)
else:
conformance_details.append(ReportMetadataItem("CT Version", 12, ""))
conformance_details.append(ReportMetadataItem("CT Version", 13, ""))
conformance_details.append(
ReportMetadataItem("Define-XML Version", 13, define_version)
ReportMetadataItem("Define-XML Version", 14, define_version)
)

# Populate external dictionary versions
unii_version = dictionary_versions.get(DictionaryTypes.UNII.value)
if unii_version is not None:
conformance_details.append(
ReportMetadataItem("UNII Version", 16, unii_version)
ReportMetadataItem("UNII Version", 15, unii_version)
)
medrt_version = dictionary_versions.get(DictionaryTypes.MEDRT.value)
if medrt_version is not None:
conformance_details.append(
ReportMetadataItem("Med-RT Version", 17, medrt_version)
ReportMetadataItem("Med-RT Version", 16, medrt_version)
)
meddra_version = dictionary_versions.get(DictionaryTypes.MEDDRA.value)
if meddra_version is not None:
conformance_details.append(
ReportMetadataItem("MedDRA Version", 18, meddra_version)
ReportMetadataItem("MedDRA Version", 17, meddra_version)
)
whodrug_version = dictionary_versions.get(DictionaryTypes.WHODRUG.value)
if whodrug_version is not None:
conformance_details.append(
ReportMetadataItem("WHODRUG Version", 19, whodrug_version)
ReportMetadataItem("WHODRUG Version", 18, whodrug_version)
)
snomed_version = dictionary_versions.get(DictionaryTypes.SNOMED.value)
if snomed_version is not None:
conformance_details.append(
ReportMetadataItem("SNOMED Version", 20, snomed_version)
ReportMetadataItem("SNOMED Version", 19, snomed_version)
)
loinc_version = dictionary_versions.get(DictionaryTypes.LOINC.value)
if loinc_version is not None:
conformance_details.append(
ReportMetadataItem("LOINC Version", 21, loinc_version)
ReportMetadataItem("LOINC Version", 20, loinc_version)
)
return conformance_details

Expand Down
29 changes: 8 additions & 21 deletions cdisc_rules_engine/utilities/rule_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
SUPPLEMENTARY_DOMAINS,
)
from cdisc_rules_engine.constants.rule_constants import ALL_KEYWORD
from cdisc_rules_engine.constants.use_cases import USE_CASE_DOMAINS
from cdisc_rules_engine.interfaces import ConditionInterface
from cdisc_rules_engine.models.operation_params import OperationParams
from cdisc_rules_engine.models.rule_conditions import AllowedConditionsKeys
Expand Down Expand Up @@ -274,32 +273,15 @@ def rule_applies_to_use_case(
rule: dict,
standard: str,
standard_substandard: str,
use_case: str,
) -> bool:
if standard.lower() != "tig":
return True
use_cases = rule.get("use_case") or []
if not use_cases:
return True
use_cases = [uc.strip() for uc in use_cases.split(",")]
substandard = standard_substandard.upper()
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:
return True
return False
return use_case in use_cases

@classmethod
def rule_applies_to_entity(
Expand Down Expand Up @@ -684,6 +666,7 @@ def is_suitable_for_validation(
datasets: Iterable[SDTMDatasetMetadata],
standard,
standard_substandard: str,
use_case: str,
) -> Tuple[bool, str]:
"""Check if rule is suitable and return reason if not"""
rule_id = rule.get("core_id", "unknown")
Expand All @@ -698,7 +681,11 @@ def is_suitable_for_validation(
):
return self.log_suitable_for_validation(rule_id, dataset_name)
if not self.rule_applies_to_use_case(
dataset_metadata, rule, standard, standard_substandard
dataset_metadata,
rule,
standard,
standard_substandard,
use_case,
):
reason = (
f"Rule skipped - doesn't apply to use case for "
Expand Down
2 changes: 1 addition & 1 deletion cdisc_rules_engine/utilities/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def get_standard_details_cache_key(
if not standard_substandard:
return f"standards/{standard_type}/{standard_version}"
else:
return f"standards/{standard_type}/{standard_version}/{standard_substandard}"
return f"standards/{standard_type}/{standard_version}/{standard_substandard.lower()}"


def normalize_adam_input(standard: str, version: str) -> tuple:
Expand Down
25 changes: 23 additions & 2 deletions core.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,19 @@ def _validate_no_arguments(logger) -> None:
"-ss",
"--substandard",
default=None,
help="CDISC Substandard to validate against",
type=click.Choice(["sdtm", "send", "adam", "cdash"], case_sensitive=False),
help="CDISC Substandard to validate against. Any of SDTM, SEND, ADaM, CDASH",
)
@click.option(
"-uc",
"--use-case",
required=False,
default=None,
type=click.Choice(["INDH", "PROD", "NONCLIN", "ANALYSIS"], case_sensitive=True),
help=(
"CDISC TIG Use Case for scoping a TIG Validation."
"Any of INDH, PROD, NONCLIN, or ANALYSIS."
),
)
@click.option(
"-ct",
Expand Down Expand Up @@ -368,7 +380,7 @@ def _validate_no_arguments(logger) -> None:
),
)
@click.pass_context
def validate(
def validate( # noqa
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above--I wanted to keep validate as a single functional unit

ctx,
cache: str,
pool_size: int,
Expand All @@ -380,6 +392,7 @@ def validate(
standard: str,
version: str,
substandard: str,
use_case: str,
controlled_terminology_package: tuple[str],
output: str,
output_format: tuple[str],
Expand Down Expand Up @@ -431,6 +444,12 @@ def validate(

cache_path: str = os.path.join(os.path.dirname(__file__), cache)

if standard.lower() == "tig":
if not substandard or not use_case:
logger.error(
"Standard 'tig' requires both --substandard and --use-case to be specified."
)
ctx.exit(2)
# Construct ExternalDictionariesContainer:
external_dictionaries = ExternalDictionariesContainer(
{
Expand Down Expand Up @@ -474,6 +493,7 @@ def validate(
standard,
version,
substandard,
use_case,
set(controlled_terminology_package), # avoiding duplicates
output,
set(output_format), # avoiding duplicates
Expand Down Expand Up @@ -840,6 +860,7 @@ def test_validate(filetype):
standard,
version,
None,
None,
set(),
output,
output_format,
Expand Down
Binary file modified resources/templates/report-template.xlsx
Binary file not shown.
Loading
Loading