Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 15 additions & 13 deletions pointblank/metadata/_adam_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def _adsl_template() -> ADaMDatasetTemplate:
),
ADaMVariableSpec(
"DCTREAS",
"Reason for Discontinuation from Treatment",
"Reason for Discontinuation of Treatment",
"Char",
core="Perm",
max_length=200,
Expand Down Expand Up @@ -475,7 +475,7 @@ def _bds_template() -> ADaMDatasetTemplate:
),
ADaMVariableSpec(
"ANL01FL",
"Analysis Record Flag 01",
"Analysis Flag 01",
"Char",
core="Perm",
max_length=1,
Expand All @@ -490,9 +490,9 @@ def _bds_template() -> ADaMDatasetTemplate:
controlled_term="NY",
),
# ── Traceability ──
ADaMVariableSpec("SRCDOM", "Source Data Domain", "Char", core="Perm", max_length=8),
ADaMVariableSpec("SRCVAR", "Source Data Variable", "Char", core="Perm", max_length=40),
ADaMVariableSpec("SRCSEQ", "Source Data Sequence Number", "Num", core="Perm"),
ADaMVariableSpec("SRCDOM", "Source Data", "Char", core="Perm", max_length=8),
ADaMVariableSpec("SRCVAR", "Source Variable", "Char", core="Perm", max_length=40),
ADaMVariableSpec("SRCSEQ", "Source Sequence Number", "Num", core="Perm"),
# ── Criterion Variables ──
ADaMVariableSpec("CRIT1", "Analysis Criterion 1", "Char", core="Perm", max_length=200),
ADaMVariableSpec(
Expand Down Expand Up @@ -639,12 +639,14 @@ def _adae_template() -> ADaMDatasetTemplate:
ADaMVariableSpec("AENDTM", "Analysis End Datetime", "Num", core="Perm"),
ADaMVariableSpec("ASTDY", "Analysis Start Relative Day", "Num", core="Perm"),
ADaMVariableSpec("AENDY", "Analysis End Relative Day", "Num", core="Perm"),
ADaMVariableSpec("ADURN", "AE Duration (N)", "Num", core="Perm"),
ADaMVariableSpec("ADURU", "AE Duration Units", "Char", core="Perm", max_length=40),
ADaMVariableSpec("ADURN", "Analysis Duration (N)", "Num", core="Perm"),
ADaMVariableSpec(
"ADURU", "Analysis Duration Units", "Char", core="Perm", max_length=40
),
# ── Flags ──
ADaMVariableSpec(
"TRTEMFL",
"Treatment Emergent Flag",
"Treatment Emergent Analysis Flag",
"Char",
core="Cond",
max_length=1,
Expand Down Expand Up @@ -721,13 +723,13 @@ def _adtte_template() -> ADaMDatasetTemplate:
# ── Time-to-Event Variables ──
ADaMVariableSpec("AVAL", "Analysis Value", "Num", required=True, core="Req"),
ADaMVariableSpec(
"STARTDT", "Time-to-Event Origin Date", "Num", required=True, core="Req"
"STARTDT", "Time-to-Event Origin Date for Subject", "Num", required=True, core="Req"
),
ADaMVariableSpec("ADT", "Analysis Date", "Num", required=True, core="Req"),
ADaMVariableSpec("CNSR", "Censor", "Num", required=True, core="Req"),
ADaMVariableSpec(
"EVNTDESC",
"Event Description",
"Event or Censoring Description",
"Char",
core="Cond",
max_length=200,
Expand All @@ -742,9 +744,9 @@ def _adtte_template() -> ADaMDatasetTemplate:
condition="Required for traceability",
),
# ── Supporting Variables ──
ADaMVariableSpec("SRCDOM", "Source Data Domain", "Char", core="Perm", max_length=8),
ADaMVariableSpec("SRCVAR", "Source Data Variable", "Char", core="Perm", max_length=40),
ADaMVariableSpec("SRCSEQ", "Source Data Sequence Number", "Num", core="Perm"),
ADaMVariableSpec("SRCDOM", "Source Data", "Char", core="Perm", max_length=8),
ADaMVariableSpec("SRCVAR", "Source Variable", "Char", core="Perm", max_length=40),
ADaMVariableSpec("SRCSEQ", "Source Sequence Number", "Num", core="Perm"),
],
)

