Skip to content

Commit fca5542

Browse files
authored
Merge pull request #56 from cdisc-org/sdtm-define-xml
Update define generator
2 parents e3f1fc2 + 08b9f5e commit fca5542

2 files changed

Lines changed: 49 additions & 32 deletions

File tree

src/generators/define/itemGroups.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ def _generate_dataset(self, dataset, define_objects, lang, acrf):
5252
vars.create_define_objects(items_list, define_objects, lang, acrf, item_group=itg)
5353
# ItemDefs
5454
itd = items.Items()
55-
itd.create_define_objects(dataset["items"], define_objects, lang, acrf)
55+
itd.create_define_objects(dataset["items"], define_objects, lang, acrf, slice=dataset["slices"] if dataset.get("slices") else None)
5656

5757
# TODO review this assumption that we have 1 class per dataset
5858
# assumption: 1 class per dataset - many need to expand this for ADaM
59-
if dataset.get("class"):
60-
ds_class = dataset["class"].upper().replace("-", " ")
59+
if dataset.get("observationClass", {}).get("name", ""):
60+
ds_class = dataset.get("observationClass", {}).get("name", "").upper().replace("-", " ")
6161
itg.Class = DEFINE.Class(Name=ds_class)
6262

6363
def _create_itemgroupdef_object(self, obj):
@@ -69,17 +69,18 @@ def _create_itemgroupdef_object(self, obj):
6969
attr["Structure"] = obj.get("structure", "NA")
7070
if obj.get("sasDatasetName"):
7171
attr["SASDatasetName"] = obj["sasDatasetName"]
72-
if obj.get("isReferenceData"):
73-
attr["IsReferenceData"] = obj["isReferenceData"]
74-
else:
75-
attr["IsReferenceData"] = self._generate_is_reference(attr)
76-
if obj.get("repeating"):
77-
if obj["repeating"]:
78-
attr["Repeating"] = "Yes"
79-
else:
80-
attr["Repeating"] = "No"
81-
else:
82-
attr["Repeating"] = self._generate_repeating_value(attr)
72+
if "isReferenceData" in obj:
73+
attr["IsReferenceData"] = "Yes" if obj["isReferenceData"] else "No"
74+
# else:
75+
# attr["IsReferenceData"] = self._generate_is_reference(attr)
76+
# if obj.get("repeating"):
77+
# if obj["repeating"]:
78+
# attr["Repeating"] = "Yes"
79+
# else:
80+
# attr["Repeating"] = "No"
81+
# else:
82+
# attr["Repeating"] = self._generate_repeating_value(attr)
83+
attr["Repeating"] = self._generate_repeating_value(attr)
8384
# TODO how to tell if we're processing SDTM or ADaM define?
8485
if obj.get("purpose"):
8586
attr["Purpose"] = obj["purpose"]
@@ -90,8 +91,8 @@ def _create_itemgroupdef_object(self, obj):
9091
attr["CommentOID"] = obj["comment"]
9192
if obj.get("isNonStandard"):
9293
attr["IsNonStandard"] = obj["isNonStandard"]
93-
if obj.get("wasDerivedFrom"):
94-
attr["StandardOID"] = obj["wasDerivedFrom"]
94+
if obj.get("standard"):
95+
attr["StandardOID"] = obj["standard"]
9596
if obj.get("hasNoData"):
9697
attr["HasNoData"] = obj["hasNoData"]
9798
igd = DEFINE.ItemGroupDef(**attr)
@@ -101,16 +102,16 @@ def _create_itemgroupdef_object(self, obj):
101102
igd.Description.TranslatedText.append(tt)
102103
return igd
103104

104-
def _generate_is_reference(self, attributes: dict[str, str]) -> str:
105-
"""
106-
Determine if the dataset is a reference dataset (trial design domains).
105+
# def _generate_is_reference(self, attributes: dict[str, str]) -> str:
106+
# """
107+
# Determine if the dataset is a reference dataset (trial design domains).
107108

108-
:param attributes: ItemGroupDef attributes dictionary
109-
:return: "Yes" if domain is a reference domain, "No" otherwise
110-
"""
111-
if attributes["Domain"] in TRIAL_DESIGN_DOMAINS:
112-
return "Yes"
113-
return "No"
109+
# :param attributes: ItemGroupDef attributes dictionary
110+
# :return: "Yes" if domain is a reference domain, "No" otherwise
111+
# """
112+
# if attributes["Domain"] in TRIAL_DESIGN_DOMAINS:
113+
# return "Yes"
114+
# return "No"
114115

115116
def _generate_repeating_value(self, attributes: dict[str, str]) -> str:
116117
"""
@@ -119,7 +120,7 @@ def _generate_repeating_value(self, attributes: dict[str, str]) -> str:
119120
:param attributes: ItemGroupDef attributes dictionary
120121
:return: "Yes" if dataset has repeating records, "No" otherwise
121122
"""
122-
if attributes["IsReferenceData"] == "Yes":
123+
if attributes.get("IsReferenceData") == "Yes":
123124
return "No"
124125
if attributes["Domain"] in NON_REPEATING_DOMAINS:
125126
# TODO check for presence of -PARMCD for DI/OI domains

src/generators/define/items.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ def create_define_objects(
1818
template: list[dict[str, Any]],
1919
define_objects: dict[str, list[Any]],
2020
lang: str,
21-
acrf: str
21+
acrf: str,
22+
slice: list[dict[str, Any]] | None = None
2223
) -> None:
2324
"""
2425
Create ItemDef objects from the DDS template.
@@ -27,15 +28,17 @@ def create_define_objects(
2728
:param define_objects: dictionary of odmlib objects updated by this method
2829
:param lang: xml:lang setting for TranslatedText
2930
:param acrf: annotated case report form leaf ID
31+
:param slice: list of slice definitions from the DDS JSON (if applicable)
3032
"""
3133
self.lang = lang
3234
self.acrf = acrf
35+
self.slice = slice
3336
for variable in template:
3437
it_oid = self.require_key(variable, "OID", "ItemDef")
35-
item = self._create_itemdef_object(variable, it_oid)
38+
item = self._create_itemdef_object(variable, it_oid, slice)
3639
define_objects["ItemDef"].append(item)
3740

38-
def _create_itemdef_object(self, obj, oid):
41+
def _create_itemdef_object(self, obj, oid, slice):
3942
name = self.require_key(obj, "name", f"ItemDef {oid}")
4043
data_type = self.require_key(obj, "dataType", f"ItemDef {oid}")
4144
attr = {"OID": oid, "Name": name, "DataType": data_type, "SASFieldName": name}
@@ -45,13 +48,20 @@ def _create_itemdef_object(self, obj, oid):
4548
tt = DEFINE.TranslatedText(_content=obj["description"], lang=self.lang)
4649
item.Description = DEFINE.Description()
4750
item.Description.TranslatedText.append(tt)
48-
self._add_optional_itemdef_elements(item, obj, oid)
51+
self._add_optional_itemdef_elements(item, obj, oid, slice)
4952
return item
5053

51-
def _add_optional_itemdef_elements(self, item, obj, it_oid):
54+
def _add_optional_itemdef_elements(self, item, obj, it_oid, slice):
5255
"""
5356
use the values from the Variables section in the define-template to add the optional ELEMENTS to the ItemDef
5457
"""
58+
for s in slice or []:
59+
if s.get("type") == "ValueList":
60+
if s.get("wasDerivedFrom") == it_oid:
61+
vl_oid = s["OID"]
62+
vl_ref = DEFINE.ValueListRef(ValueListOID=vl_oid)
63+
item.ValueListRef = vl_ref
64+
5565
# TODO do not find codeList in define.json example for items
5666
if obj.get("codeList"):
5767
cl_oid = self.generate_oid(["CL", obj["codeList"].split(".")[1]])
@@ -65,7 +75,13 @@ def _add_optional_itemdef_elements(self, item, obj, it_oid):
6575
attr["Type"] = obj["origin"]["type"]
6676
if obj.get("origin").get("source"):
6777
attr["Source"] = obj["origin"]["source"]
68-
item.Origin.append(DEFINE.Origin(**attr))
78+
# item.Origin.append(DEFINE.Origin(**attr))
79+
# Bypass odmlib descriptor validation to allow __PLACEHOLDER__ values
80+
origin = object.__new__(DEFINE.Origin)
81+
for key, value in attr.items():
82+
origin.__dict__[key] = value
83+
item.Origin.append(origin)
84+
6985
if obj.get("predecessor"):
7086
item.Origin[0].Description = DEFINE.Description()
7187
item.Origin[0].Description.TranslatedText.append(DEFINE.TranslatedText(_content=obj["Predecessor"]))

0 commit comments

Comments
 (0)