Expand Down
12 changes: 7 additions & 5 deletions pointblank/metadata/_sdtm_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,15 +617,15 @@ def _lb_template() -> SDTMDomainTemplate:
),
SDTMVariableSpec(
"LBORNRLO",
"Reference Range Lower Limit-Orig Unit",
"Reference Range Lower Limit in Orig Unit",
"Char",
"Qualifier",
max_length=40,
core="Exp",
),
SDTMVariableSpec(
"LBORNRHI",
"Reference Range Upper Limit-Orig Unit",
"Reference Range Upper Limit in Orig Unit",
"Char",
"Qualifier",
max_length=40,
Expand Down Expand Up @@ -1058,7 +1058,9 @@ def _ds_template() -> SDTMDomainTemplate:
max_length=64,
core="Exp",
),
SDTMVariableSpec("DSSTDY", "Study Day of Start of Event", "Num", "Timing", core="Perm"),
SDTMVariableSpec(
"DSSTDY", "Study Day of Start of Disposition Event", "Num", "Timing", core="Perm"
),
],
)

Expand Down Expand Up @@ -1154,15 +1156,15 @@ def _mh_template() -> SDTMDomainTemplate:
),
SDTMVariableSpec(
"MHSTDTC",
"Start Date/Time of Medical History",
"Start Date/Time of Medical History Event",
"Char",
"Timing",
max_length=64,
core="Perm",
),
SDTMVariableSpec(
"MHENDTC",
"End Date/Time of Medical History",
"End Date/Time of Medical History Event",
"Char",
"Timing",
max_length=64,
Expand Down
62 changes: 62 additions & 0 deletions tests/test_metadata_template_labels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
SDTM and ADaM templates must fit SAS transport (XPT v5) limits and use the IG wording.

XPT v5, the format required for FDA submissions, caps variable names at 8 characters and
variable and dataset labels at 40 characters.
"""

from __future__ import annotations

import pytest

from pointblank.metadata._adam_templates import get_adam_dataset, list_adam_datasets
from pointblank.metadata._sdtm_templates import get_sdtm_domain, list_sdtm_domains

TEMPLATES = [("SDTM", d, get_sdtm_domain(d)) for d in list_sdtm_domains()] + [
("ADaM", d, get_adam_dataset(d)) for d in list_adam_datasets()
]


@pytest.mark.parametrize(
"template", [t for _, _, t in TEMPLATES], ids=[f"{s}-{d}" for s, d, _ in TEMPLATES]
)
def test_template_fits_sas_transport_limits(template):
name = getattr(template, "domain", None) or template.name
assert len(name) <= 8
assert len(template.label) <= 40, template.label

too_long = [
f"{v.name}: {v.label!r} ({len(v.label)})" for v in template.variables if len(v.label) > 40
]
assert too_long == []
assert [v.name for v in template.variables if len(v.name) > 8] == []


@pytest.mark.parametrize(
"get, dataset, variable, label",
[
# SDTMIG 3.4
(get_sdtm_domain, "DS", "DSSTDY", "Study Day of Start of Disposition Event"),
(get_sdtm_domain, "MH", "MHSTDTC", "Start Date/Time of Medical History Event"),
(get_sdtm_domain, "MH", "MHENDTC", "End Date/Time of Medical History Event"),
(get_sdtm_domain, "LB", "LBORNRLO", "Reference Range Lower Limit in Orig Unit"),
(get_sdtm_domain, "LB", "LBORNRHI", "Reference Range Upper Limit in Orig Unit"),
# ADaMIG 1.3
(get_adam_dataset, "ADSL", "DCTREAS", "Reason for Discontinuation of Treatment"),
(get_adam_dataset, "BDS", "ANL01FL", "Analysis Flag 01"),
(get_adam_dataset, "BDS", "SRCDOM", "Source Data"),
(get_adam_dataset, "BDS", "SRCVAR", "Source Variable"),
(get_adam_dataset, "BDS", "SRCSEQ", "Source Sequence Number"),
# ADaM OCCDS
(get_adam_dataset, "ADAE", "ADURN", "Analysis Duration (N)"),
(get_adam_dataset, "ADAE", "ADURU", "Analysis Duration Units"),
(get_adam_dataset, "ADAE", "TRTEMFL", "Treatment Emergent Analysis Flag"),
# ADaM BDS for time-to-event
(get_adam_dataset, "ADTTE", "STARTDT", "Time-to-Event Origin Date for Subject"),
(get_adam_dataset, "ADTTE", "EVNTDESC", "Event or Censoring Description"),
(get_adam_dataset, "ADTTE", "SRCDOM", "Source Data"),
],
)
def test_template_labels_use_ig_wording(get, dataset, variable, label):
spec = next(v for v in get(dataset).variables if v.name == variable)
assert spec.label == label
Loading