From 87f7a6ac6263ee05ef5a1546b5ec3ccb67b7aa0f Mon Sep 17 00:00:00 2001 From: yibeichan Date: Thu, 25 Jan 2024 11:25:44 -0500 Subject: [PATCH 01/27] add print for testing --- reproschema/redcap2reproschema.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index f267a2f..c6b7dfd 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -371,7 +371,9 @@ def process_csv( with open(csv_file, mode="r", encoding="utf-8") as csvfile: reader = csv.DictReader(csvfile) for row in reader: + print(f"process_csv: {row}") row = clean_header(row) + print(f"process_csv: {row} - after") form_name = row["Form Name"] if form_name not in datas: datas[form_name] = [] From 31627829ffd6c92a7897e82bb6efc243ef1b1b94 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Thu, 25 Jan 2024 11:30:34 -0500 Subject: [PATCH 02/27] update clear_header --- reproschema/redcap2reproschema.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index c6b7dfd..6f9cea4 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -10,7 +10,12 @@ def clean_header(header): - return {k.lstrip("\ufeff"): v for k, v in header.items()} + cleaned_header = {} + for k, v in header.items(): + # Strip BOM, whitespace, and enclosing quotation marks if present + cleaned_key = k.lstrip('\ufeff').strip().strip('"') + cleaned_header[cleaned_key] = v + return cleaned_header def normalize_condition(condition_str): From 64521d9e45053f2327b4ca5164d305fe289e2498 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Thu, 25 Jan 2024 12:39:08 -0500 Subject: [PATCH 03/27] remove print --- reproschema/redcap2reproschema.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index 6f9cea4..f8c5fdf 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -376,9 +376,7 @@ def process_csv( with open(csv_file, mode="r", encoding="utf-8") as csvfile: reader = csv.DictReader(csvfile) for row in reader: - print(f"process_csv: {row}") row = clean_header(row) - print(f"process_csv: {row} - after") form_name = row["Form Name"] if form_name not in datas: datas[form_name] = [] From 4c1081af6f130505fcfa90132e01927409f08bee Mon Sep 17 00:00:00 2001 From: yibeichan Date: Wed, 7 Feb 2024 11:35:51 -0500 Subject: [PATCH 04/27] fix order and other errors --- reproschema/redcap2reproschema.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index f8c5fdf..35b758a 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -19,16 +19,24 @@ def clean_header(header): def normalize_condition(condition_str): + # Regular expressions for various pattern replacements re_parentheses = re.compile(r"\(([0-9]*)\)") re_non_gt_lt_equal = re.compile(r"([^>|<])=") re_brackets = re.compile(r"\[([^\]]*)\]") + re_extra_spaces = re.compile(r"\s+") + re_double_quotes = re.compile(r'"') + # Apply regex replacements condition_str = re_parentheses.sub(r"___\1", condition_str) condition_str = re_non_gt_lt_equal.sub(r"\1 ==", condition_str) condition_str = condition_str.replace(" and ", " && ").replace(" or ", " || ") condition_str = re_brackets.sub(r" \1 ", condition_str) - return condition_str + # Trim extra spaces and replace double quotes with single quotes + condition_str = re_extra_spaces.sub(' ', condition_str) # Reduce multiple spaces to a single space + condition_str = re_double_quotes.sub("'", condition_str) # Replace double quotes with single quotes + + return condition_str.strip() def process_visibility(data): condition = data.get("Branching Logic (Show field only if...)") @@ -245,6 +253,7 @@ def process_row( def create_form_schema( abs_folder_path, schema_context_url, + redcap_version, form_name, activity_display_name, activity_description, @@ -264,7 +273,7 @@ def create_form_schema( "prefLabel": activity_display_name, "description": activity_description, "schemaVersion": "1.0.0-rc4", - "version": "0.0.1", + "version": redcap_version, "ui": { "order": unique_order, "addProperties": bl_list, @@ -301,6 +310,7 @@ def process_activities(activity_name, protocol_visibility_obj, protocol_order): def create_protocol_schema( abs_folder_path, schema_context_url, + redcap_version, protocol_name, protocol_display_name, protocol_description, @@ -316,27 +326,27 @@ def create_protocol_schema( "skos:altLabel": f"{protocol_name}_schema", "schema:description": protocol_description, "schema:schemaVersion": "1.0.0-rc4", - "schema:version": "0.0.1", + "schema:version": redcap_version, "ui": { "addProperties": [], - "order": protocol_order, + "order": [], "shuffle": False, }, } # Populate addProperties list for activity in protocol_order: + full_path = f"../activities/{activity_name}/{activity_name}_schema" add_property = { - "isAbout": f"../activities/{activity}/{activity}_schema", + "isAbout": full_path, "variableName": f"{activity}_schema", # Assuming activity name as prefLabel, update as needed "prefLabel": activity.replace("_", " ").title(), + "isVis": protocol_visibility_obj.get(activity, True), # Default to True if not specified } protocol_schema["ui"]["addProperties"].append(add_property) - - # Add visibility if needed - if protocol_visibility_obj: - protocol_schema["ui"]["visibility"] = protocol_visibility_obj + # Add the full path to the order list + protocol_schema["ui"]["order"].append(full_path) protocol_dir = f"{abs_folder_path}/{protocol_name}" schema_file = f"{protocol_name}_schema" @@ -425,6 +435,7 @@ def redcap2reproschema(csv_file, yaml_file, schema_context_url=None): protocol_name = protocol.get("protocol_name") protocol_display_name = protocol.get("protocol_display_name") protocol_description = protocol.get("protocol_description") + redcap_version = protocol.get("redcap_version") if not protocol_name: raise ValueError("Protocol name not specified in the YAML file.") @@ -520,6 +531,7 @@ def redcap2reproschema(csv_file, yaml_file, schema_context_url=None): create_form_schema( abs_folder_path, schema_context_url, + redcap_version, form_name, activity_display_name, activity_description, @@ -535,6 +547,7 @@ def redcap2reproschema(csv_file, yaml_file, schema_context_url=None): create_protocol_schema( abs_folder_path, schema_context_url, + redcap_version, protocol_name, protocol_display_name, protocol_description, From 50fe4ceb234e386876ed1b12ee9ed32896275679 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Wed, 7 Feb 2024 11:41:14 -0500 Subject: [PATCH 05/27] change ui yesno to radio --- reproschema/redcap2reproschema.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index 35b758a..aa0e655 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -55,7 +55,11 @@ def process_visibility(data): def parse_field_type_and_value(field, input_type_map): field_type = field.get("Field Type", "") - input_type = input_type_map.get(field_type, field_type) + # Check if field_type is 'yesno' and directly assign 'radio' as the input type + if field_type == "yesno": + input_type = "radio" # Directly set to 'radio' for 'yesno' fields + else: + input_type = input_type_map.get(field_type, field_type) # Original logic # Initialize the default value type as string value_type = "xsd:string" @@ -68,7 +72,8 @@ def parse_field_type_and_value(field, input_type_map): "time_": "xsd:time", "email": "xsd:string", "phone": "xsd:string", - } # todo: input_type="signature" + # No change needed here for 'yesno', as it's handled above + } # Get the validation type from the field, if available validation_type = field.get( @@ -85,6 +90,7 @@ def parse_field_type_and_value(field, input_type_map): return input_type, value_type + def process_choices(field_type, choices_str): if field_type not in ["radio", "dropdown"]: # Handle only radio and dropdown types return None From 4359791a214e7ed1b64d58eb29482340e941859d Mon Sep 17 00:00:00 2001 From: yibeichan Date: Wed, 7 Feb 2024 11:47:16 -0500 Subject: [PATCH 06/27] fix typo --- reproschema/redcap2reproschema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index aa0e655..3959d1b 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -342,7 +342,7 @@ def create_protocol_schema( # Populate addProperties list for activity in protocol_order: - full_path = f"../activities/{activity_name}/{activity_name}_schema" + full_path = f"../activities/{activity}/{activity}_schema" add_property = { "isAbout": full_path, "variableName": f"{activity}_schema", From b17b5c7c93dc492104f3720dd4ddbd7702a2b905 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Thu, 22 Feb 2024 17:09:00 -0500 Subject: [PATCH 07/27] update context, field->item, fix isVis --- reproschema/redcap2reproschema.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index 3959d1b..b9e223c 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -25,15 +25,21 @@ def normalize_condition(condition_str): re_brackets = re.compile(r"\[([^\]]*)\]") re_extra_spaces = re.compile(r"\s+") re_double_quotes = re.compile(r'"') + re_or = re.compile(r'\bor\b') # Match 'or' as whole word # Apply regex replacements condition_str = re_parentheses.sub(r"___\1", condition_str) condition_str = re_non_gt_lt_equal.sub(r"\1 ==", condition_str) - condition_str = condition_str.replace(" and ", " && ").replace(" or ", " || ") condition_str = re_brackets.sub(r" \1 ", condition_str) + # Replace 'or' with '||', ensuring not to replace '||' + condition_str = re_or.sub('||', condition_str) + + # Replace 'and' with '&&' + condition_str = condition_str.replace(" and ", " && ") + # Trim extra spaces and replace double quotes with single quotes - condition_str = re_extra_spaces.sub(' ', condition_str) # Reduce multiple spaces to a single space + condition_str = re_extra_spaces.sub(' ', condition_str).strip() # Reduce multiple spaces to a single space condition_str = re_double_quotes.sub("'", condition_str) # Replace double quotes with single quotes return condition_str.strip() @@ -175,7 +181,7 @@ def process_row( rowData = { "@context": schema_context_url, - "@type": "reproschema:Field", + "@type": "reproschema:Item", "@id": item_id, "prefLabel": item_id, "description": f"{item_id} of {form_name}", @@ -456,7 +462,7 @@ def redcap2reproschema(csv_file, yaml_file, schema_context_url=None): abs_folder_path = os.path.abspath(protocol_name) if schema_context_url is None: - schema_context_url = "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic" + schema_context_url = "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new" # Initialize variables schema_map = { From ca3162de5bed4017ea9088ec1f8ae04f62d2a655 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Thu, 22 Feb 2024 21:35:12 -0500 Subject: [PATCH 08/27] remove useless due to failed validation --- reproschema/redcap2reproschema.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index b9e223c..d3aee9d 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -119,7 +119,7 @@ def process_choices(field_type, choices_str): choice_obj = {"name": parts[1], "value": value} if len(parts) == 3: # Handle image url - choice_obj["schema:image"] = f"{parts[2]}.png" + choice_obj["image"] = f"{parts[2]}.png" choices.append(choice_obj) return choices @@ -205,7 +205,7 @@ def process_row( for key, value in field.items(): if ( - schema_map.get(key) in ["question", "schema:description", "preamble"] + schema_map.get(key) in ["question", "description", "preamble"] and value ): rowData.update({schema_map[key]: parse_html(value)}) @@ -334,11 +334,11 @@ def create_protocol_schema( "@context": schema_context_url, "@type": "reproschema:Protocol", "@id": f"{protocol_name}_schema", - "skos:prefLabel": protocol_display_name, - "skos:altLabel": f"{protocol_name}_schema", - "schema:description": protocol_description, - "schema:schemaVersion": "1.0.0-rc4", - "schema:version": redcap_version, + "prefLabel": protocol_display_name, + # "altLabel": f"{protocol_name}_schema", + "description": protocol_description, + "schemaVersion": "1.0.0-rc4", + "version": redcap_version, "ui": { "addProperties": [], "order": [], From 4288f8aa2bd7a1ae9e48643fa2a538854e310d00 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Fri, 23 Feb 2024 15:28:41 -0500 Subject: [PATCH 09/27] remove visibility at the item level & remove matrixInfo --- reproschema/redcap2reproschema.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index d3aee9d..b1dcd52 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -239,12 +239,6 @@ def process_row( } ) - elif schema_map.get(key) == "visibility" and value: - condition = normalize_condition(value) - rowData.setdefault("visibility", []).append( - {"variableName": field["Variable / Field Name"], "isVis": condition} - ) - elif key == "Identifier?" and value: identifier_val = value.lower() == "y" rowData.update( @@ -293,8 +287,9 @@ def create_form_schema( }, } - if matrix_list: - json_ld["matrixInfo"] = matrix_list + # remove matrixInfo to pass validataion + # if matrix_list: + # json_ld["matrixInfo"] = matrix_list if scores_list: json_ld["scoringLogic"] = scores_list @@ -335,7 +330,7 @@ def create_protocol_schema( "@type": "reproschema:Protocol", "@id": f"{protocol_name}_schema", "prefLabel": protocol_display_name, - # "altLabel": f"{protocol_name}_schema", + "altLabel": f"{protocol_name}_schema", "description": protocol_description, "schemaVersion": "1.0.0-rc4", "version": redcap_version, From 57ca52e16d3966dd0ef03cc73cea74fc874b9bcf Mon Sep 17 00:00:00 2001 From: yibeichan Date: Sun, 25 Feb 2024 17:54:03 -0500 Subject: [PATCH 10/27] fix choice --- reproschema/redcap2reproschema.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index b1dcd52..8afdc5b 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -116,10 +116,11 @@ def process_choices(field_type, choices_str): except ValueError: value = parts[0] - choice_obj = {"name": parts[1], "value": value} - if len(parts) == 3: - # Handle image url - choice_obj["image"] = f"{parts[2]}.png" + choice_obj = {"name": " ".join(parts[1:]), "value": value} + # remove image for now + # if len(parts) == 3: + # # Handle image url + # choice_obj["image"] = f"{parts[2]}.png" choices.append(choice_obj) return choices From 82e2300566080acd5cef3b0225510abe9fb2eea0 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Wed, 28 Feb 2024 11:33:26 -0500 Subject: [PATCH 11/27] remove identifier --- reproschema/redcap2reproschema.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index 8afdc5b..d7d881c 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -240,15 +240,15 @@ def process_row( } ) - elif key == "Identifier?" and value: - identifier_val = value.lower() == "y" - rowData.update( - { - schema_map[key]: [ - {"legalStandard": "unknown", "isIdentifier": identifier_val} - ] - } - ) + # elif key == "Identifier?" and value: + # identifier_val = value.lower() == "y" + # rowData.update( + # { + # schema_map[key]: [ + # {"legalStandard": "unknown", "isIdentifier": identifier_val} + # ] + # } + # ) elif key in additional_notes_list and value: notes_obj = {"source": "redcap", "column": key, "value": value} @@ -475,7 +475,7 @@ def redcap2reproschema(csv_file, yaml_file, schema_context_url=None): "Choices, Calculations, OR Slider Labels": "choices", # column F "Branching Logic (Show field only if...)": "visibility", # column L "Custom Alignment": "customAlignment", # column N - "Identifier?": "identifiable", # column K + # "Identifier?": "identifiable", # column K "multipleChoice": "multipleChoice", "responseType": "@type", } From c6cabf59cd0ab6cf21a4837a8b8716d96b5917c9 Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Fri, 5 Apr 2024 17:24:05 -0400 Subject: [PATCH 12/27] updating validate command to the new pydantic model --- reproschema/cli.py | 7 +- reproschema/jsonldutils.py | 52 +++--- reproschema/models/__init__.py | 4 +- reproschema/models/activity.py | 66 -------- reproschema/models/base.py | 76 --------- reproschema/models/item.py | 156 ------------------ reproschema/{ => models}/model.py | 0 reproschema/models/protocol.py | 77 --------- reproschema/models/reproschema | 252 ++++++++++++++++++++++++++++++ reproschema/models/utils.py | 3 +- reproschema/utils.py | 103 ++++++++++++ reproschema/validate.py | 20 +-- 12 files changed, 400 insertions(+), 416 deletions(-) delete mode 100644 reproschema/models/activity.py delete mode 100644 reproschema/models/base.py delete mode 100644 reproschema/models/item.py rename reproschema/{ => models}/model.py (100%) delete mode 100644 reproschema/models/protocol.py create mode 100644 reproschema/models/reproschema diff --git a/reproschema/cli.py b/reproschema/cli.py index e31b03e..685af39 100644 --- a/reproschema/cli.py +++ b/reproschema/cli.py @@ -42,14 +42,15 @@ def main(log_level): @main.command() -@click.option("--shapefile", default=None, type=click.Path(exists=True, dir_okay=False)) @click.argument("path", nargs=1, type=str) -def validate(shapefile, path): +def validate(path): if not (path.startswith("http") or os.path.exists(path)): raise ValueError(f"{path} must be a URL or an existing file or directory") from .validate import validate - validate(shapefile, path) + result = validate(path) + if result: + click.echo("Validation successful") @main.command() diff --git a/reproschema/jsonldutils.py b/reproschema/jsonldutils.py index f88f38f..988c2ff 100644 --- a/reproschema/jsonldutils.py +++ b/reproschema/jsonldutils.py @@ -1,8 +1,10 @@ from pyld import jsonld -from pyshacl import validate as shacl_validate import json import os -from .utils import start_server, stop_server, lgr +from pathlib import Path +from copy import deepcopy +from .utils import start_server, stop_server, lgr, fixing_old_schema +from .models import Item, Activity, Protocol, ResponseOption def load_file(path_or_url, started=False, http_kwargs={}): @@ -41,37 +43,47 @@ def load_file(path_or_url, started=False, http_kwargs={}): return data -def validate_data(data, shape_file_path): - """Validate an expanded jsonld document against a shape. +def validate_data(data): + """Validate an expanded jsonld document against the pydantic model. Parameters ---------- data : dict Python dictionary containing JSONLD object - shape_file_path : str - SHACL file for the document Returns ------- conforms: bool Whether the document is conformant with the shape v_text: str - Validation information returned by PySHACL + Validation errors if any returned by pydantic """ - kwargs = {"algorithm": "URDNA2015", "format": "application/n-quads"} - normalized = jsonld.normalize(data, kwargs) - data_file_format = "nquads" - shape_file_format = "turtle" - conforms, v_graph, v_text = shacl_validate( - normalized, - shacl_graph=shape_file_path, - data_graph_format=data_file_format, - shacl_graph_format=shape_file_format, - inference="rdfs", - debug=False, - serialize_report_graph=True, - ) + # do we need it? + # kwargs = {"algorithm": "URDNA2015", "format": "application/n-quads"} + # normalized = jsonld.normalize(data, kwargs) + if data[0]["@type"][0] == "http://schema.repronim.org/Field": + obj_type = Item + elif data[0]["@type"][0] == "http://schema.repronim.org/ResponseOption": + obj_type = ResponseOption + elif data[0]["@type"][0] == "http://schema.repronim.org/Activity": + obj_type = Activity + else: + raise ValueError("Unknown type") + data_fixed = [fixing_old_schema(data[0], copy_data=True)] + # TODO: where should we load the context from? + contexfile = Path(__file__).resolve().parent / "models/reproschema" + with open(contexfile) as fp: + context = json.load(fp) + data_fixed_comp = jsonld.compact(data_fixed, context) + del data_fixed_comp["@context"] + conforms = False + v_text = "" + try: + obj_type(**data_fixed_comp) + conforms = True + except Exception as e: + v_text = str(e) return conforms, v_text diff --git a/reproschema/models/__init__.py b/reproschema/models/__init__.py index 1c1a154..bfac402 100644 --- a/reproschema/models/__init__.py +++ b/reproschema/models/__init__.py @@ -1,3 +1 @@ -from .protocol import Protocol -from .activity import Activity -from .item import Item +from .model import Activity, Item, Protocol, ResponseOption diff --git a/reproschema/models/activity.py b/reproschema/models/activity.py deleted file mode 100644 index 0ad79e2..0000000 --- a/reproschema/models/activity.py +++ /dev/null @@ -1,66 +0,0 @@ -from .base import SchemaBase - - -class Activity(SchemaBase): - """ - class to deal with reproschema activities - """ - - schema_type = "reproschema:Activity" - - def __init__(self, version=None): - super().__init__(version) - self.schema["ui"] = {"shuffle": [], "order": [], "addProperties": []} - - def set_ui_shuffle(self, shuffle=False): - self.schema["ui"]["shuffle"] = shuffle - - def set_URI(self, URI): - self.URI = URI - - def get_URI(self): - return self.URI - - # TODO - # preamble - # compute - # citation - # image - - def set_defaults(self, name): - self._ReproschemaSchema__set_defaults(name) # this looks wrong - self.set_ui_shuffle(False) - - def update_activity(self, item_info): - # TODO - # - remove the hard coding on visibility and valueRequired - - # update the content of the activity schema with new item - - item_info["URI"] = "items/" + item_info["name"] - - append_to_activity = { - "variableName": item_info["name"], - "isAbout": item_info["URI"], - "isVis": item_info["visibility"], - "valueRequired": False, - } - - self.schema["ui"]["order"].append(item_info["URI"]) - self.schema["ui"]["addProperties"].append(append_to_activity) - - def sort(self): - schema_order = [ - "@context", - "@type", - "@id", - "prefLabel", - "description", - "schemaVersion", - "version", - "ui", - ] - self.sort_schema(schema_order) - - ui_order = ["shuffle", "order", "addProperties"] - self.sort_ui(ui_order) diff --git a/reproschema/models/base.py b/reproschema/models/base.py deleted file mode 100644 index f3ecf93..0000000 --- a/reproschema/models/base.py +++ /dev/null @@ -1,76 +0,0 @@ -import json -import os - - -class SchemaBase: - """ - class to deal with reproschema schemas - """ - - schema_type = None - - def __init__(self, version): - URL = "https://raw.githubusercontent.com/ReproNim/reproschema/" - VERSION = version or "1.0.0-rc2" - - self.schema = { - "@context": URL + VERSION + "/contexts/generic", - "@type": self.schema_type, - "schemaVersion": VERSION, - "version": "0.0.1", - } - - def set_filename(self, name): - self.schema_file = name + "_schema" - self.schema["@id"] = name + "_schema" - - def get_name(self): - return self.schema_file.replace("_schema", "") - - def get_filename(self): - return self.schema_file - - def set_pref_label(self, pref_label): - self.schema["prefLabel"] = pref_label - - def set_description(self, description): - self.schema["description"] = description - - def set_directory(self, output_directory): - self.dir = output_directory - - def __set_defaults(self, name): - self.set_filename(name) - self.set_directory(name) - self.set_pref_label(name.replace("_", " ")) - self.set_description(name.replace("_", " ")) - - def sort_schema(self, schema_order): - reordered_dict = {k: self.schema[k] for k in schema_order} - self.schema = reordered_dict - - def sort_ui(self, ui_order): - reordered_dict = {k: self.schema["ui"][k] for k in ui_order} - self.schema["ui"] = reordered_dict - - def write(self, output_dir): - with open(os.path.join(output_dir, self.schema_file), "w") as ff: - json.dump(self.schema, ff, sort_keys=False, indent=4) - - @classmethod - def from_data(cls, data): - if cls.schema_type is None: - raise ValueError("SchemaBase cannot be used to instantiate class") - if cls.schema_type != data["@type"]: - raise ValueError(f"Mismatch in type {data['@type']} != {cls.schema_type}") - klass = cls() - klass.schema = data - return klass - - @classmethod - def from_file(cls, filepath): - with open(filepath) as fp: - data = json.load(fp) - if "@type" not in data: - raise ValueError("Missing @type key") - return cls.from_data(data) diff --git a/reproschema/models/item.py b/reproschema/models/item.py deleted file mode 100644 index fc08c70..0000000 --- a/reproschema/models/item.py +++ /dev/null @@ -1,156 +0,0 @@ -from .base import SchemaBase - - -class Item(SchemaBase): - """ - class to deal with reproschema activities - """ - - schema_type = "reproschema:Field" - - def __init__(self, version=None): - super().__init__(version) - self.schema["ui"] = {"inputType": []} - self.schema["question"] = {} - self.schema["responseOptions"] = {} - # default input type is "char" - self.set_input_type_as_char() - - def set_URI(self, URI): - self.URI = URI - - # TODO - # image - # readonlyValue - - def set_defaults(self, name): - self._ReproschemaSchema__set_defaults(name) # this looks wrong - self.schema_file = name - self.schema["@id"] = name - self.set_input_type_as_char() - - def set_question(self, question, lang="en"): - self.schema["question"][lang] = question - - def set_input_type(self, input_type): - self.schema["ui"]["inputType"] = input_type - - def set_response_options(self, response_options): - self.schema["responseOptions"] = response_options - - """ - - input types with different response choices - - """ - - def set_input_type_as_radio(self, response_options): - self.set_input_type("radio") - self.set_response_options(response_options) - - def set_input_type_as_select(self, response_options): - self.set_input_type("select") - self.set_response_options(response_options) - - def set_input_type_as_slider(self): - self.set_input_type_as_char() # until the slide item of the ui is fixed - # self.set_input_type("slider") - # self.set_response_options({"valueType": "xsd:string"}) - - def set_input_type_as_language(self): - URL = "https://raw.githubusercontent.com/ReproNim/reproschema/" - - self.set_input_type("selectLanguage") - - response_options = { - "valueType": "xsd:string", - "multipleChoice": True, - "choices": URL + "master/resources/languages.json", - } - self.set_response_options(response_options) - - """ - - input types with no response choice - - """ - - def set_input_type_as_char(self): - self.set_input_type("text") - self.set_response_options({"valueType": "xsd:string"}) - - def set_input_type_as_int(self): - self.set_input_type("number") - self.set_response_options({"valueType": "xsd:integer"}) - - def set_input_type_as_float(self): - self.set_input_type("float") - self.set_response_options({"valueType": "xsd:float"}) - - def set_input_type_as_time_range(self): - self.set_input_type("timeRange") - self.set_response_options({"valueType": "datetime"}) - - def set_input_type_as_date(self): - self.set_input_type("date") - self.set_response_options({"valueType": "xsd:date"}) - - """ - - input types with no response choice but with some parameters - - """ - - def set_input_type_as_multitext(self, max_length=300): - self.set_input_type("text") - self.set_response_options({"valueType": "xsd:string", "maxLength": max_length}) - - # TODO - # email: EmailInput/EmailInput.vue - # audioCheck: AudioCheck/AudioCheck.vue - # audioRecord: WebAudioRecord/Audio.vue - # audioPassageRecord: WebAudioRecord/Audio.vue - # audioImageRecord: WebAudioRecord/Audio.vue - # audioRecordNumberTask: WebAudioRecord/Audio.vue - # audioAutoRecord: AudioCheckRecord/AudioCheckRecord.vue - # year: YearInput/YearInput.vue - # selectCountry: SelectInput/SelectInput.vue - # selectState: SelectInput/SelectInput.vue - # documentUpload: DocumentUpload/DocumentUpload.vue - # save: SaveData/SaveData.vue - # static: Static/Static.vue - # StaticReadOnly: Static/Static.vue - - def set_basic_response_type(self, response_type): - # default (also valid for "char" input type) - self.set_input_type_as_char() - - if response_type == "int": - self.set_input_type_as_int() - - elif response_type == "float": - self.set_input_type_as_float() - - elif response_type == "date": - self.set_input_type_as_date() - - elif response_type == "time range": - self.set_input_type_as_time_range() - - elif response_type == "language": - self.set_input_type_as_language() - - def sort(self): - schema_order = [ - "@context", - "@type", - "@id", - "prefLabel", - "description", - "schemaVersion", - "version", - "ui", - "question", - "responseOptions", - ] - self.sort_schema(schema_order) diff --git a/reproschema/model.py b/reproschema/models/model.py similarity index 100% rename from reproschema/model.py rename to reproschema/models/model.py diff --git a/reproschema/models/protocol.py b/reproschema/models/protocol.py deleted file mode 100644 index 10fa951..0000000 --- a/reproschema/models/protocol.py +++ /dev/null @@ -1,77 +0,0 @@ -from .base import SchemaBase - - -class Protocol(SchemaBase): - """ - class to deal with reproschema protocols - """ - - schema_type = "reproschema:Protocol" - - def __init__(self, version=None): - super().__init__(version) - self.schema["ui"] = { - "allow": [], - "shuffle": [], - "order": [], - "addProperties": [], - } - - def set_landing_page(self, landing_page_url, lang="en"): - self.schema["landingPage"] = {"@id": landing_page_url, "inLanguage": lang} - - # TODO - # def add_landing_page(self, landing_page_url, lang="en"): - # preamble - # compute - - def set_image(self, image_url): - self.schema["image"] = image_url - - def set_ui_allow(self): - self.schema["ui"]["allow"] = [ - "reproschema:AutoAdvance", - "reproschema:AllowExport", - ] - - def set_ui_shuffle(self, shuffle=False): - self.schema["ui"]["shuffle"] = shuffle - - def set_defaults(self, name): - self._ReproschemaSchema__set_defaults(name) # this looks wrong - self.set_landing_page("../../README-en.md") - self.set_ui_allow() - self.set_ui_shuffle(False) - - def append_activity(self, activity): - # TODO - # - remove the hard coding on visibility and valueRequired - - # update the content of the protocol with this new activity - append_to_protocol = { - "variableName": activity.get_name(), - "isAbout": activity.get_URI(), - "prefLabel": {"en": activity.schema["prefLabel"]}, - "isVis": True, - "valueRequired": False, - } - - self.schema["ui"]["order"].append(activity.URI) - self.schema["ui"]["addProperties"].append(append_to_protocol) - - def sort(self): - schema_order = [ - "@context", - "@type", - "@id", - "prefLabel", - "description", - "schemaVersion", - "version", - "landingPage", - "ui", - ] - self.sort_schema(schema_order) - - ui_order = ["allow", "shuffle", "order", "addProperties"] - self.sort_ui(ui_order) diff --git a/reproschema/models/reproschema b/reproschema/models/reproschema new file mode 100644 index 0000000..1d8e6dd --- /dev/null +++ b/reproschema/models/reproschema @@ -0,0 +1,252 @@ +{ + "comments": { + "description": "Auto generated by LinkML jsonld context generator", + "generation_date": "2024-02-16T13:37:16", + "source": "reproschema.yaml" + }, + "@context": { + "linkml": "https://w3id.org/linkml/", + "nidm": "http://purl.org/nidash/nidm#", + "owl": "http://www.w3.org/2002/07/owl#", + "prov": "http://www.w3.org/ns/prov#", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "reproschema": "http://schema.repronim.org/", + "schema": "http://schema.org/", + "skos": "http://www.w3.org/2004/02/skos/core#", + "xml": { + "@id": "http://www.w3.org/XML/1998/namespace", + "@prefix": true + }, + "xsd": "http://www.w3.org/2001/XMLSchema#", + "@vocab": "http://schema.repronim.org/", + "@version": 1.1, + "@language": "en", + "id": "@id", + "category": "@type", + "ui": "@nest", + "about": { + "@id": "schema:about" + }, + "addProperties": { + "@container": "@set", + "@nest": "ui" + }, + "additionalNotesObj": { + "@container": "@set" + }, + "allow": { + "@type": "@id", + "@container": "@set", + "@nest": "ui" + }, + "altLabel": { + "@id": "skos:altLabel", + "@container": "@language" + }, + "associatedMedia": { + "@id": "schema:associatedMedia" + }, + "audio": { + "@type": "@id", + "@id": "schema:audio" + }, + "choices": { + "@container": "@set" + }, + "citation": { + "@id": "schema:citation", + "@container": "@language" + }, + "column": { + "@type": "xsd:string" + }, + "compute": { + "@id": "reproschema:compute", + "@container": "@set" + }, + "contentUrl": { + "@type": "@id", + "@id": "schema:contentUrl" + }, + "cronTable": { + "@id": "reproschema:cronTable" + }, + "datumType": { + "@id": "reproschema:datumType" + }, + "description": { + "@id": "schema:description", + "@container": "@language" + }, + "endedAtTime": { + "@type": "xsd:dateTime", + "@id": "prov:endedAtTime" + }, + "generated": { + "@id": "prov:generated" + }, + "image": { + "@type": "@id", + "@id": "schema:image" + }, + "imageUrl": { + "@type": "@id" + }, + "inLanguage": { + "@id": "schema:inLanguage", + "@language": null + }, + "inputType": { + "@type": "xsd:string", + "@nest": "ui" + }, + "isAbout": { + "@type": "@id" + }, + "isPartOf": { + "@type": "@id", + "@id": "schema:isPartOf" + }, + "landingPage": { + "@type": "@id", + "@container": "@set" + }, + "limit": { + "@language": null + }, + "maxValue": { + "@id": "schema:maxValue" + }, + "message": { + "@container": "@language" + }, + "messages": { + "@container": "@set" + }, + "minValue": { + "@id": "schema:minValue" + }, + "multipleChoice": { + "@type": "xsd:boolean" + }, + "name": { + "@id": "schema:name", + "@container": "@language" + }, + "order": { + "@type": "@id", + "@container": "@list", + "@nest": "ui" + }, + "overrideProperties": { + "@container": "@set", + "@nest": "ui" + }, + "preamble": { + "@id": "reproschema:preamble", + "@container": "@language" + }, + "prefLabel": { + "@id": "skos:prefLabel", + "@container": "@language" + }, + "question": { + "@id": "schema:question", + "@container": "@language" + }, + "randomMaxDelay": { + "@language": null + }, + "readonlyValue": { + "@type": "xsd:boolean", + "@id": "schema:readonlyValue", + "@nest": "ui" + }, + "responseOptions": { + "@type": "@id" + }, + "schedule": { + "@language": null + }, + "schemaVersion": { + "@id": "schema:schemaVersion", + "@language": null + }, + "shuffle": { + "@type": "xsd:boolean", + "@nest": "ui" + }, + "source": { + "@type": "xsd:string" + }, + "startedAtTime": { + "@type": "xsd:dateTime", + "@id": "prov:startedAtTime" + }, + "subject_id": { + "@id": "nidm:subject_id" + }, + "unitOptions": { + "@type": "@id", + "@container": "@set" + }, + "url": { + "@type": "@id", + "@id": "schema:url" + }, + "used": { + "@type": "@id", + "@container": "@set", + "@id": "prov:used" + }, + "valueRequired": { + "@type": "xsd:boolean", + "@id": "schema:valueRequired" + }, + "valueType": { + "@type": "@id", + "@container": "@set" + }, + "version": { + "@id": "schema:version", + "@language": null + }, + "video": { + "@type": "@id", + "@id": "schema:video" + }, + "wasAssociatedWith": { + "@type": "@id", + "@id": "prov:wasAssociatedWith" + }, + "wasAttributedTo": { + "@type": "@id", + "@id": "prov:wasAttributedTo" + }, + "Activity": { + "@id": "reproschema:Activity" + }, + "Agent": { + "@id": "prov:Agent" + }, + "CreativeWork": { + "@id": "schema:CreativeWork" + }, + "LangString": { + "@id": "rdf:langString" + }, + "MediaObject": { + "@id": "schema:MediaObject" + }, + "StructuredValue": { + "@id": "schema:StructuredValue" + }, + "Thing": { + "@id": "schema:Thing" + }, + "VideoObject": { + "@id": "schema:VideoObject" + } + } +} diff --git a/reproschema/models/utils.py b/reproschema/models/utils.py index 745ec4a..c1d34b6 100644 --- a/reproschema/models/utils.py +++ b/reproschema/models/utils.py @@ -1,7 +1,8 @@ import json -from . import Protocol, Activity, Item +from .model import Protocol, Activity, Item, ResponseOption +# TODO: where can we be used? def load_schema(filepath): with open(filepath) as fp: data = json.load(fp) diff --git a/reproschema/utils.py b/reproschema/utils.py index 2f85d1a..36c754d 100644 --- a/reproschema/utils.py +++ b/reproschema/utils.py @@ -4,6 +4,7 @@ from tempfile import mkdtemp import requests import requests_cache +from copy import deepcopy from . import get_logger @@ -52,3 +53,105 @@ def start_server(port=8000, path=None, tmpdir=None): def stop_server(stop): stop() requests_cache.clear() + + +# items that have to be fixed in the old schema +LANG_FIX = [ + "http://schema.org/schemaVersion", + "http://schema.org/version", + "http://schema.repronim.org/limit", + "http://schema.repronim.org/randomMaxDelay", + "http://schema.org/inLanguage", + "http://schema.repronim.org/schedule", +] +BOOL_FIX = [ + "http://schema.repronim.org/shuffle", + "http://schema.org/readonlyValue", + "http://schema.repronim.org/multipleChoice", + "http://schema.org/valueRequired", +] + +ALLOWTYPE_FIX = ["http://schema.repronim.org/allow"] +ALLOWTYPE_MAPPING = { + "http://schema.repronim.org/Skipped": "http://schema.repronim.org/AllowSkip", + "http://schema.repronim.org/DontKnow": "http://schema.repronim.org/AllowAltResponse", +} + +IMAGE_FIX = ["http://schema.org/image"] + + +def _lang_fix(data_el): + if isinstance(data_el, dict): + data_el.pop("@language", None) + elif isinstance(data_el, list) and len(data_el) == 1: + data_el = data_el[0] + data_el.pop("@language", None) + else: + raise Exception(f"expected a list or dictionary, got {data_el}") + return data_el + + +def _image_fix(data_el): + if isinstance(data_el, dict): + if "@id" not in data_el: + data_el["@id"] = data_el.pop("@value") + data_el.pop("@language", None) + elif isinstance(data_el, list) and len(data_el) == 1: + data_el = data_el[0] + data_el = _image_fix(data_el) + else: + raise Exception(f"expected a list or dictionary, got {data_el}") + return data_el + + +def _bool_fix(data_el): + if isinstance(data_el, dict): + data_el["@type"] = "http://www.w3.org/2001/XMLSchema#boolean" + elif isinstance(data_el, list): + for el in data_el: + _bool_fix(el) + else: + raise Exception(f"expected a list or dictionary, got {data_el}") + + +def _allowtype_fix(data_el): + if isinstance(data_el, dict): + if data_el["@id"] in ALLOWTYPE_MAPPING: + data_el["@id"] = ALLOWTYPE_MAPPING[data_el["@id"]] + elif isinstance(data_el, list): + for el in data_el: + _allowtype_fix(el) + else: + raise Exception(f"expected a list or dictionary, got {data_el}") + + +def fixing_old_schema(data, copy_data=False): + """Fixes the old schema so it can be load to teh new model""" + if copy_data: + data = deepcopy(data) + for key, val in data.items(): + if key in LANG_FIX: + data[key] = _lang_fix(val) + elif key in BOOL_FIX: + _bool_fix(val) + elif key in ALLOWTYPE_FIX: + _allowtype_fix(val) + elif key in IMAGE_FIX: + data[key] = _image_fix(val) + elif isinstance(val, (str, bool, int, float)): + pass + elif isinstance(val, dict): + fix_rec(val) + elif isinstance(val, list): + for el in val: + if isinstance(el, (str, bool, int, float)): + pass + elif isinstance(el, dict): + fixing_old_schema(el) + else: + raise Exception( + f"expected a list, str, bool or numerics, got {data_el}" + ) + else: + raise Exception(f"type {type(val)} not supported yet") + return data diff --git a/reproschema/validate.py b/reproschema/validate.py index 64b612e..638bb03 100644 --- a/reproschema/validate.py +++ b/reproschema/validate.py @@ -3,8 +3,8 @@ from .jsonldutils import load_file, validate_data -def validate_dir(directory, shape_file, started=False, http_kwargs={}): - """Validate a directory containing JSONLD documents +def validate_dir(directory, started=False, http_kwargs={}): + """Validate a directory containing JSONLD documents against the ReproSchema pydantic model. .. warning:: This assumes every file in the directory can be read by a json parser. @@ -12,8 +12,6 @@ def validate_dir(directory, shape_file, started=False, http_kwargs={}): ---------- directory: str Path to directory to walk for validation - shape_file: str - Path containing validation SHACL shape files started : bool Whether an http server exists or not http_kwargs : dict @@ -41,7 +39,7 @@ def validate_dir(directory, shape_file, started=False, http_kwargs={}): data = load_file(full_file_name, started=True, http_kwargs=http_kwargs) if len(data) == 0: raise ValueError("Empty data graph") - conforms, vtext = validate_data(data, shape_file) + conforms, vtext = validate_data(data) except (ValueError,): if stop is not None: stop_server(stop) @@ -57,13 +55,11 @@ def validate_dir(directory, shape_file, started=False, http_kwargs={}): return True -def validate(shapefile, path): +def validate(path): """Helper function to validate directory or path Parameters ---------- - shapefile : path-like - Path to folder or file containing ReproSchema SHACL descriptors path : path-like Path to folder or file containing JSONLD documents. @@ -74,15 +70,11 @@ def validate(shapefile, path): exception. """ - if shapefile is None: - shapefile = os.path.join( - os.path.dirname(__file__), "tests", "reproschema-shacl.ttl" - ) if os.path.isdir(path): - conforms = validate_dir(path, shapefile) + conforms = validate_dir(path) else: data = load_file(path, started=False) - conforms, vtext = validate_data(data, shapefile) + conforms, vtext = validate_data(data) if not conforms: lgr.critical(f"File {path} has validation errors.") raise ValueError(vtext) From ad8a82cb90de8b299742089d1a755c7b0df6a8a7 Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Thu, 18 Apr 2024 18:27:17 -0400 Subject: [PATCH 13/27] updating/fixing the tests; updating the model to use CreativeWork; changes in formating --- reproschema/jsonldutils.py | 8 +- reproschema/models/__init__.py | 2 +- reproschema/models/model.py | 243 +++++++++++++----------- reproschema/models/tests/test_schema.py | 25 +-- reproschema/tests/test_validate.py | 6 +- reproschema/utils.py | 2 +- reproschema/validate.py | 4 + 7 files changed, 150 insertions(+), 140 deletions(-) diff --git a/reproschema/jsonldutils.py b/reproschema/jsonldutils.py index 988c2ff..11fe449 100644 --- a/reproschema/jsonldutils.py +++ b/reproschema/jsonldutils.py @@ -4,7 +4,7 @@ from pathlib import Path from copy import deepcopy from .utils import start_server, stop_server, lgr, fixing_old_schema -from .models import Item, Activity, Protocol, ResponseOption +from .models import Item, Activity, Protocol, ResponseOption, ResponseActivity, Response def load_file(path_or_url, started=False, http_kwargs={}): @@ -68,6 +68,12 @@ def validate_data(data): obj_type = ResponseOption elif data[0]["@type"][0] == "http://schema.repronim.org/Activity": obj_type = Activity + elif data[0]["@type"][0] == "http://schema.repronim.org/Protocol": + obj_type = Protocol + elif data[0]["@type"][0] == "http://schema.repronim.org/ResponseActivity": + obj_type = ResponseActivity + elif data[0]["@type"][0] == "http://schema.repronim.org/Response": + obj_type = Response else: raise ValueError("Unknown type") data_fixed = [fixing_old_schema(data[0], copy_data=True)] diff --git a/reproschema/models/__init__.py b/reproschema/models/__init__.py index bfac402..0da3b23 100644 --- a/reproschema/models/__init__.py +++ b/reproschema/models/__init__.py @@ -1 +1 @@ -from .model import Activity, Item, Protocol, ResponseOption +from .model import Activity, Item, Protocol, ResponseOption, ResponseActivity, Response diff --git a/reproschema/models/model.py b/reproschema/models/model.py index 5d8808e..3d50d80 100644 --- a/reproschema/models/model.py +++ b/reproschema/models/model.py @@ -1,21 +1,19 @@ from __future__ import annotations from datetime import datetime, date -from enum import Enum - from decimal import Decimal -from typing import List, Dict, Optional, Any, Union -from pydantic import BaseModel as BaseModel, ConfigDict, Field, field_validator +from enum import Enum import re import sys +from typing import Any, List, Literal, Dict, Optional, Union +from pydantic.version import VERSION as PYDANTIC_VERSION -if sys.version_info >= (3, 8): - from typing import Literal +if int(PYDANTIC_VERSION[0]) >= 2: + from pydantic import BaseModel, ConfigDict, Field, field_validator else: - from typing_extensions import Literal - + from pydantic import BaseModel, Field, validator metamodel_version = "None" -version = "None" +version = "1.0.0" class ConfiguredBaseModel(BaseModel): @@ -25,8 +23,8 @@ class ConfiguredBaseModel(BaseModel): extra="forbid", arbitrary_types_allowed=True, use_enum_values=True, + strict=False, ) - pass @@ -56,7 +54,75 @@ class MissingType(str, Enum): TimedOut = "reproschema:TimedOut" -class AdditionalNoteObj(ConfiguredBaseModel): +class Agent(ConfiguredBaseModel): + pass + + +class CreativeWork(ConfiguredBaseModel): + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") + + +class Activity(CreativeWork): + """ + An assessment in a protocol. + """ + + about: Optional[str] = Field( + None, description="""The subject matter of the Field.""" + ) + altLabel: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="alternate label", + description="""The alternate label.""", + ) + associatedMedia: Optional[str] = Field( + None, + title="associatedMedia", + description="""A media object that encodes this CreativeWork. This property is a synonym for encoding.""", + ) + citation: Optional[Dict[str, str]] = Field(default_factory=dict) + compute: Optional[List[ComputeSpecification]] = Field( + default_factory=list, + title="computation", + description="""An array of objects indicating computations in an activity or protocol and maps it to the corresponding Item. scoring logic is a subset of all computations that could be performed and not all computations will be scoring. For example, one may want to do conversion from one unit to another.""", + ) + cronTable: Optional[str] = Field( + None, title="cronTable", description="""TODO not described in reproschema""" + ) + description: Optional[Dict[str, str]] = Field(default_factory=dict) + image: Optional[Union[ImageObject, str]] = Field( + None, + title="image", + description="""An image of the item. This can be a URL or a fully described ImageObject.""", + ) + messages: Optional[List[MessageSpecification]] = Field( + default_factory=list, + title="messages", + description="""An array of objects to define conditional messages in an activity or protocol.""", + ) + preamble: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="Preamble", + description="""The preamble for an assessment""", + ) + prefLabel: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="preferred label", + description="""The preferred label.""", + ) + schemaVersion: Optional[str] = Field(None) + ui: Optional[UI] = Field( + None, + title="UI", + description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", + ) + version: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") + + +class AdditionalNoteObj(CreativeWork): """ A set of objects to define notes in a Item. For example, most Redcap and NDA data dictionaries have notes for each item which needs to be captured in reproschema """ @@ -78,9 +144,11 @@ class AdditionalNoteObj(ConfiguredBaseModel): title="value", description="""The value for each option in choices or in additionalNotesObj""", ) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") -class AdditionalProperty(ConfiguredBaseModel): +class AdditionalProperty(CreativeWork): """ An object to describe the various properties added to assessments and Items. """ @@ -136,13 +204,11 @@ class AdditionalProperty(ConfiguredBaseModel): title="UI", description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", ) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") -class Agent(ConfiguredBaseModel): - None - - -class Choice(ConfiguredBaseModel): +class Choice(CreativeWork): """ An object to describe a response option. """ @@ -160,9 +226,11 @@ class Choice(ConfiguredBaseModel): title="value", description="""The value for each option in choices or in additionalNotesObj""", ) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") -class ComputeSpecification(ConfiguredBaseModel): +class ComputeSpecification(CreativeWork): """ An object to define computations in an activity or protocol. """ @@ -177,70 +245,8 @@ class ComputeSpecification(ConfiguredBaseModel): title="variableName", description="""The name used to represent an item.""", ) - - -class CreativeWork(ConfiguredBaseModel): - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) - - -class Activity(CreativeWork): - """ - An assessment in a protocol. - """ - - about: Optional[str] = Field( - None, description="""The subject matter of the Field.""" - ) - altLabel: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="alternate label", - description="""The alternate label.""", - ) - associatedMedia: Optional[str] = Field( - None, - title="associatedMedia", - description="""A media object that encodes this CreativeWork. This property is a synonym for encoding.""", - ) - citation: Optional[Dict[str, str]] = Field(default_factory=dict) - compute: Optional[List[ComputeSpecification]] = Field( - default_factory=list, - title="computation", - description="""An array of objects indicating computations in an activity or protocol and maps it to the corresponding Item. scoring logic is a subset of all computations that could be performed and not all computations will be scoring. For example, one may want to do conversion from one unit to another.""", - ) - cronTable: Optional[str] = Field( - None, title="cronTable", description="""TODO not described in reproschema""" - ) - description: Optional[Dict[str, str]] = Field(default_factory=dict) - image: Optional[Union[ImageObject, str]] = Field( - None, - title="image", - description="""An image of the item. This can be a URL or a fully described ImageObject.""", - ) - messages: Optional[List[MessageSpecification]] = Field( - default_factory=list, - title="messages", - description="""An array of objects to define conditional messages in an activity or protocol.""", - ) - preamble: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="Preamble", - description="""The preamble for an assessment""", - ) - prefLabel: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="preferred label", - description="""The preferred label.""", - ) - schemaVersion: Optional[str] = Field(None) - ui: Optional[UI] = Field( - None, - title="UI", - description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", - ) - version: Optional[str] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class Item(CreativeWork): @@ -303,17 +309,18 @@ class Item(CreativeWork): ) version: Optional[str] = Field(None) video: Optional[VideoObject] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") -class LandingPage(ConfiguredBaseModel): +class LandingPage(CreativeWork): """ An object to define the landing page of a protocol. """ inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class MediaObject(CreativeWork): @@ -323,25 +330,25 @@ class MediaObject(CreativeWork): contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class AudioObject(MediaObject): contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class ImageObject(MediaObject): contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") -class MessageSpecification(ConfiguredBaseModel): +class MessageSpecification(CreativeWork): """ An object to define messages in an activity or protocol. """ @@ -356,9 +363,11 @@ class MessageSpecification(ConfiguredBaseModel): title="Message", description="""The message to be conditionally displayed for an item.""", ) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") -class OverrideProperty(ConfiguredBaseModel): +class OverrideProperty(CreativeWork): """ An object to override the various properties added to assessments and Items. """ @@ -404,6 +413,8 @@ class OverrideProperty(ConfiguredBaseModel): title="variableName", description="""The name used to represent an item.""", ) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class Participant(Agent): @@ -411,6 +422,7 @@ class Participant(Agent): An Agent describing characteristics associated with a participant. """ + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") subject_id: Optional[str] = Field(None) @@ -463,8 +475,8 @@ class Protocol(CreativeWork): description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", ) version: Optional[str] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class Response(CreativeWork): @@ -485,8 +497,8 @@ class Response(CreativeWork): description="""The value for each option in choices or in additionalNotesObj""", ) wasAttributedTo: Optional[Participant] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class ResponseActivity(CreativeWork): @@ -500,8 +512,8 @@ class ResponseActivity(CreativeWork): startedAtTime: Optional[datetime] = Field(None) used: Optional[List[str]] = Field(default_factory=list) wasAssociatedWith: Optional[SoftwareAgent] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class ResponseOption(CreativeWork): @@ -536,26 +548,24 @@ class ResponseOption(CreativeWork): title="The type of the response", description="""The type of the response of an item. For example, string, integer, etc.""", ) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") -class SoftwareAgent(ConfiguredBaseModel): +class SoftwareAgent(CreativeWork): """ Captures information about some action that took place. It also links to information (entities) that were used during the activity """ version: Optional[str] = Field(None) url: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class StructuredValue(CreativeWork): - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) - - -class Thing(ConfiguredBaseModel): - None + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class UI(ConfiguredBaseModel): @@ -596,7 +606,7 @@ class UI(ConfiguredBaseModel): readonlyValue: Optional[bool] = Field(None) -class UnitOption(ConfiguredBaseModel): +class UnitOption(CreativeWork): """ An object to represent a human displayable name alongside the more formal value for units. """ @@ -611,24 +621,26 @@ class UnitOption(ConfiguredBaseModel): title="value", description="""The value for each option in choices or in additionalNotesObj""", ) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") class VideoObject(MediaObject): contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None) - category: Optional[str] = Field(None) + id: Optional[str] = Field(None, description="""A unique identifier for an item.""") + category: Optional[str] = Field(None, description="""A specific type of class.""") # Model rebuild # see https://pydantic-docs.helpmanual.io/usage/models/#rebuilding-a-model +Agent.model_rebuild() +CreativeWork.model_rebuild() +Activity.model_rebuild() AdditionalNoteObj.model_rebuild() AdditionalProperty.model_rebuild() -Agent.model_rebuild() Choice.model_rebuild() ComputeSpecification.model_rebuild() -CreativeWork.model_rebuild() -Activity.model_rebuild() Item.model_rebuild() LandingPage.model_rebuild() MediaObject.model_rebuild() @@ -643,7 +655,6 @@ class VideoObject(MediaObject): ResponseOption.model_rebuild() SoftwareAgent.model_rebuild() StructuredValue.model_rebuild() -Thing.model_rebuild() UI.model_rebuild() UnitOption.model_rebuild() VideoObject.model_rebuild() diff --git a/reproschema/models/tests/test_schema.py b/reproschema/models/tests/test_schema.py index a68e808..d5e9b0b 100644 --- a/reproschema/models/tests/test_schema.py +++ b/reproschema/models/tests/test_schema.py @@ -1,20 +1,9 @@ -from .. import Protocol, Activity, Item +from .. import Protocol, Activity, Item, ResponseOption +import pytest -def test_constructors(): - Protocol() - Activity() - Item() - version = "1.0.0-rc2" - proto = Protocol(version=version) - assert proto.schema["schemaVersion"] == version - act = Activity(version) - assert act.schema["schemaVersion"] == version - item = Item(version) - assert item.schema["schemaVersion"] == version - - -def test_constructors_from_data(): - Protocol.from_data({"@type": "reproschema:Protocol"}) - Activity.from_data({"@type": "reproschema:Activity"}) - Item.from_data({"@type": "reproschema:Field"}) +@pytest.mark.parametrize("model_class", [Protocol, Activity, Item, ResponseOption]) +def test_constructors(model_class): + ob = model_class() + assert hasattr(ob, "id") + assert hasattr(ob, "category") diff --git a/reproschema/tests/test_validate.py b/reproschema/tests/test_validate.py index 96e40db..43c4d08 100644 --- a/reproschema/tests/test_validate.py +++ b/reproschema/tests/test_validate.py @@ -5,15 +5,15 @@ def test_validate(): os.chdir(os.path.dirname(__file__)) - assert validate_dir("data", os.path.abspath("reproschema-shacl.ttl")) + assert validate_dir("data") def test_type_error(): os.chdir(os.path.dirname(__file__)) with pytest.raises(ValueError): - validate_dir("contexts", os.path.abspath("reproschema-shacl.ttl")) + validate_dir("contexts") def test_url(): url = "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc1/examples/activities/activity1.jsonld" - assert validate(os.path.abspath("reproschema-shacl.ttl"), url) + assert validate(url) diff --git a/reproschema/utils.py b/reproschema/utils.py index 36c754d..d08ba87 100644 --- a/reproschema/utils.py +++ b/reproschema/utils.py @@ -93,7 +93,7 @@ def _lang_fix(data_el): def _image_fix(data_el): if isinstance(data_el, dict): - if "@id" not in data_el: + if "@id" not in data_el and "@value" in data_el: data_el["@id"] = data_el.pop("@value") data_el.pop("@language", None) elif isinstance(data_el, list) and len(data_el) == 1: diff --git a/reproschema/validate.py b/reproschema/validate.py index 638bb03..a4f7fec 100644 --- a/reproschema/validate.py +++ b/reproschema/validate.py @@ -25,6 +25,9 @@ def validate_dir(directory, started=False, http_kwargs={}): if any document is non-conformant. """ + if not os.path.isdir(directory): + raise Exception(f"{directory} is not a directory") + print(f"Validating directory {directory}") stop = None if not started: stop, port = start_server(**http_kwargs) @@ -39,6 +42,7 @@ def validate_dir(directory, started=False, http_kwargs={}): data = load_file(full_file_name, started=True, http_kwargs=http_kwargs) if len(data) == 0: raise ValueError("Empty data graph") + print(f"Validating {full_file_name}") conforms, vtext = validate_data(data) except (ValueError,): if stop is not None: From 3c7049fa7c81b5b110cb687dffd2021b4849f80c Mon Sep 17 00:00:00 2001 From: yibeichan Date: Sat, 20 Apr 2024 21:33:27 -0400 Subject: [PATCH 14/27] fix conversion tests --- reproschema/redcap2reproschema.py | 2 - reproschema/reproschema2redcap.py | 13 +- reproschema/tests/test_redcap2reproschema.py | 26 ++-- .../tests/test_redcap2rs_data/redcap2rs.yaml | 9 +- reproschema/tests/test_reproschema2redcap.py | 18 ++- templates/redcap2rs.yaml | 2 + .../autism_parenting_stress_index_apsi_schema | 124 ++++++++++++++++++ .../items/apsi_accepted | 38 ++++++ .../items/apsi_agressive | 38 ++++++ .../items/apsi_bowel | 38 ++++++ .../items/apsi_communicate | 38 ++++++ .../items/apsi_date | 19 +++ .../items/apsi_diet | 38 ++++++ .../items/apsi_independently | 38 ++++++ .../items/apsi_name_of_child | 16 +++ .../items/apsi_not_close | 38 ++++++ .../items/apsi_person_completing | 16 +++ .../items/apsi_potty | 38 ++++++ .../items/apsi_self_injure | 38 ++++++ .../items/apsi_sleep | 38 ++++++ .../items/apsi_social_dev | 41 ++++++ .../items/apsi_tantrums | 38 ++++++ .../items/apsi_total | 16 +++ .../items/apsi_transitions | 38 ++++++ .../items/record_id | 16 +++ ...ffective_mindfulness_scalerevised_c_schema | 88 +++++++++++++ .../items/cams_r_1 | 37 ++++++ .../items/cams_r_10 | 34 +++++ .../items/cams_r_11 | 34 +++++ .../items/cams_r_12 | 34 +++++ .../items/cams_r_2 | 34 +++++ .../items/cams_r_3 | 34 +++++ .../items/cams_r_4 | 34 +++++ .../items/cams_r_5 | 34 +++++ .../items/cams_r_6 | 34 +++++ .../items/cams_r_7 | 34 +++++ .../items/cams_r_8 | 34 +++++ .../items/cams_r_9 | 34 +++++ .../test_redcap2rs/test_redcap2rs_schema | 31 +++++ 39 files changed, 1273 insertions(+), 31 deletions(-) create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions create mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 create mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 create mode 100644 test_redcap2rs/test_redcap2rs/test_redcap2rs_schema diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index d7d881c..799a795 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -8,7 +8,6 @@ matrix_group_count = {} - def clean_header(header): cleaned_header = {} for k, v in header.items(): @@ -17,7 +16,6 @@ def clean_header(header): cleaned_header[cleaned_key] = v return cleaned_header - def normalize_condition(condition_str): # Regular expressions for various pattern replacements re_parentheses = re.compile(r"\(([0-9]*)\)") diff --git a/reproschema/reproschema2redcap.py b/reproschema/reproschema2redcap.py index 3d03cf3..3e1af67 100644 --- a/reproschema/reproschema2redcap.py +++ b/reproschema/reproschema2redcap.py @@ -142,6 +142,7 @@ def get_csv_data(dir_path): if protocol_dir.is_dir(): # Check for a _schema file in each directory schema_file = next(protocol_dir.glob("*_schema"), None) + print(f"Found schema file: {schema_file}") if schema_file: # Process the found _schema file parsed_protocol_json = read_json_file(schema_file) @@ -149,11 +150,10 @@ def get_csv_data(dir_path): activity_order = parsed_protocol_json.get("ui", {}).get("order", []) for relative_activity_path in activity_order: # Normalize the relative path and construct the absolute path - normalized_relative_path = Path( - relative_activity_path.lstrip("../") - ) - activity_path = dir_path / normalized_relative_path - print(f"Processing activity {activity_path}") + normalized_relative_path = Path(relative_activity_path.lstrip("../")) + + activity_path = dir_path / "activities" / normalized_relative_path / (normalized_relative_path.name + "_schema") + parsed_activity_json = read_json_file(activity_path) if parsed_activity_json: @@ -164,6 +164,7 @@ def get_csv_data(dir_path): if item_json: row_data = process_item(item_json, activity_path.stem) csv_data.append(row_data) + print(f"Processed item {item_path}") # Break after finding the first _schema file break @@ -239,4 +240,4 @@ def main(input_dir_path, output_csv_filename): sys.exit(1) input_dir_path = Path(sys.argv[1]) output_csv_filename = sys.argv[2] - main(input_dir_path, output_csv_filename) + main(input_dir_path, output_csv_filename) \ No newline at end of file diff --git a/reproschema/tests/test_redcap2reproschema.py b/reproschema/tests/test_redcap2reproschema.py index 2386a8c..2486714 100644 --- a/reproschema/tests/test_redcap2reproschema.py +++ b/reproschema/tests/test_redcap2reproschema.py @@ -1,10 +1,10 @@ import os import shutil import pytest +import yaml from click.testing import CliRunner -from ..cli import main # Import the Click group +from ..cli import main -# Assuming your test files are located in a 'tests' directory CSV_FILE_NAME = "redcap_dict.csv" YAML_FILE_NAME = "redcap2rs.yaml" CSV_TEST_FILE = os.path.join( @@ -14,18 +14,24 @@ os.path.dirname(__file__), "test_redcap2rs_data", YAML_FILE_NAME ) - -def test_redcap2reproschema_success(): +def test_redcap2reproschema_success(tmpdir): runner = CliRunner() - with runner.isolated_filesystem(): - # Copy the test files to the isolated filesystem - shutil.copy(CSV_TEST_FILE, CSV_FILE_NAME) - shutil.copy(YAML_TEST_FILE, YAML_FILE_NAME) + # Copy the test files to the custom temporary directory + shutil.copy(CSV_TEST_FILE, tmpdir.join(CSV_FILE_NAME)) + shutil.copy(YAML_TEST_FILE, tmpdir.join(YAML_FILE_NAME)) + + # Set the working directory to tmpdir + with tmpdir.as_cwd(): + # Read YAML to find the expected output directory name + with open(YAML_FILE_NAME, 'r') as file: + protocol = yaml.safe_load(file) + protocol_name = protocol.get("protocol_name", "").replace(" ", "_") - # Run the command within the isolated filesystem result = runner.invoke( main, ["redcap2reproschema", CSV_FILE_NAME, YAML_FILE_NAME] ) - print(result.output) + + # Assertions assert result.exit_code == 0 + assert os.path.isdir(protocol_name), f"Expected output directory '{protocol_name}' does not exist" diff --git a/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml b/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml index 3330f3b..c201323 100644 --- a/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml +++ b/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml @@ -9,13 +9,8 @@ protocol_name: "test_redcap2rs" # Example: "My_Protocol" # This name will be displayed in the application. protocol_display_name: "redcap protocols" -# GitHub Repository Information: -# Create a GitHub repository named 'reproschema' to store your reproschema protocols. -# Replace 'your_github_username' with your actual GitHub username. -user_name: "yibeichan" -repo_name: "redcap2reproschema" # Recommended name; can be different if preferred. -repo_url: "https://github.com/{{user_name}}/{{repo_name}}" - # Protocol Description: # Provide a brief description of your protocol. protocol_description: "testing" # Example: "This protocol is for ..." + +redcap_version: "3.0.0" \ No newline at end of file diff --git a/reproschema/tests/test_reproschema2redcap.py b/reproschema/tests/test_reproschema2redcap.py index f0a02ce..5860121 100644 --- a/reproschema/tests/test_reproschema2redcap.py +++ b/reproschema/tests/test_reproschema2redcap.py @@ -2,23 +2,26 @@ import pytest from click.testing import CliRunner from ..cli import main -from shutil import copytree +from shutil import copytree, rmtree from pathlib import Path import csv - +import tempfile def test_reproschema2redcap_success(): runner = CliRunner() with runner.isolated_filesystem(): + # Create a temporary directory for output + temp_dir = tempfile.mkdtemp(dir='.') + print(f"Temporary directory: {temp_dir}") # Copy necessary test data into the isolated filesystem original_data_dir = os.path.join( - os.path.dirname(__file__), "test_rs2redcap_data" + os.path.dirname(__file__), "test_rs2redcap_data", "test_redcap2rs" ) copytree(original_data_dir, "input_data") input_path = Path("input_data") # Using Path object - output_csv_path = "output.csv" + output_csv_path = os.path.join(temp_dir, "output.csv") # Invoke the reproschema2redcap command result = runner.invoke( @@ -43,5 +46,8 @@ def test_reproschema2redcap_success(): print(row) # Optionally, assert conditions about the CSV contents - # For example, assert that the file is not empty - assert len(csv_contents) > 0 + # For example, assert that the file has more than just headers + assert len(csv_contents) > 1 # More than one row indicates content beyond headers + + # Clean up temporary directory after use (optional) + # rmtree(temp_dir) \ No newline at end of file diff --git a/templates/redcap2rs.yaml b/templates/redcap2rs.yaml index 1e1dbc3..aa2f831 100644 --- a/templates/redcap2rs.yaml +++ b/templates/redcap2rs.yaml @@ -12,3 +12,5 @@ protocol_display_name: "Your protocol display name" # Protocol Description: # Provide a brief description of your protocol. protocol_description: "Description for your protocol" # Example: "This protocol is for ..." + +redcap_version: "x.y.z" # Example: "3.0.0" \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema new file mode 100644 index 0000000..fff03c4 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema @@ -0,0 +1,124 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Activity", + "@id": "autism_parenting_stress_index_apsi_schema", + "prefLabel": "autism_parenting_stress_index_apsi", + "description": "Default description", + "schemaVersion": "1.0.0-rc4", + "version": "3.0.0", + "ui": { + "order": [ + "items/record_id", + "items/apsi_date", + "items/apsi_name_of_child", + "items/apsi_person_completing", + "items/apsi_social_dev", + "items/apsi_communicate", + "items/apsi_tantrums", + "items/apsi_agressive", + "items/apsi_self_injure", + "items/apsi_transitions", + "items/apsi_sleep", + "items/apsi_diet", + "items/apsi_bowel", + "items/apsi_potty", + "items/apsi_not_close", + "items/apsi_accepted", + "items/apsi_independently", + "items/apsi_total" + ], + "addProperties": [ + { + "variableName": "record_id", + "isAbout": "items/record_id", + "isVis": true + }, + { + "variableName": "apsi_date", + "isAbout": "items/apsi_date", + "isVis": true + }, + { + "variableName": "apsi_name_of_child", + "isAbout": "items/apsi_name_of_child", + "isVis": true + }, + { + "variableName": "apsi_person_completing", + "isAbout": "items/apsi_person_completing", + "isVis": true + }, + { + "variableName": "apsi_social_dev", + "isAbout": "items/apsi_social_dev", + "isVis": true + }, + { + "variableName": "apsi_communicate", + "isAbout": "items/apsi_communicate", + "isVis": true + }, + { + "variableName": "apsi_tantrums", + "isAbout": "items/apsi_tantrums", + "isVis": true + }, + { + "variableName": "apsi_agressive", + "isAbout": "items/apsi_agressive", + "isVis": true + }, + { + "variableName": "apsi_self_injure", + "isAbout": "items/apsi_self_injure", + "isVis": true + }, + { + "variableName": "apsi_transitions", + "isAbout": "items/apsi_transitions", + "isVis": true + }, + { + "variableName": "apsi_sleep", + "isAbout": "items/apsi_sleep", + "isVis": true + }, + { + "variableName": "apsi_diet", + "isAbout": "items/apsi_diet", + "isVis": true + }, + { + "variableName": "apsi_bowel", + "isAbout": "items/apsi_bowel", + "isVis": true + }, + { + "variableName": "apsi_potty", + "isAbout": "items/apsi_potty", + "isVis": true + }, + { + "variableName": "apsi_not_close", + "isAbout": "items/apsi_not_close", + "isVis": true + }, + { + "variableName": "apsi_accepted", + "isAbout": "items/apsi_accepted", + "isVis": true + }, + { + "variableName": "apsi_independently", + "isAbout": "items/apsi_independently", + "isVis": true + }, + { + "variableName": "apsi_total", + "isAbout": "items/apsi_total", + "isVis": true + } + ], + "shuffle": false + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted new file mode 100644 index 0000000..5833f48 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_accepted", + "prefLabel": "apsi_accepted", + "description": "apsi_accepted of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Concern for the future of your child being accepted by others" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive new file mode 100644 index 0000000..8717b1b --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_agressive", + "prefLabel": "apsi_agressive", + "description": "apsi_agressive of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Aggressive behavior (siblings, peers)" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel new file mode 100644 index 0000000..7b06f0f --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_bowel", + "prefLabel": "apsi_bowel", + "description": "apsi_bowel of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Bowel problems (diarrhea, constipation)" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate new file mode 100644 index 0000000..cc0bada --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_communicate", + "prefLabel": "apsi_communicate", + "description": "apsi_communicate of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Your child's ability to communicate" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date new file mode 100644 index 0000000..4af48ba --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date @@ -0,0 +1,19 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_date", + "prefLabel": "apsi_date", + "description": "apsi_date of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "text" + }, + "responseOptions": { + "valueType": "xsd:string" + }, + "preamble": { + "en": "Autism Parenting Stress Index for the Qigong Sensory Training Program Instructions: 1. Before beginning Qigong Sensory Training therapy with your child, complete the form on the following page. 2. Enter the date, name of your child, and who is completing the checklist. (It is very important that the same parent/caretaker complete the form each time the form is used.) 3. Choose the response for each item that most accurately describes your child. 4. Add all of the numbers chosen. 5. Enter total into the space provided. After using Qigong Sensory Training therapy on your child once a day for a five months, have the same parent complete the form again. Total numbers circled. Compare this number to the number at the beginning. If Qigong Sensory Training therapy is being implemented successfully, the total number should decrease over time." + }, + "question": { + "en": "Date:" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet new file mode 100644 index 0000000..f1bb04c --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_diet", + "prefLabel": "apsi_diet", + "description": "apsi_diet of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Your child's diet" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently new file mode 100644 index 0000000..0389638 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_independently", + "prefLabel": "apsi_independently", + "description": "apsi_independently of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Concern for the future of your child living independently" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child new file mode 100644 index 0000000..195af9a --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child @@ -0,0 +1,16 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_name_of_child", + "prefLabel": "apsi_name_of_child", + "description": "apsi_name_of_child of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "text" + }, + "responseOptions": { + "valueType": "xsd:string" + }, + "question": { + "en": "Name of child:" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close new file mode 100644 index 0000000..a2b8fa7 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_not_close", + "prefLabel": "apsi_not_close", + "description": "apsi_not_close of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Not feeling close to your child" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing new file mode 100644 index 0000000..76cfd23 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing @@ -0,0 +1,16 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_person_completing", + "prefLabel": "apsi_person_completing", + "description": "apsi_person_completing of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "text" + }, + "responseOptions": { + "valueType": "xsd:string" + }, + "question": { + "en": "Person completing checklist:" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty new file mode 100644 index 0000000..6640aae --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_potty", + "prefLabel": "apsi_potty", + "description": "apsi_potty of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Potty training" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure new file mode 100644 index 0000000..29d8837 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_self_injure", + "prefLabel": "apsi_self_injure", + "description": "apsi_self_injure of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Self-injurious behavior" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep new file mode 100644 index 0000000..dbd01be --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_sleep", + "prefLabel": "apsi_sleep", + "description": "apsi_sleep of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Sleep problems" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev new file mode 100644 index 0000000..333be63 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev @@ -0,0 +1,41 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_social_dev", + "prefLabel": "apsi_social_dev", + "description": "apsi_social_dev of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "preamble": { + "en": "Stress Ratings Please rate the following aspects of your child'shealth according to how much stress it causes you and/or your familyby clicking on the button that best describes your situation." + }, + "question": { + "en": "Your child's social development" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums new file mode 100644 index 0000000..e07f99d --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_tantrums", + "prefLabel": "apsi_tantrums", + "description": "apsi_tantrums of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Tantrums/meltdowns" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total new file mode 100644 index 0000000..15328ec --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total @@ -0,0 +1,16 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_total", + "prefLabel": "apsi_total", + "description": "apsi_total of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "text" + }, + "responseOptions": { + "valueType": "xsd:string" + }, + "question": { + "en": "Total" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions new file mode 100644 index 0000000..ce9782c --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions @@ -0,0 +1,38 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "apsi_transitions", + "prefLabel": "apsi_transitions", + "description": "apsi_transitions of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "0 - Not stressful ", + "value": 0 + }, + { + "name": "1 - Sometimes creates stress ", + "value": 1 + }, + { + "name": "2 - Often creates stress ", + "value": 2 + }, + { + "name": "3 - Very stressful on a daily basis ", + "value": 3 + }, + { + "name": "5 - So stressful sometimes we feel we can't cope", + "value": 5 + } + ] + }, + "question": { + "en": "Difficulty making transitions from one activity to another" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id new file mode 100644 index 0000000..3971398 --- /dev/null +++ b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id @@ -0,0 +1,16 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "record_id", + "prefLabel": "record_id", + "description": "record_id of autism_parenting_stress_index_apsi", + "ui": { + "inputType": "text" + }, + "responseOptions": { + "valueType": "xsd:string" + }, + "question": { + "en": "Record ID" + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema new file mode 100644 index 0000000..ed06073 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema @@ -0,0 +1,88 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Activity", + "@id": "cognitive_and_affective_mindfulness_scalerevised_c_schema", + "prefLabel": "cognitive_and_affective_mindfulness_scalerevised_c", + "description": "Default description", + "schemaVersion": "1.0.0-rc4", + "version": "3.0.0", + "ui": { + "order": [ + "items/cams_r_1", + "items/cams_r_2", + "items/cams_r_3", + "items/cams_r_4", + "items/cams_r_5", + "items/cams_r_6", + "items/cams_r_7", + "items/cams_r_8", + "items/cams_r_9", + "items/cams_r_10", + "items/cams_r_11", + "items/cams_r_12" + ], + "addProperties": [ + { + "variableName": "cams_r_1", + "isAbout": "items/cams_r_1", + "isVis": true + }, + { + "variableName": "cams_r_2", + "isAbout": "items/cams_r_2", + "isVis": true + }, + { + "variableName": "cams_r_3", + "isAbout": "items/cams_r_3", + "isVis": true + }, + { + "variableName": "cams_r_4", + "isAbout": "items/cams_r_4", + "isVis": true + }, + { + "variableName": "cams_r_5", + "isAbout": "items/cams_r_5", + "isVis": true + }, + { + "variableName": "cams_r_6", + "isAbout": "items/cams_r_6", + "isVis": true + }, + { + "variableName": "cams_r_7", + "isAbout": "items/cams_r_7", + "isVis": true + }, + { + "variableName": "cams_r_8", + "isAbout": "items/cams_r_8", + "isVis": true + }, + { + "variableName": "cams_r_9", + "isAbout": "items/cams_r_9", + "isVis": true + }, + { + "variableName": "cams_r_10", + "isAbout": "items/cams_r_10", + "isVis": true + }, + { + "variableName": "cams_r_11", + "isAbout": "items/cams_r_11", + "isVis": true + }, + { + "variableName": "cams_r_12", + "isAbout": "items/cams_r_12", + "isVis": true + } + ], + "shuffle": false + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 new file mode 100644 index 0000000..433ff0b --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 @@ -0,0 +1,37 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_1", + "prefLabel": "cams_r_1", + "description": "cams_r_1 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "preamble": { + "en": "Instructions: People have a variety of ways of relating to their thoughts and feelings. For each of the items below, rate how much each of these ways applies to you." + }, + "question": { + "en": "1. It is easy for me to concentrate on what I am doing." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 new file mode 100644 index 0000000..2d39b9e --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_10", + "prefLabel": "cams_r_10", + "description": "cams_r_10 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "10. I am able to accept the thoughts and feelings I have." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 new file mode 100644 index 0000000..cd236fb --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_11", + "prefLabel": "cams_r_11", + "description": "cams_r_11 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "11. I am able to focus on the present moment." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 new file mode 100644 index 0000000..69c0020 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_12", + "prefLabel": "cams_r_12", + "description": "cams_r_12 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "12. I am able to pay close attention to one thing for a long period of time." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 new file mode 100644 index 0000000..701fe6f --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_2", + "prefLabel": "cams_r_2", + "description": "cams_r_2 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "2. I am preoccupied by the future." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 new file mode 100644 index 0000000..3bf5196 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_3", + "prefLabel": "cams_r_3", + "description": "cams_r_3 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "3. I can tolerate emotional pain." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 new file mode 100644 index 0000000..85598a5 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_4", + "prefLabel": "cams_r_4", + "description": "cams_r_4 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "4. I can accept things I cannot change." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 new file mode 100644 index 0000000..8df3dc3 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_5", + "prefLabel": "cams_r_5", + "description": "cams_r_5 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "5. I can usually describe how I feel at the moment in considerable detail." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 new file mode 100644 index 0000000..ee98bb5 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_6", + "prefLabel": "cams_r_6", + "description": "cams_r_6 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "6. I am easily distracted." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 new file mode 100644 index 0000000..8f264e2 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_7", + "prefLabel": "cams_r_7", + "description": "cams_r_7 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "7. I am preoccupied by the past." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 new file mode 100644 index 0000000..7bae21c --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_8", + "prefLabel": "cams_r_8", + "description": "cams_r_8 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "8. It's easy for me to keep track of my thoughts and feelings." + } +} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 new file mode 100644 index 0000000..2b628a7 --- /dev/null +++ b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 @@ -0,0 +1,34 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Item", + "@id": "cams_r_9", + "prefLabel": "cams_r_9", + "description": "cams_r_9 of cognitive_and_affective_mindfulness_scalerevised_c", + "ui": { + "inputType": "radio" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": "1 - Rarely/Not at all ", + "value": 1 + }, + { + "name": "2 - Sometimes ", + "value": 2 + }, + { + "name": "3 - Often ", + "value": 3 + }, + { + "name": "4 - Almost Always", + "value": 4 + } + ] + }, + "question": { + "en": "9. I try to notice my thoughts without judging them." + } +} \ No newline at end of file diff --git a/test_redcap2rs/test_redcap2rs/test_redcap2rs_schema b/test_redcap2rs/test_redcap2rs/test_redcap2rs_schema new file mode 100644 index 0000000..423c39b --- /dev/null +++ b/test_redcap2rs/test_redcap2rs/test_redcap2rs_schema @@ -0,0 +1,31 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", + "@type": "reproschema:Protocol", + "@id": "test_redcap2rs_schema", + "prefLabel": "redcap protocols", + "altLabel": "test_redcap2rs_schema", + "description": "testing", + "schemaVersion": "1.0.0-rc4", + "version": "3.0.0", + "ui": { + "addProperties": [ + { + "isAbout": "../activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema", + "variableName": "autism_parenting_stress_index_apsi_schema", + "prefLabel": "Autism Parenting Stress Index Apsi", + "isVis": true + }, + { + "isAbout": "../activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema", + "variableName": "cognitive_and_affective_mindfulness_scalerevised_c_schema", + "prefLabel": "Cognitive And Affective Mindfulness Scalerevised C", + "isVis": true + } + ], + "order": [ + "../activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema", + "../activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema" + ], + "shuffle": false + } +} \ No newline at end of file From a60612fc96369c1bcdeb1655aee2a02355eb7810 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Sat, 20 Apr 2024 21:34:38 -0400 Subject: [PATCH 15/27] remove test output --- .../autism_parenting_stress_index_apsi_schema | 124 ------------------ .../items/apsi_accepted | 38 ------ .../items/apsi_agressive | 38 ------ .../items/apsi_bowel | 38 ------ .../items/apsi_communicate | 38 ------ .../items/apsi_date | 19 --- .../items/apsi_diet | 38 ------ .../items/apsi_independently | 38 ------ .../items/apsi_name_of_child | 16 --- .../items/apsi_not_close | 38 ------ .../items/apsi_person_completing | 16 --- .../items/apsi_potty | 38 ------ .../items/apsi_self_injure | 38 ------ .../items/apsi_sleep | 38 ------ .../items/apsi_social_dev | 41 ------ .../items/apsi_tantrums | 38 ------ .../items/apsi_total | 16 --- .../items/apsi_transitions | 38 ------ .../items/record_id | 16 --- ...ffective_mindfulness_scalerevised_c_schema | 88 ------------- .../items/cams_r_1 | 37 ------ .../items/cams_r_10 | 34 ----- .../items/cams_r_11 | 34 ----- .../items/cams_r_12 | 34 ----- .../items/cams_r_2 | 34 ----- .../items/cams_r_3 | 34 ----- .../items/cams_r_4 | 34 ----- .../items/cams_r_5 | 34 ----- .../items/cams_r_6 | 34 ----- .../items/cams_r_7 | 34 ----- .../items/cams_r_8 | 34 ----- .../items/cams_r_9 | 34 ----- .../test_redcap2rs/test_redcap2rs_schema | 31 ----- 33 files changed, 1234 deletions(-) delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions delete mode 100644 test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 delete mode 100644 test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 delete mode 100644 test_redcap2rs/test_redcap2rs/test_redcap2rs_schema diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema deleted file mode 100644 index fff03c4..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema +++ /dev/null @@ -1,124 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Activity", - "@id": "autism_parenting_stress_index_apsi_schema", - "prefLabel": "autism_parenting_stress_index_apsi", - "description": "Default description", - "schemaVersion": "1.0.0-rc4", - "version": "3.0.0", - "ui": { - "order": [ - "items/record_id", - "items/apsi_date", - "items/apsi_name_of_child", - "items/apsi_person_completing", - "items/apsi_social_dev", - "items/apsi_communicate", - "items/apsi_tantrums", - "items/apsi_agressive", - "items/apsi_self_injure", - "items/apsi_transitions", - "items/apsi_sleep", - "items/apsi_diet", - "items/apsi_bowel", - "items/apsi_potty", - "items/apsi_not_close", - "items/apsi_accepted", - "items/apsi_independently", - "items/apsi_total" - ], - "addProperties": [ - { - "variableName": "record_id", - "isAbout": "items/record_id", - "isVis": true - }, - { - "variableName": "apsi_date", - "isAbout": "items/apsi_date", - "isVis": true - }, - { - "variableName": "apsi_name_of_child", - "isAbout": "items/apsi_name_of_child", - "isVis": true - }, - { - "variableName": "apsi_person_completing", - "isAbout": "items/apsi_person_completing", - "isVis": true - }, - { - "variableName": "apsi_social_dev", - "isAbout": "items/apsi_social_dev", - "isVis": true - }, - { - "variableName": "apsi_communicate", - "isAbout": "items/apsi_communicate", - "isVis": true - }, - { - "variableName": "apsi_tantrums", - "isAbout": "items/apsi_tantrums", - "isVis": true - }, - { - "variableName": "apsi_agressive", - "isAbout": "items/apsi_agressive", - "isVis": true - }, - { - "variableName": "apsi_self_injure", - "isAbout": "items/apsi_self_injure", - "isVis": true - }, - { - "variableName": "apsi_transitions", - "isAbout": "items/apsi_transitions", - "isVis": true - }, - { - "variableName": "apsi_sleep", - "isAbout": "items/apsi_sleep", - "isVis": true - }, - { - "variableName": "apsi_diet", - "isAbout": "items/apsi_diet", - "isVis": true - }, - { - "variableName": "apsi_bowel", - "isAbout": "items/apsi_bowel", - "isVis": true - }, - { - "variableName": "apsi_potty", - "isAbout": "items/apsi_potty", - "isVis": true - }, - { - "variableName": "apsi_not_close", - "isAbout": "items/apsi_not_close", - "isVis": true - }, - { - "variableName": "apsi_accepted", - "isAbout": "items/apsi_accepted", - "isVis": true - }, - { - "variableName": "apsi_independently", - "isAbout": "items/apsi_independently", - "isVis": true - }, - { - "variableName": "apsi_total", - "isAbout": "items/apsi_total", - "isVis": true - } - ], - "shuffle": false - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted deleted file mode 100644 index 5833f48..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_accepted +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_accepted", - "prefLabel": "apsi_accepted", - "description": "apsi_accepted of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Concern for the future of your child being accepted by others" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive deleted file mode 100644 index 8717b1b..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_agressive +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_agressive", - "prefLabel": "apsi_agressive", - "description": "apsi_agressive of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Aggressive behavior (siblings, peers)" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel deleted file mode 100644 index 7b06f0f..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_bowel +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_bowel", - "prefLabel": "apsi_bowel", - "description": "apsi_bowel of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Bowel problems (diarrhea, constipation)" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate deleted file mode 100644 index cc0bada..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_communicate +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_communicate", - "prefLabel": "apsi_communicate", - "description": "apsi_communicate of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Your child's ability to communicate" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date deleted file mode 100644 index 4af48ba..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_date +++ /dev/null @@ -1,19 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_date", - "prefLabel": "apsi_date", - "description": "apsi_date of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "text" - }, - "responseOptions": { - "valueType": "xsd:string" - }, - "preamble": { - "en": "Autism Parenting Stress Index for the Qigong Sensory Training Program Instructions: 1. Before beginning Qigong Sensory Training therapy with your child, complete the form on the following page. 2. Enter the date, name of your child, and who is completing the checklist. (It is very important that the same parent/caretaker complete the form each time the form is used.) 3. Choose the response for each item that most accurately describes your child. 4. Add all of the numbers chosen. 5. Enter total into the space provided. After using Qigong Sensory Training therapy on your child once a day for a five months, have the same parent complete the form again. Total numbers circled. Compare this number to the number at the beginning. If Qigong Sensory Training therapy is being implemented successfully, the total number should decrease over time." - }, - "question": { - "en": "Date:" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet deleted file mode 100644 index f1bb04c..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_diet +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_diet", - "prefLabel": "apsi_diet", - "description": "apsi_diet of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Your child's diet" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently deleted file mode 100644 index 0389638..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_independently +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_independently", - "prefLabel": "apsi_independently", - "description": "apsi_independently of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Concern for the future of your child living independently" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child deleted file mode 100644 index 195af9a..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_name_of_child +++ /dev/null @@ -1,16 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_name_of_child", - "prefLabel": "apsi_name_of_child", - "description": "apsi_name_of_child of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "text" - }, - "responseOptions": { - "valueType": "xsd:string" - }, - "question": { - "en": "Name of child:" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close deleted file mode 100644 index a2b8fa7..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_not_close +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_not_close", - "prefLabel": "apsi_not_close", - "description": "apsi_not_close of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Not feeling close to your child" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing deleted file mode 100644 index 76cfd23..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_person_completing +++ /dev/null @@ -1,16 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_person_completing", - "prefLabel": "apsi_person_completing", - "description": "apsi_person_completing of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "text" - }, - "responseOptions": { - "valueType": "xsd:string" - }, - "question": { - "en": "Person completing checklist:" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty deleted file mode 100644 index 6640aae..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_potty +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_potty", - "prefLabel": "apsi_potty", - "description": "apsi_potty of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Potty training" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure deleted file mode 100644 index 29d8837..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_self_injure +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_self_injure", - "prefLabel": "apsi_self_injure", - "description": "apsi_self_injure of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Self-injurious behavior" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep deleted file mode 100644 index dbd01be..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_sleep +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_sleep", - "prefLabel": "apsi_sleep", - "description": "apsi_sleep of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Sleep problems" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev deleted file mode 100644 index 333be63..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_social_dev +++ /dev/null @@ -1,41 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_social_dev", - "prefLabel": "apsi_social_dev", - "description": "apsi_social_dev of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "preamble": { - "en": "Stress Ratings Please rate the following aspects of your child'shealth according to how much stress it causes you and/or your familyby clicking on the button that best describes your situation." - }, - "question": { - "en": "Your child's social development" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums deleted file mode 100644 index e07f99d..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_tantrums +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_tantrums", - "prefLabel": "apsi_tantrums", - "description": "apsi_tantrums of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Tantrums/meltdowns" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total deleted file mode 100644 index 15328ec..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_total +++ /dev/null @@ -1,16 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_total", - "prefLabel": "apsi_total", - "description": "apsi_total of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "text" - }, - "responseOptions": { - "valueType": "xsd:string" - }, - "question": { - "en": "Total" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions deleted file mode 100644 index ce9782c..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/apsi_transitions +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "apsi_transitions", - "prefLabel": "apsi_transitions", - "description": "apsi_transitions of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "0 - Not stressful ", - "value": 0 - }, - { - "name": "1 - Sometimes creates stress ", - "value": 1 - }, - { - "name": "2 - Often creates stress ", - "value": 2 - }, - { - "name": "3 - Very stressful on a daily basis ", - "value": 3 - }, - { - "name": "5 - So stressful sometimes we feel we can't cope", - "value": 5 - } - ] - }, - "question": { - "en": "Difficulty making transitions from one activity to another" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id b/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id deleted file mode 100644 index 3971398..0000000 --- a/test_redcap2rs/activities/autism_parenting_stress_index_apsi/items/record_id +++ /dev/null @@ -1,16 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "record_id", - "prefLabel": "record_id", - "description": "record_id of autism_parenting_stress_index_apsi", - "ui": { - "inputType": "text" - }, - "responseOptions": { - "valueType": "xsd:string" - }, - "question": { - "en": "Record ID" - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema deleted file mode 100644 index ed06073..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema +++ /dev/null @@ -1,88 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Activity", - "@id": "cognitive_and_affective_mindfulness_scalerevised_c_schema", - "prefLabel": "cognitive_and_affective_mindfulness_scalerevised_c", - "description": "Default description", - "schemaVersion": "1.0.0-rc4", - "version": "3.0.0", - "ui": { - "order": [ - "items/cams_r_1", - "items/cams_r_2", - "items/cams_r_3", - "items/cams_r_4", - "items/cams_r_5", - "items/cams_r_6", - "items/cams_r_7", - "items/cams_r_8", - "items/cams_r_9", - "items/cams_r_10", - "items/cams_r_11", - "items/cams_r_12" - ], - "addProperties": [ - { - "variableName": "cams_r_1", - "isAbout": "items/cams_r_1", - "isVis": true - }, - { - "variableName": "cams_r_2", - "isAbout": "items/cams_r_2", - "isVis": true - }, - { - "variableName": "cams_r_3", - "isAbout": "items/cams_r_3", - "isVis": true - }, - { - "variableName": "cams_r_4", - "isAbout": "items/cams_r_4", - "isVis": true - }, - { - "variableName": "cams_r_5", - "isAbout": "items/cams_r_5", - "isVis": true - }, - { - "variableName": "cams_r_6", - "isAbout": "items/cams_r_6", - "isVis": true - }, - { - "variableName": "cams_r_7", - "isAbout": "items/cams_r_7", - "isVis": true - }, - { - "variableName": "cams_r_8", - "isAbout": "items/cams_r_8", - "isVis": true - }, - { - "variableName": "cams_r_9", - "isAbout": "items/cams_r_9", - "isVis": true - }, - { - "variableName": "cams_r_10", - "isAbout": "items/cams_r_10", - "isVis": true - }, - { - "variableName": "cams_r_11", - "isAbout": "items/cams_r_11", - "isVis": true - }, - { - "variableName": "cams_r_12", - "isAbout": "items/cams_r_12", - "isVis": true - } - ], - "shuffle": false - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 deleted file mode 100644 index 433ff0b..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_1 +++ /dev/null @@ -1,37 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_1", - "prefLabel": "cams_r_1", - "description": "cams_r_1 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "preamble": { - "en": "Instructions: People have a variety of ways of relating to their thoughts and feelings. For each of the items below, rate how much each of these ways applies to you." - }, - "question": { - "en": "1. It is easy for me to concentrate on what I am doing." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 deleted file mode 100644 index 2d39b9e..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_10 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_10", - "prefLabel": "cams_r_10", - "description": "cams_r_10 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "10. I am able to accept the thoughts and feelings I have." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 deleted file mode 100644 index cd236fb..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_11 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_11", - "prefLabel": "cams_r_11", - "description": "cams_r_11 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "11. I am able to focus on the present moment." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 deleted file mode 100644 index 69c0020..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_12 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_12", - "prefLabel": "cams_r_12", - "description": "cams_r_12 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "12. I am able to pay close attention to one thing for a long period of time." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 deleted file mode 100644 index 701fe6f..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_2 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_2", - "prefLabel": "cams_r_2", - "description": "cams_r_2 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "2. I am preoccupied by the future." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 deleted file mode 100644 index 3bf5196..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_3 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_3", - "prefLabel": "cams_r_3", - "description": "cams_r_3 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "3. I can tolerate emotional pain." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 deleted file mode 100644 index 85598a5..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_4 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_4", - "prefLabel": "cams_r_4", - "description": "cams_r_4 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "4. I can accept things I cannot change." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 deleted file mode 100644 index 8df3dc3..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_5 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_5", - "prefLabel": "cams_r_5", - "description": "cams_r_5 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "5. I can usually describe how I feel at the moment in considerable detail." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 deleted file mode 100644 index ee98bb5..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_6 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_6", - "prefLabel": "cams_r_6", - "description": "cams_r_6 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "6. I am easily distracted." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 deleted file mode 100644 index 8f264e2..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_7 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_7", - "prefLabel": "cams_r_7", - "description": "cams_r_7 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "7. I am preoccupied by the past." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 deleted file mode 100644 index 7bae21c..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_8 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_8", - "prefLabel": "cams_r_8", - "description": "cams_r_8 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "8. It's easy for me to keep track of my thoughts and feelings." - } -} \ No newline at end of file diff --git a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 b/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 deleted file mode 100644 index 2b628a7..0000000 --- a/test_redcap2rs/activities/cognitive_and_affective_mindfulness_scalerevised_c/items/cams_r_9 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Item", - "@id": "cams_r_9", - "prefLabel": "cams_r_9", - "description": "cams_r_9 of cognitive_and_affective_mindfulness_scalerevised_c", - "ui": { - "inputType": "radio" - }, - "responseOptions": { - "valueType": "xsd:integer", - "choices": [ - { - "name": "1 - Rarely/Not at all ", - "value": 1 - }, - { - "name": "2 - Sometimes ", - "value": 2 - }, - { - "name": "3 - Often ", - "value": 3 - }, - { - "name": "4 - Almost Always", - "value": 4 - } - ] - }, - "question": { - "en": "9. I try to notice my thoughts without judging them." - } -} \ No newline at end of file diff --git a/test_redcap2rs/test_redcap2rs/test_redcap2rs_schema b/test_redcap2rs/test_redcap2rs/test_redcap2rs_schema deleted file mode 100644 index 423c39b..0000000 --- a/test_redcap2rs/test_redcap2rs/test_redcap2rs_schema +++ /dev/null @@ -1,31 +0,0 @@ -{ - "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/efb74e155c09e13aa009ea04609ba4f1152fcbc6/contexts/reproschema_new", - "@type": "reproschema:Protocol", - "@id": "test_redcap2rs_schema", - "prefLabel": "redcap protocols", - "altLabel": "test_redcap2rs_schema", - "description": "testing", - "schemaVersion": "1.0.0-rc4", - "version": "3.0.0", - "ui": { - "addProperties": [ - { - "isAbout": "../activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema", - "variableName": "autism_parenting_stress_index_apsi_schema", - "prefLabel": "Autism Parenting Stress Index Apsi", - "isVis": true - }, - { - "isAbout": "../activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema", - "variableName": "cognitive_and_affective_mindfulness_scalerevised_c_schema", - "prefLabel": "Cognitive And Affective Mindfulness Scalerevised C", - "isVis": true - } - ], - "order": [ - "../activities/autism_parenting_stress_index_apsi/autism_parenting_stress_index_apsi_schema", - "../activities/cognitive_and_affective_mindfulness_scalerevised_c/cognitive_and_affective_mindfulness_scalerevised_c_schema" - ], - "shuffle": false - } -} \ No newline at end of file From e1e847d342c1921fa422a8f96674bfcf16d860ea Mon Sep 17 00:00:00 2001 From: yibeichan Date: Sat, 20 Apr 2024 21:47:56 -0400 Subject: [PATCH 16/27] change test output directory --- reproschema/tests/test_redcap2reproschema.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/reproschema/tests/test_redcap2reproschema.py b/reproschema/tests/test_redcap2reproschema.py index 2486714..840ac4f 100644 --- a/reproschema/tests/test_redcap2reproschema.py +++ b/reproschema/tests/test_redcap2reproschema.py @@ -17,21 +17,27 @@ def test_redcap2reproschema_success(tmpdir): runner = CliRunner() - # Copy the test files to the custom temporary directory - shutil.copy(CSV_TEST_FILE, tmpdir.join(CSV_FILE_NAME)) - shutil.copy(YAML_TEST_FILE, tmpdir.join(YAML_FILE_NAME)) + # Define the paths to the CSV and YAML files in the temporary directory + temp_csv_file = tmpdir.join(CSV_FILE_NAME) + temp_yaml_file = tmpdir.join(YAML_FILE_NAME) - # Set the working directory to tmpdir + # Copy the test files to the temporary directory + shutil.copy(CSV_TEST_FILE, str(temp_csv_file)) # Convert to string + shutil.copy(YAML_TEST_FILE, str(temp_yaml_file)) # Convert to string + + # Change the current working directory to tmpdir with tmpdir.as_cwd(): # Read YAML to find the expected output directory name - with open(YAML_FILE_NAME, 'r') as file: + with open(str(temp_yaml_file), 'r') as file: # Convert to string protocol = yaml.safe_load(file) protocol_name = protocol.get("protocol_name", "").replace(" ", "_") + # Run the command with the path arguments pointing to the temp directory files result = runner.invoke( - main, ["redcap2reproschema", CSV_FILE_NAME, YAML_FILE_NAME] + main, ["redcap2reproschema", str(temp_csv_file), str(temp_yaml_file)] # Convert to string ) # Assertions - assert result.exit_code == 0 + assert result.exit_code == 0, f"The command failed to execute successfully: {result.output}" assert os.path.isdir(protocol_name), f"Expected output directory '{protocol_name}' does not exist" + print("Command output:", result.output) \ No newline at end of file From 51d30b7bd1a0203ebe28622e7eeebd3d61fa1413 Mon Sep 17 00:00:00 2001 From: yibeichan Date: Sat, 20 Apr 2024 21:54:53 -0400 Subject: [PATCH 17/27] final improvments on tests --- reproschema/redcap2reproschema.py | 3 ++- reproschema/reproschema2redcap.py | 1 - reproschema/tests/test_redcap2reproschema.py | 7 +------ reproschema/tests/test_reproschema2redcap.py | 22 ++++---------------- 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index 799a795..253c6b5 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -16,6 +16,7 @@ def clean_header(header): cleaned_header[cleaned_key] = v return cleaned_header + def normalize_condition(condition_str): # Regular expressions for various pattern replacements re_parentheses = re.compile(r"\(([0-9]*)\)") @@ -42,6 +43,7 @@ def normalize_condition(condition_str): return condition_str.strip() + def process_visibility(data): condition = data.get("Branching Logic (Show field only if...)") if condition: @@ -94,7 +96,6 @@ def parse_field_type_and_value(field, input_type_map): return input_type, value_type - def process_choices(field_type, choices_str): if field_type not in ["radio", "dropdown"]: # Handle only radio and dropdown types return None diff --git a/reproschema/reproschema2redcap.py b/reproschema/reproschema2redcap.py index 3e1af67..ffb7eea 100644 --- a/reproschema/reproschema2redcap.py +++ b/reproschema/reproschema2redcap.py @@ -164,7 +164,6 @@ def get_csv_data(dir_path): if item_json: row_data = process_item(item_json, activity_path.stem) csv_data.append(row_data) - print(f"Processed item {item_path}") # Break after finding the first _schema file break diff --git a/reproschema/tests/test_redcap2reproschema.py b/reproschema/tests/test_redcap2reproschema.py index 840ac4f..4dff719 100644 --- a/reproschema/tests/test_redcap2reproschema.py +++ b/reproschema/tests/test_redcap2reproschema.py @@ -14,14 +14,12 @@ os.path.dirname(__file__), "test_redcap2rs_data", YAML_FILE_NAME ) -def test_redcap2reproschema_success(tmpdir): +def test_redcap2reproschema(tmpdir): runner = CliRunner() - # Define the paths to the CSV and YAML files in the temporary directory temp_csv_file = tmpdir.join(CSV_FILE_NAME) temp_yaml_file = tmpdir.join(YAML_FILE_NAME) - # Copy the test files to the temporary directory shutil.copy(CSV_TEST_FILE, str(temp_csv_file)) # Convert to string shutil.copy(YAML_TEST_FILE, str(temp_yaml_file)) # Convert to string @@ -32,12 +30,9 @@ def test_redcap2reproschema_success(tmpdir): protocol = yaml.safe_load(file) protocol_name = protocol.get("protocol_name", "").replace(" ", "_") - # Run the command with the path arguments pointing to the temp directory files result = runner.invoke( main, ["redcap2reproschema", str(temp_csv_file), str(temp_yaml_file)] # Convert to string ) - # Assertions assert result.exit_code == 0, f"The command failed to execute successfully: {result.output}" assert os.path.isdir(protocol_name), f"Expected output directory '{protocol_name}' does not exist" - print("Command output:", result.output) \ No newline at end of file diff --git a/reproschema/tests/test_reproschema2redcap.py b/reproschema/tests/test_reproschema2redcap.py index 5860121..c652d3d 100644 --- a/reproschema/tests/test_reproschema2redcap.py +++ b/reproschema/tests/test_reproschema2redcap.py @@ -5,49 +5,35 @@ from shutil import copytree, rmtree from pathlib import Path import csv -import tempfile -def test_reproschema2redcap_success(): +def test_reproschema2redcap(tmpdir): runner = CliRunner() with runner.isolated_filesystem(): - # Create a temporary directory for output - temp_dir = tempfile.mkdtemp(dir='.') - print(f"Temporary directory: {temp_dir}") # Copy necessary test data into the isolated filesystem original_data_dir = os.path.join( os.path.dirname(__file__), "test_rs2redcap_data", "test_redcap2rs" ) copytree(original_data_dir, "input_data") - input_path = Path("input_data") # Using Path object - output_csv_path = os.path.join(temp_dir, "output.csv") + input_path = Path("input_data") + output_csv_path = os.path.join(tmpdir, "output.csv") - # Invoke the reproschema2redcap command result = runner.invoke( main, ["reproschema2redcap", str(input_path), output_csv_path] ) - # Print the output for debugging print(result.output) - # Assert the expected outcomes assert result.exit_code == 0 - # Check if the output CSV file has been created assert os.path.exists(output_csv_path) - # Read and print the contents of the CSV file with open(output_csv_path, "r", encoding="utf-8") as csv_file: reader = csv.reader(csv_file) csv_contents = list(reader) - print("CSV File Contents:") - for row in csv_contents: - print(row) - # Optionally, assert conditions about the CSV contents - # For example, assert that the file has more than just headers assert len(csv_contents) > 1 # More than one row indicates content beyond headers # Clean up temporary directory after use (optional) - # rmtree(temp_dir) \ No newline at end of file + # rmtree(tmpdir) \ No newline at end of file From ab7c051dbd4ebfce92917ce154a8053343a011e7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 21 Apr 2024 02:02:04 +0000 Subject: [PATCH 18/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- reproschema/redcap2reproschema.py | 28 +++++++++++-------- reproschema/reproschema2redcap.py | 15 +++++++--- reproschema/tests/test_redcap2reproschema.py | 20 +++++++++---- .../tests/test_redcap2rs_data/redcap2rs.yaml | 2 +- reproschema/tests/test_reproschema2redcap.py | 9 ++++-- templates/redcap2rs.yaml | 2 +- 6 files changed, 50 insertions(+), 26 deletions(-) diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index 253c6b5..e7f67c7 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -8,11 +8,12 @@ matrix_group_count = {} + def clean_header(header): cleaned_header = {} for k, v in header.items(): # Strip BOM, whitespace, and enclosing quotation marks if present - cleaned_key = k.lstrip('\ufeff').strip().strip('"') + cleaned_key = k.lstrip("\ufeff").strip().strip('"') cleaned_header[cleaned_key] = v return cleaned_header @@ -24,7 +25,7 @@ def normalize_condition(condition_str): re_brackets = re.compile(r"\[([^\]]*)\]") re_extra_spaces = re.compile(r"\s+") re_double_quotes = re.compile(r'"') - re_or = re.compile(r'\bor\b') # Match 'or' as whole word + re_or = re.compile(r"\bor\b") # Match 'or' as whole word # Apply regex replacements condition_str = re_parentheses.sub(r"___\1", condition_str) @@ -32,16 +33,20 @@ def normalize_condition(condition_str): condition_str = re_brackets.sub(r" \1 ", condition_str) # Replace 'or' with '||', ensuring not to replace '||' - condition_str = re_or.sub('||', condition_str) + condition_str = re_or.sub("||", condition_str) # Replace 'and' with '&&' condition_str = condition_str.replace(" and ", " && ") # Trim extra spaces and replace double quotes with single quotes - condition_str = re_extra_spaces.sub(' ', condition_str).strip() # Reduce multiple spaces to a single space - condition_str = re_double_quotes.sub("'", condition_str) # Replace double quotes with single quotes + condition_str = re_extra_spaces.sub( + " ", condition_str + ).strip() # Reduce multiple spaces to a single space + condition_str = re_double_quotes.sub( + "'", condition_str + ) # Replace double quotes with single quotes - return condition_str.strip() + return condition_str.strip() def process_visibility(data): @@ -116,7 +121,7 @@ def process_choices(field_type, choices_str): value = parts[0] choice_obj = {"name": " ".join(parts[1:]), "value": value} - # remove image for now + # remove image for now # if len(parts) == 3: # # Handle image url # choice_obj["image"] = f"{parts[2]}.png" @@ -204,10 +209,7 @@ def process_row( } for key, value in field.items(): - if ( - schema_map.get(key) in ["question", "description", "preamble"] - and value - ): + if schema_map.get(key) in ["question", "description", "preamble"] and value: rowData.update({schema_map[key]: parse_html(value)}) elif schema_map.get(key) == "allow" and value: @@ -349,7 +351,9 @@ def create_protocol_schema( "variableName": f"{activity}_schema", # Assuming activity name as prefLabel, update as needed "prefLabel": activity.replace("_", " ").title(), - "isVis": protocol_visibility_obj.get(activity, True), # Default to True if not specified + "isVis": protocol_visibility_obj.get( + activity, True + ), # Default to True if not specified } protocol_schema["ui"]["addProperties"].append(add_property) # Add the full path to the order list diff --git a/reproschema/reproschema2redcap.py b/reproschema/reproschema2redcap.py index ffb7eea..298c56e 100644 --- a/reproschema/reproschema2redcap.py +++ b/reproschema/reproschema2redcap.py @@ -150,10 +150,17 @@ def get_csv_data(dir_path): activity_order = parsed_protocol_json.get("ui", {}).get("order", []) for relative_activity_path in activity_order: # Normalize the relative path and construct the absolute path - normalized_relative_path = Path(relative_activity_path.lstrip("../")) + normalized_relative_path = Path( + relative_activity_path.lstrip("../") + ) + + activity_path = ( + dir_path + / "activities" + / normalized_relative_path + / (normalized_relative_path.name + "_schema") + ) - activity_path = dir_path / "activities" / normalized_relative_path / (normalized_relative_path.name + "_schema") - parsed_activity_json = read_json_file(activity_path) if parsed_activity_json: @@ -239,4 +246,4 @@ def main(input_dir_path, output_csv_filename): sys.exit(1) input_dir_path = Path(sys.argv[1]) output_csv_filename = sys.argv[2] - main(input_dir_path, output_csv_filename) \ No newline at end of file + main(input_dir_path, output_csv_filename) diff --git a/reproschema/tests/test_redcap2reproschema.py b/reproschema/tests/test_redcap2reproschema.py index 4dff719..bbf2df7 100644 --- a/reproschema/tests/test_redcap2reproschema.py +++ b/reproschema/tests/test_redcap2reproschema.py @@ -3,7 +3,7 @@ import pytest import yaml from click.testing import CliRunner -from ..cli import main +from ..cli import main CSV_FILE_NAME = "redcap_dict.csv" YAML_FILE_NAME = "redcap2rs.yaml" @@ -14,6 +14,7 @@ os.path.dirname(__file__), "test_redcap2rs_data", YAML_FILE_NAME ) + def test_redcap2reproschema(tmpdir): runner = CliRunner() @@ -26,13 +27,22 @@ def test_redcap2reproschema(tmpdir): # Change the current working directory to tmpdir with tmpdir.as_cwd(): # Read YAML to find the expected output directory name - with open(str(temp_yaml_file), 'r') as file: # Convert to string + with open(str(temp_yaml_file), "r") as file: # Convert to string protocol = yaml.safe_load(file) protocol_name = protocol.get("protocol_name", "").replace(" ", "_") result = runner.invoke( - main, ["redcap2reproschema", str(temp_csv_file), str(temp_yaml_file)] # Convert to string + main, + [ + "redcap2reproschema", + str(temp_csv_file), + str(temp_yaml_file), + ], # Convert to string ) - assert result.exit_code == 0, f"The command failed to execute successfully: {result.output}" - assert os.path.isdir(protocol_name), f"Expected output directory '{protocol_name}' does not exist" + assert ( + result.exit_code == 0 + ), f"The command failed to execute successfully: {result.output}" + assert os.path.isdir( + protocol_name + ), f"Expected output directory '{protocol_name}' does not exist" diff --git a/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml b/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml index c201323..95d4a9c 100644 --- a/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml +++ b/reproschema/tests/test_redcap2rs_data/redcap2rs.yaml @@ -13,4 +13,4 @@ protocol_display_name: "redcap protocols" # Provide a brief description of your protocol. protocol_description: "testing" # Example: "This protocol is for ..." -redcap_version: "3.0.0" \ No newline at end of file +redcap_version: "3.0.0" diff --git a/reproschema/tests/test_reproschema2redcap.py b/reproschema/tests/test_reproschema2redcap.py index c652d3d..eff26b3 100644 --- a/reproschema/tests/test_reproschema2redcap.py +++ b/reproschema/tests/test_reproschema2redcap.py @@ -6,6 +6,7 @@ from pathlib import Path import csv + def test_reproschema2redcap(tmpdir): runner = CliRunner() @@ -16,7 +17,7 @@ def test_reproschema2redcap(tmpdir): ) copytree(original_data_dir, "input_data") - input_path = Path("input_data") + input_path = Path("input_data") output_csv_path = os.path.join(tmpdir, "output.csv") result = runner.invoke( @@ -33,7 +34,9 @@ def test_reproschema2redcap(tmpdir): reader = csv.reader(csv_file) csv_contents = list(reader) - assert len(csv_contents) > 1 # More than one row indicates content beyond headers + assert ( + len(csv_contents) > 1 + ) # More than one row indicates content beyond headers # Clean up temporary directory after use (optional) - # rmtree(tmpdir) \ No newline at end of file + # rmtree(tmpdir) diff --git a/templates/redcap2rs.yaml b/templates/redcap2rs.yaml index aa2f831..4bbf78f 100644 --- a/templates/redcap2rs.yaml +++ b/templates/redcap2rs.yaml @@ -13,4 +13,4 @@ protocol_display_name: "Your protocol display name" # Provide a brief description of your protocol. protocol_description: "Description for your protocol" # Example: "This protocol is for ..." -redcap_version: "x.y.z" # Example: "3.0.0" \ No newline at end of file +redcap_version: "x.y.z" # Example: "3.0.0" From 0543e4172ea4a12a0d553b961286254b7fda30a9 Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Fri, 26 Apr 2024 22:03:47 -0400 Subject: [PATCH 19/27] model version after adding Thing class --- reproschema/models/model.py | 372 +++++++++++++++++++++++++----------- 1 file changed, 256 insertions(+), 116 deletions(-) diff --git a/reproschema/models/model.py b/reproschema/models/model.py index 3d50d80..89334ed 100644 --- a/reproschema/models/model.py +++ b/reproschema/models/model.py @@ -58,71 +58,27 @@ class Agent(ConfiguredBaseModel): pass -class CreativeWork(ConfiguredBaseModel): - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") - - -class Activity(CreativeWork): +class Participant(Agent): """ - An assessment in a protocol. + An Agent describing characteristics associated with a participant. """ - about: Optional[str] = Field( - None, description="""The subject matter of the Field.""" - ) - altLabel: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="alternate label", - description="""The alternate label.""", - ) - associatedMedia: Optional[str] = Field( + id: Optional[str] = Field( None, - title="associatedMedia", - description="""A media object that encodes this CreativeWork. This property is a synonym for encoding.""", - ) - citation: Optional[Dict[str, str]] = Field(default_factory=dict) - compute: Optional[List[ComputeSpecification]] = Field( - default_factory=list, - title="computation", - description="""An array of objects indicating computations in an activity or protocol and maps it to the corresponding Item. scoring logic is a subset of all computations that could be performed and not all computations will be scoring. For example, one may want to do conversion from one unit to another.""", - ) - cronTable: Optional[str] = Field( - None, title="cronTable", description="""TODO not described in reproschema""" + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) - description: Optional[Dict[str, str]] = Field(default_factory=dict) - image: Optional[Union[ImageObject, str]] = Field( - None, - title="image", - description="""An image of the item. This can be a URL or a fully described ImageObject.""", - ) - messages: Optional[List[MessageSpecification]] = Field( - default_factory=list, - title="messages", - description="""An array of objects to define conditional messages in an activity or protocol.""", - ) - preamble: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="Preamble", - description="""The preamble for an assessment""", - ) - prefLabel: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="preferred label", - description="""The preferred label.""", - ) - schemaVersion: Optional[str] = Field(None) - ui: Optional[UI] = Field( + subject_id: Optional[str] = Field(None) + + +class Thing(ConfiguredBaseModel): + id: Optional[str] = Field( None, - title="UI", - description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) - version: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + name: Optional[Dict[str, str]] = Field(default_factory=dict) -class AdditionalNoteObj(CreativeWork): +class AdditionalNoteObj(Thing): """ A set of objects to define notes in a Item. For example, most Redcap and NDA data dictionaries have notes for each item which needs to be captured in reproschema """ @@ -144,11 +100,14 @@ class AdditionalNoteObj(CreativeWork): title="value", description="""The value for each option in choices or in additionalNotesObj""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) -class AdditionalProperty(CreativeWork): +class AdditionalProperty(Thing): """ An object to describe the various properties added to assessments and Items. """ @@ -204,11 +163,14 @@ class AdditionalProperty(CreativeWork): title="UI", description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) -class Choice(CreativeWork): +class Choice(Thing): """ An object to describe a response option. """ @@ -226,8 +188,90 @@ class Choice(CreativeWork): title="value", description="""The value for each option in choices or in additionalNotesObj""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + + +class CreativeWork(Thing): + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) + + +class Activity(CreativeWork): + """ + An assessment in a protocol. + """ + + about: Optional[str] = Field( + None, description="""The subject matter of the Field.""" + ) + altLabel: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="alternate label", + description="""The alternate label.""", + ) + associatedMedia: Optional[str] = Field( + None, + title="associatedMedia", + description="""A media object that encodes this CreativeWork. This property is a synonym for encoding.""", + ) + citation: Optional[Dict[str, str]] = Field(default_factory=dict) + compute: Optional[List[ComputeSpecification]] = Field( + default_factory=list, + title="computation", + description="""An array of objects indicating computations in an activity or protocol and maps it to the corresponding Item. scoring logic is a subset of all computations that could be performed and not all computations will be scoring. For example, one may want to do conversion from one unit to another.""", + ) + cronTable: Optional[str] = Field( + None, title="cronTable", description="""TODO not described in reproschema""" + ) + description: Optional[Dict[str, str]] = Field(default_factory=dict) + image: Optional[Union[ImageObject, str]] = Field( + None, + title="image", + description="""An image of the item. This can be a URL or a fully described ImageObject.""", + ) + messages: Optional[List[MessageSpecification]] = Field( + default_factory=list, + title="messages", + description="""An array of objects to define conditional messages in an activity or protocol.""", + ) + preamble: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="Preamble", + description="""The preamble for an assessment""", + ) + prefLabel: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="preferred label", + description="""The preferred label.""", + ) + schemaVersion: Optional[str] = Field(None) + ui: Optional[UI] = Field( + None, + title="UI", + description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", + ) + version: Optional[str] = Field(None) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class ComputeSpecification(CreativeWork): @@ -245,8 +289,16 @@ class ComputeSpecification(CreativeWork): title="variableName", description="""The name used to represent an item.""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class Item(CreativeWork): @@ -309,8 +361,16 @@ class Item(CreativeWork): ) version: Optional[str] = Field(None) video: Optional[VideoObject] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class LandingPage(CreativeWork): @@ -319,8 +379,16 @@ class LandingPage(CreativeWork): """ inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class MediaObject(CreativeWork): @@ -328,24 +396,45 @@ class MediaObject(CreativeWork): Add description """ - contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: str = Field(...) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class AudioObject(MediaObject): - contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: str = Field(...) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class ImageObject(MediaObject): - contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: str = Field(...) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class MessageSpecification(CreativeWork): @@ -363,11 +452,19 @@ class MessageSpecification(CreativeWork): title="Message", description="""The message to be conditionally displayed for an item.""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) -class OverrideProperty(CreativeWork): +class OverrideProperty(Thing): """ An object to override the various properties added to assessments and Items. """ @@ -413,17 +510,11 @@ class OverrideProperty(CreativeWork): title="variableName", description="""The name used to represent an item.""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") - - -class Participant(Agent): - """ - An Agent describing characteristics associated with a participant. - """ - - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - subject_id: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class Protocol(CreativeWork): @@ -475,8 +566,16 @@ class Protocol(CreativeWork): description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", ) version: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class Response(CreativeWork): @@ -497,8 +596,16 @@ class Response(CreativeWork): description="""The value for each option in choices or in additionalNotesObj""", ) wasAttributedTo: Optional[Participant] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class ResponseActivity(CreativeWork): @@ -512,8 +619,16 @@ class ResponseActivity(CreativeWork): startedAtTime: Optional[datetime] = Field(None) used: Optional[List[str]] = Field(default_factory=list) wasAssociatedWith: Optional[SoftwareAgent] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class ResponseOption(CreativeWork): @@ -548,24 +663,38 @@ class ResponseOption(CreativeWork): title="The type of the response", description="""The type of the response of an item. For example, string, integer, etc.""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) -class SoftwareAgent(CreativeWork): +class SoftwareAgent(Thing): """ Captures information about some action that took place. It also links to information (entities) that were used during the activity """ version: Optional[str] = Field(None) url: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) -class StructuredValue(CreativeWork): - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") +class StructuredValue(Thing): + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class UI(ConfiguredBaseModel): @@ -606,7 +735,7 @@ class UI(ConfiguredBaseModel): readonlyValue: Optional[bool] = Field(None) -class UnitOption(CreativeWork): +class UnitOption(Thing): """ An object to represent a human displayable name alongside the more formal value for units. """ @@ -621,25 +750,37 @@ class UnitOption(CreativeWork): title="value", description="""The value for each option in choices or in additionalNotesObj""", ) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) class VideoObject(MediaObject): - contentUrl: str = Field(...) inLanguage: Optional[str] = Field(None) - id: Optional[str] = Field(None, description="""A unique identifier for an item.""") - category: Optional[str] = Field(None, description="""A specific type of class.""") + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + contentUrl: str = Field(...) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) # Model rebuild # see https://pydantic-docs.helpmanual.io/usage/models/#rebuilding-a-model Agent.model_rebuild() -CreativeWork.model_rebuild() -Activity.model_rebuild() +Participant.model_rebuild() +Thing.model_rebuild() AdditionalNoteObj.model_rebuild() AdditionalProperty.model_rebuild() Choice.model_rebuild() +CreativeWork.model_rebuild() +Activity.model_rebuild() ComputeSpecification.model_rebuild() Item.model_rebuild() LandingPage.model_rebuild() @@ -648,7 +789,6 @@ class VideoObject(MediaObject): ImageObject.model_rebuild() MessageSpecification.model_rebuild() OverrideProperty.model_rebuild() -Participant.model_rebuild() Protocol.model_rebuild() Response.model_rebuild() ResponseActivity.model_rebuild() From 36bbb3670480f676ca29d04d561e8ef1a7f7dffa Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Wed, 8 May 2024 20:15:45 -0400 Subject: [PATCH 20/27] updating model after removing CreativeWork and ImageUrl --- reproschema/models/model.py | 304 ++++++++++++++++++------------------ 1 file changed, 155 insertions(+), 149 deletions(-) diff --git a/reproschema/models/model.py b/reproschema/models/model.py index 89334ed..aa64600 100644 --- a/reproschema/models/model.py +++ b/reproschema/models/model.py @@ -76,6 +76,76 @@ class Thing(ConfiguredBaseModel): description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) + + +class Activity(Thing): + """ + An assessment in a protocol. + """ + + about: Optional[str] = Field( + None, description="""The subject matter of the Field.""" + ) + altLabel: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="alternate label", + description="""The alternate label.""", + ) + associatedMedia: Optional[str] = Field( + None, + title="associatedMedia", + description="""A media object that encodes this creative work. This property is a synonym for encoding.""", + ) + citation: Optional[Dict[str, str]] = Field(default_factory=dict) + compute: Optional[List[ComputeSpecification]] = Field( + default_factory=list, + title="computation", + description="""An array of objects indicating computations in an activity or protocol and maps it to the corresponding Item. scoring logic is a subset of all computations that could be performed and not all computations will be scoring. For example, one may want to do conversion from one unit to another.""", + ) + cronTable: Optional[str] = Field( + None, title="cronTable", description="""TODO not described in reproschema""" + ) + description: Optional[Dict[str, str]] = Field(default_factory=dict) + image: Optional[Union[ImageObject, str]] = Field( + None, + title="image", + description="""An image of the item. This can be a URL or a fully described ImageObject.""", + ) + messages: Optional[List[MessageSpecification]] = Field( + default_factory=list, + title="messages", + description="""An array of objects to define conditional messages in an activity or protocol.""", + ) + preamble: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="Preamble", + description="""The preamble for an assessment""", + ) + prefLabel: Optional[Dict[str, str]] = Field( + default_factory=dict, + title="preferred label", + description="""The preferred label.""", + ) + schemaVersion: Optional[str] = Field(None) + ui: Optional[UI] = Field( + None, + title="UI", + description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", + ) + version: Optional[str] = Field(None) + id: Optional[str] = Field( + None, + description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", + ) + name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) class AdditionalNoteObj(Thing): @@ -105,6 +175,10 @@ class AdditionalNoteObj(Thing): description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) class AdditionalProperty(Thing): @@ -168,6 +242,10 @@ class AdditionalProperty(Thing): description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) class Choice(Thing): @@ -192,89 +270,13 @@ class Choice(Thing): None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) - - -class CreativeWork(Thing): - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) - id: Optional[str] = Field( - None, - description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", - ) - name: Optional[Dict[str, str]] = Field(default_factory=dict) - - -class Activity(CreativeWork): - """ - An assessment in a protocol. - """ - - about: Optional[str] = Field( - None, description="""The subject matter of the Field.""" - ) - altLabel: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="alternate label", - description="""The alternate label.""", - ) - associatedMedia: Optional[str] = Field( - None, - title="associatedMedia", - description="""A media object that encodes this CreativeWork. This property is a synonym for encoding.""", - ) - citation: Optional[Dict[str, str]] = Field(default_factory=dict) - compute: Optional[List[ComputeSpecification]] = Field( - default_factory=list, - title="computation", - description="""An array of objects indicating computations in an activity or protocol and maps it to the corresponding Item. scoring logic is a subset of all computations that could be performed and not all computations will be scoring. For example, one may want to do conversion from one unit to another.""", - ) - cronTable: Optional[str] = Field( - None, title="cronTable", description="""TODO not described in reproschema""" - ) - description: Optional[Dict[str, str]] = Field(default_factory=dict) - image: Optional[Union[ImageObject, str]] = Field( - None, - title="image", - description="""An image of the item. This can be a URL or a fully described ImageObject.""", - ) - messages: Optional[List[MessageSpecification]] = Field( - default_factory=list, - title="messages", - description="""An array of objects to define conditional messages in an activity or protocol.""", - ) - preamble: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="Preamble", - description="""The preamble for an assessment""", - ) - prefLabel: Optional[Dict[str, str]] = Field( - default_factory=dict, - title="preferred label", - description="""The preferred label.""", - ) - schemaVersion: Optional[str] = Field(None) - ui: Optional[UI] = Field( - None, - title="UI", - description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", - ) - version: Optional[str] = Field(None) category: Optional[str] = Field( None, description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", ) - contentUrl: Optional[str] = Field(None) - id: Optional[str] = Field( - None, - description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", - ) - name: Optional[Dict[str, str]] = Field(default_factory=dict) -class ComputeSpecification(CreativeWork): +class ComputeSpecification(Thing): """ An object to define computations in an activity or protocol. """ @@ -289,19 +291,18 @@ class ComputeSpecification(CreativeWork): title="variableName", description="""The name used to represent an item.""", ) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class Item(CreativeWork): +class Item(Thing): """ An item in an assessment. """ @@ -322,7 +323,7 @@ class Item(CreativeWork): associatedMedia: Optional[str] = Field( None, title="associatedMedia", - description="""A media object that encodes this CreativeWork. This property is a synonym for encoding.""", + description="""A media object that encodes this creative work. This property is a synonym for encoding.""", ) audio: Optional[Union[AudioObject, str]] = Field( None, title="audio", description="""TODO""" @@ -333,9 +334,6 @@ class Item(CreativeWork): title="image", description="""An image of the item. This can be a URL or a fully described ImageObject.""", ) - imageUrl: Optional[str] = Field( - None, title="imageUrl", description="""An image url.""" - ) isPartOf: Optional[Activity] = Field(None) preamble: Optional[Dict[str, str]] = Field( default_factory=dict, @@ -360,84 +358,82 @@ class Item(CreativeWork): description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", ) version: Optional[str] = Field(None) - video: Optional[VideoObject] = Field(None) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) + video: Optional[Union[VideoObject, str]] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class LandingPage(CreativeWork): +class LandingPage(Thing): """ An object to define the landing page of a protocol. """ inLanguage: Optional[str] = Field(None) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class MediaObject(CreativeWork): +class MediaObject(Thing): """ Add description """ inLanguage: Optional[str] = Field(None) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) contentUrl: str = Field(...) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) - - -class AudioObject(MediaObject): - inLanguage: Optional[str] = Field(None) category: Optional[str] = Field( None, description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", ) + + +class AudioObject(MediaObject): + inLanguage: Optional[str] = Field(None) contentUrl: str = Field(...) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) - - -class ImageObject(MediaObject): - inLanguage: Optional[str] = Field(None) category: Optional[str] = Field( None, description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", ) + + +class ImageObject(MediaObject): + inLanguage: Optional[str] = Field(None) contentUrl: str = Field(...) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class MessageSpecification(CreativeWork): +class MessageSpecification(Thing): """ An object to define messages in an activity or protocol. """ @@ -452,16 +448,15 @@ class MessageSpecification(CreativeWork): title="Message", description="""The message to be conditionally displayed for an item.""", ) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) class OverrideProperty(Thing): @@ -515,9 +510,13 @@ class OverrideProperty(Thing): description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class Protocol(CreativeWork): +class Protocol(Thing): """ A representation of a study which comprises one or more assessments. """ @@ -533,7 +532,7 @@ class Protocol(CreativeWork): associatedMedia: Optional[str] = Field( None, title="associatedMedia", - description="""A media object that encodes this CreativeWork. This property is a synonym for encoding.""", + description="""A media object that encodes this creative work. This property is a synonym for encoding.""", ) compute: Optional[List[ComputeSpecification]] = Field( default_factory=list, @@ -566,19 +565,18 @@ class Protocol(CreativeWork): description="""An element to control UI specifications. Originally @nest in jsonld, but using a class in the model.""", ) version: Optional[str] = Field(None) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class Response(CreativeWork): +class Response(Thing): """ Describes the response of an item. """ @@ -596,19 +594,18 @@ class Response(CreativeWork): description="""The value for each option in choices or in additionalNotesObj""", ) wasAttributedTo: Optional[Participant] = Field(None) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class ResponseActivity(CreativeWork): +class ResponseActivity(Thing): """ Captures information about some action that took place. It also links to information (entities) that were used during the activity """ @@ -619,19 +616,18 @@ class ResponseActivity(CreativeWork): startedAtTime: Optional[datetime] = Field(None) used: Optional[List[str]] = Field(default_factory=list) wasAssociatedWith: Optional[SoftwareAgent] = Field(None) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) -class ResponseOption(CreativeWork): +class ResponseOption(Thing): """ An element (object or by URL)to describe the properties of response of the Item. """ @@ -663,16 +659,15 @@ class ResponseOption(CreativeWork): title="The type of the response", description="""The type of the response of an item. For example, string, integer, etc.""", ) - category: Optional[str] = Field( - None, - description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", - ) - contentUrl: Optional[str] = Field(None) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) class SoftwareAgent(Thing): @@ -687,6 +682,10 @@ class SoftwareAgent(Thing): description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) class StructuredValue(Thing): @@ -695,6 +694,10 @@ class StructuredValue(Thing): description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) class UI(ConfiguredBaseModel): @@ -755,20 +758,24 @@ class UnitOption(Thing): description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) - - -class VideoObject(MediaObject): - inLanguage: Optional[str] = Field(None) category: Optional[str] = Field( None, description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", ) + + +class VideoObject(MediaObject): + inLanguage: Optional[str] = Field(None) contentUrl: str = Field(...) id: Optional[str] = Field( None, description="""A unique identifier for an entity. Must be either a CURIE shorthand for a URI or a complete URI.""", ) name: Optional[Dict[str, str]] = Field(default_factory=dict) + category: Optional[str] = Field( + None, + description="""Name of the high level ontology class in which this entity is categorized. Corresponds to the label for the biolink entity type class. In an RDF database it should be a model class URI. This field is multi-valued.""", + ) # Model rebuild @@ -776,11 +783,10 @@ class VideoObject(MediaObject): Agent.model_rebuild() Participant.model_rebuild() Thing.model_rebuild() +Activity.model_rebuild() AdditionalNoteObj.model_rebuild() AdditionalProperty.model_rebuild() Choice.model_rebuild() -CreativeWork.model_rebuild() -Activity.model_rebuild() ComputeSpecification.model_rebuild() Item.model_rebuild() LandingPage.model_rebuild() From 2f3e3ca6f1cc98c24a8f52705ad17955b29885d5 Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Wed, 8 May 2024 22:45:03 -0400 Subject: [PATCH 21/27] adding tests to initialize the model classes --- reproschema/models/tests/test_schema.py | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/reproschema/models/tests/test_schema.py b/reproschema/models/tests/test_schema.py index d5e9b0b..2297dd2 100644 --- a/reproschema/models/tests/test_schema.py +++ b/reproschema/models/tests/test_schema.py @@ -7,3 +7,85 @@ def test_constructors(model_class): ob = model_class() assert hasattr(ob, "id") assert hasattr(ob, "category") + + +def test_protocol(): + """check if protocol is created correctly for a simple example""" + protocol_dict = { + "category": "reproschema:Protocol", + "id": "protocol1.jsonld", + "prefLabel": {"en": "Protocol1", "es": "Protocol1_es"}, + "description": {"en": "example Protocol"}, + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "messages": [ + { + "message": { + "en": "Test message: Triggered when item1 value is greater than 0" + }, + "jsExpression": "item1 > 0", + } + ], + } + Protocol(**protocol_dict) + + +def test_activity(): + """check if activity is created correctly for a simple example""" + activity_dict = { + "category": "reproschema:Activity", + "id": "activity1.jsonld", + "prefLabel": {"en": "Example 1"}, + "description": {"en": "Activity example 1"}, + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "image": { + "category": "AudioObject", + "contentUrl": "http://example.com/sample-image.png", + }, + "preamble": { + "en": "Over the last 2 weeks, how often have you been bothered by any of the following problems?", + "es": "Durante las últimas 2 semanas, ¿con qué frecuencia le han molestado los siguintes problemas?", + }, + "compute": [ + {"variableName": "activity1_total_score", "jsExpression": "item1 + item2"} + ], + } + Activity(**activity_dict) + + +def test_item(): + """check if item is created correctly for a simple example""" + + item_dict = { + "category": "reproschema:Field", + "id": "item1.jsonld", + "prefLabel": "item1", + "altLabel": "item1_alt", + "description": "Q1 of example 1", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "audio": { + "@type": "AudioObject", + "contentUrl": "http://media.freesound.org/sample-file.mp4", + }, + "image": { + "@type": "ImageObject", + "contentUrl": "http://example.com/sample-image.jpg", + }, + "question": { + "en": "Little interest or pleasure in doing things", + "es": "Poco interés o placer en hacer cosas", + }, + "ui": {"inputType": "radio"}, + "responseOptions": { + "valueType": "xsd:integer", + "minValue": 0, + "maxValue": 3, + "multipleChoice": False, + "choices": [ + {"name": {"en": "Not at all", "es": "Para nada"}, "value": 0}, + {"name": {"en": "Several days", "es": "Varios días"}, "value": "a"}, + ], + }, + } From 2e543313790e596ba985adfdf504afc031fd7fcc Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Fri, 10 May 2024 12:31:49 -0400 Subject: [PATCH 22/27] fixing load_file; adding write_obj_jsonld function and expanding test_schema --- reproschema/jsonldutils.py | 71 +++++++++++++-------- reproschema/models/tests/test_schema.py | 82 ++++++++++++++++++++----- reproschema/models/utils.py | 13 ++++ 3 files changed, 122 insertions(+), 44 deletions(-) diff --git a/reproschema/jsonldutils.py b/reproschema/jsonldutils.py index 11fe449..c82f0d2 100644 --- a/reproschema/jsonldutils.py +++ b/reproschema/jsonldutils.py @@ -3,43 +3,60 @@ import os from pathlib import Path from copy import deepcopy +from urllib.parse import urlparse from .utils import start_server, stop_server, lgr, fixing_old_schema from .models import Item, Activity, Protocol, ResponseOption, ResponseActivity, Response +def _is_url(path): + """ + Determine whether the given path is a URL. + """ + parsed = urlparse(path) + return parsed.scheme in ("http", "https", "ftp", "ftps") + + +def _is_file(path): + """ + Determine whether the given path is a valid file path. + """ + return os.path.isfile(path) + + def load_file(path_or_url, started=False, http_kwargs={}): - try: + """Load a file or URL and return the expanded JSON-LD data.""" + path_or_url = str(path_or_url) + if _is_url(path_or_url): data = jsonld.expand(path_or_url) if len(data) == 1: - if "@id" not in data[0]: + if "@id" not in data[0] and "id" not in data[0]: data[0]["@id"] = path_or_url - except jsonld.JsonLdError as e: - if 'only "http" and "https"' in str(e): - lgr.debug("Reloading with local server") - root = os.path.dirname(path_or_url) - if not started: - stop, port = start_server(**http_kwargs) - else: - if "port" not in http_kwargs: - raise KeyError("port key missing in http_kwargs") - port = http_kwargs["port"] - base_url = f"http://localhost:{port}/" - if root: - base_url += f"{root}/" - with open(path_or_url) as json_file: - data = json.load(json_file) - try: - data = jsonld.expand(data, options={"base": base_url}) - except: - raise - finally: - if not started: - stop_server(stop) - if len(data) == 1: - if "@id" not in data[0]: - data[0]["@id"] = base_url + os.path.basename(path_or_url) + elif _is_file(path_or_url): + lgr.debug("Reloading with local server") + root = os.path.dirname(path_or_url) + if not started: + stop, port = start_server(**http_kwargs) else: + if "port" not in http_kwargs: + raise KeyError("port key missing in http_kwargs") + port = http_kwargs["port"] + base_url = f"http://localhost:{port}/" + if root: + base_url += f"{root}/" + with open(path_or_url) as json_file: + data = json.load(json_file) + try: + data = jsonld.expand(data, options={"base": base_url}) + except: raise + finally: + if not started: + stop_server(stop) + if len(data) == 1: + if "@id" not in data[0] and "id" not in data[0]: + data[0]["@id"] = base_url + os.path.basename(path_or_url) + else: + raise Exception(f"{path_or_url} is not a valid URL or file path") return data diff --git a/reproschema/models/tests/test_schema.py b/reproschema/models/tests/test_schema.py index 2297dd2..04a4658 100644 --- a/reproschema/models/tests/test_schema.py +++ b/reproschema/models/tests/test_schema.py @@ -1,7 +1,32 @@ from .. import Protocol, Activity, Item, ResponseOption +from ..utils import write_obj_jsonld +from ...utils import start_server, stop_server +from ...jsonldutils import load_file + +from pyld import jsonld +import json, os +from pathlib import Path + import pytest +@pytest.fixture +def server_http_kwargs(request): + http_kwargs = {} + stop, port = start_server() + http_kwargs["port"] = port + + olddir = os.getcwd() + os.chdir(os.path.dirname(__file__)) + + def stoping_server(): + stop_server(stop) + os.chdir(olddir) + + request.addfinalizer(stoping_server) + return http_kwargs + + @pytest.mark.parametrize("model_class", [Protocol, Activity, Item, ResponseOption]) def test_constructors(model_class): ob = model_class() @@ -9,8 +34,10 @@ def test_constructors(model_class): assert hasattr(ob, "category") -def test_protocol(): - """check if protocol is created correctly for a simple example""" +def test_protocol(tmp_path, server_http_kwargs): + """check if protocol is created correctly for a simple example + and if it can be written to the file as jsonld. + """ protocol_dict = { "category": "reproschema:Protocol", "id": "protocol1.jsonld", @@ -27,11 +54,18 @@ def test_protocol(): } ], } - Protocol(**protocol_dict) + protocol_obj = Protocol(**protocol_dict) + + file_path = tmp_path / "protocol1.jsonld" + write_obj_jsonld(protocol_obj, file_path) + data = load_file(file_path, started=True, http_kwargs=server_http_kwargs) + expanded = jsonld.expand(data) + assert len(expanded) > 0 -def test_activity(): - """check if activity is created correctly for a simple example""" +def test_activity(tmp_path, server_http_kwargs): + """check if activity is created correctly for a simple example + and if it can be written to the file as jsonld.""" activity_dict = { "category": "reproschema:Activity", "id": "activity1.jsonld", @@ -51,41 +85,55 @@ def test_activity(): {"variableName": "activity1_total_score", "jsExpression": "item1 + item2"} ], } - Activity(**activity_dict) + activity_obj = Activity(**activity_dict) + + file_path = tmp_path / "activity1.jsonld" + write_obj_jsonld(activity_obj, file_path) + data = load_file(file_path, started=True, http_kwargs=server_http_kwargs) + expanded = jsonld.expand(data) + assert len(expanded) > 0 -def test_item(): - """check if item is created correctly for a simple example""" +def test_item(tmp_path, server_http_kwargs): + """check if item is created correctly for a simple example" + and if it can be written to the file as jsonld.""" item_dict = { "category": "reproschema:Field", "id": "item1.jsonld", - "prefLabel": "item1", - "altLabel": "item1_alt", - "description": "Q1 of example 1", + "prefLabel": {"en": "item1"}, + "altLabel": {"en": "item1_alt"}, + "description": {"en": "Q1 of example 1"}, "schemaVersion": "1.0.0-rc4", "version": "0.0.1", "audio": { - "@type": "AudioObject", + "category": "AudioObject", "contentUrl": "http://media.freesound.org/sample-file.mp4", }, "image": { - "@type": "ImageObject", + "category": "ImageObject", "contentUrl": "http://example.com/sample-image.jpg", }, "question": { "en": "Little interest or pleasure in doing things", "es": "Poco interés o placer en hacer cosas", }, - "ui": {"inputType": "radio"}, + # "ui": {"inputType": "radio"}, "responseOptions": { - "valueType": "xsd:integer", "minValue": 0, "maxValue": 3, "multipleChoice": False, "choices": [ - {"name": {"en": "Not at all", "es": "Para nada"}, "value": 0}, - {"name": {"en": "Several days", "es": "Varios días"}, "value": "a"}, + {"name": {"en": "Not at all", "es": "Para nada"}, "value": "a"}, + {"name": {"en": "Several days", "es": "Varios días"}, "value": "b"}, ], }, } + + item_obj = Item(**item_dict) + + file_path = tmp_path / "item1.jsonld" + write_obj_jsonld(item_obj, file_path) + data = load_file(file_path, started=True, http_kwargs=server_http_kwargs) + expanded = jsonld.expand(data) + assert len(expanded) > 0 diff --git a/reproschema/models/utils.py b/reproschema/models/utils.py index c1d34b6..e6452df 100644 --- a/reproschema/models/utils.py +++ b/reproschema/models/utils.py @@ -15,3 +15,16 @@ def load_schema(filepath): return Activity.from_data(data) if schema_type == "reproschema:Item": return Item.from_data(data) + + +def write_obj_jsonld(model_obj, path): + """Write a pydantic model object to a jsonld file.""" + contextfile = "https://raw.githubusercontent.com/djarecka/reproschema/linkml_new_tmp/contexts/reproschema_new" + model_dict = model_obj.model_dump( + exclude_unset=True, + ) + model_dict["@context"] = contextfile + + with open(path, "w") as f: + json.dump(model_dict, f, indent=4) + return path From 71e90f04e94b4ad65c752730182b634134c3ea23 Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Sun, 12 May 2024 22:57:52 -0400 Subject: [PATCH 23/27] changing redcap2reproschema to use ned pydantic classes; some small changes to the pydantic model --- reproschema/models/__init__.py | 1 + reproschema/models/model.py | 6 +- reproschema/redcap2reproschema.py | 90 +++++++++----------- reproschema/tests/test_redcap2reproschema.py | 2 +- 4 files changed, 44 insertions(+), 55 deletions(-) diff --git a/reproschema/models/__init__.py b/reproschema/models/__init__.py index 0da3b23..347ad42 100644 --- a/reproschema/models/__init__.py +++ b/reproschema/models/__init__.py @@ -1 +1,2 @@ from .model import Activity, Item, Protocol, ResponseOption, ResponseActivity, Response +from .utils import load_schema, write_obj_jsonld diff --git a/reproschema/models/model.py b/reproschema/models/model.py index aa64600..9c387fa 100644 --- a/reproschema/models/model.py +++ b/reproschema/models/model.py @@ -260,7 +260,9 @@ class Choice(Thing): description="""An image of the item. This can be a URL or a fully described ImageObject.""", ) value: Optional[ - Union[Decimal, Dict[str, str], MissingType, StructuredValue, bool, str] + Union[ + float, int, Decimal, Dict[str, str], MissingType, StructuredValue, bool, str + ] ] = Field( None, title="value", @@ -654,7 +656,7 @@ class ResponseOption(Thing): title="unitOptions", description="""A list of objects to represent a human displayable name alongside the more formal value for units.""", ) - valueType: Optional[List[str]] = Field( + valueType: Optional[Union[str, List[str]]] = Field( default_factory=list, title="The type of the response", description="""The type of the response of an item. For example, string, integer, etc.""", diff --git a/reproschema/redcap2reproschema.py b/reproschema/redcap2reproschema.py index e7f67c7..cefb8a4 100644 --- a/reproschema/redcap2reproschema.py +++ b/reproschema/redcap2reproschema.py @@ -5,6 +5,7 @@ import re import yaml from bs4 import BeautifulSoup +from .models import Activity, Item, Protocol, write_obj_jsonld matrix_group_count = {} @@ -120,7 +121,7 @@ def process_choices(field_type, choices_str): except ValueError: value = parts[0] - choice_obj = {"name": " ".join(parts[1:]), "value": value} + choice_obj = {"name": {"en": " ".join(parts[1:])}, "value": value} # remove image for now # if len(parts) == 3: # # Handle image url @@ -129,19 +130,6 @@ def process_choices(field_type, choices_str): return choices -def write_to_file(abs_folder_path, form_name, field_name, rowData): - file_path = os.path.join( - f"{abs_folder_path}", "activities", form_name, "items", f"{field_name}" - ) - os.makedirs(os.path.dirname(file_path), exist_ok=True) - try: - with open(file_path, "w") as file: - json.dump(rowData, file, indent=4) - print(f"Item schema for {form_name} written successfully.") - except Exception as e: - print(f"Error in writing item schema for {form_name}: {e}") - - def parse_html(input_string, default_language="en"): result = {} soup = BeautifulSoup(input_string, "html.parser") @@ -174,6 +162,7 @@ def process_row( response_list, additional_notes_list, ): + """Process a row of the REDCap data and generate the jsonld file for the item.""" global matrix_group_count matrix_group_name = field.get("Matrix Group Name", "") if matrix_group_name: @@ -185,11 +174,10 @@ def process_row( item_id = field.get("Variable / Field Name", "") rowData = { - "@context": schema_context_url, - "@type": "reproschema:Item", - "@id": item_id, - "prefLabel": item_id, - "description": f"{item_id} of {form_name}", + "category": "reproschema:Item", + "id": item_id, + "prefLabel": {"en": item_id}, + "description": {"en": f"{item_id} of {form_name}"}, } field_type = field.get("Field Type", "") @@ -255,7 +243,15 @@ def process_row( notes_obj = {"source": "redcap", "column": key, "value": value} rowData.setdefault("additionalNotesObj", []).append(notes_obj) - write_to_file(abs_folder_path, form_name, field["Variable / Field Name"], rowData) + it = Item(**rowData) + file_path_item = os.path.join( + f"{abs_folder_path}", + "activities", + form_name, + "items", + f'{field["Variable / Field Name"]}', + ) + write_obj_jsonld(it, file_path_item) def create_form_schema( @@ -270,16 +266,16 @@ def create_form_schema( matrix_list, scores_list, ): + """Create the JSON-LD schema for the Activity.""" # Use a set to track unique items and preserve order unique_order = list(dict.fromkeys(order.get(form_name, []))) # Construct the JSON-LD structure json_ld = { - "@context": schema_context_url, - "@type": "reproschema:Activity", - "@id": f"{form_name}_schema", - "prefLabel": activity_display_name, - "description": activity_description, + "category": "reproschema:Activity", + "id": f"{form_name}_schema", + "prefLabel": {"en": activity_display_name}, + "description": {"en": activity_description}, "schemaVersion": "1.0.0-rc4", "version": redcap_version, "ui": { @@ -288,7 +284,7 @@ def create_form_schema( "shuffle": False, }, } - + act = Activity(**json_ld) # remove matrixInfo to pass validataion # if matrix_list: # json_ld["matrixInfo"] = matrix_list @@ -296,17 +292,11 @@ def create_form_schema( json_ld["scoringLogic"] = scores_list path = os.path.join(f"{abs_folder_path}", "activities", form_name) + os.makedirs(path, exist_ok=True) filename = f"{form_name}_schema" file_path = os.path.join(path, filename) - try: - os.makedirs(path, exist_ok=True) - with open(file_path, "w") as file: - json.dump(json_ld, file, indent=4) - print(f"{form_name} Instrument schema created") - except OSError as e: - print(f"Error creating directory {path}: {e}") - except IOError as e: - print(f"Error writing to file {file_path}: {e}") + write_obj_jsonld(act, file_path) + print(f"{form_name} Instrument schema created") def process_activities(activity_name, protocol_visibility_obj, protocol_order): @@ -328,12 +318,11 @@ def create_protocol_schema( ): # Construct the protocol schema protocol_schema = { - "@context": schema_context_url, - "@type": "reproschema:Protocol", - "@id": f"{protocol_name}_schema", - "prefLabel": protocol_display_name, - "altLabel": f"{protocol_name}_schema", - "description": protocol_description, + "category": "reproschema:Protocol", + "id": f"{protocol_name}_schema", + "prefLabel": {"en": protocol_display_name}, + "altLabel": {"en": f"{protocol_name}_schema"}, + "description": {"en": protocol_description}, "schemaVersion": "1.0.0-rc4", "version": redcap_version, "ui": { @@ -350,7 +339,7 @@ def create_protocol_schema( "isAbout": full_path, "variableName": f"{activity}_schema", # Assuming activity name as prefLabel, update as needed - "prefLabel": activity.replace("_", " ").title(), + "prefLabel": {"en": activity.replace("_", " ").title()}, "isVis": protocol_visibility_obj.get( activity, True ), # Default to True if not specified @@ -359,19 +348,14 @@ def create_protocol_schema( # Add the full path to the order list protocol_schema["ui"]["order"].append(full_path) + prot = Protocol(**protocol_schema) + # Write the protocol schema to file protocol_dir = f"{abs_folder_path}/{protocol_name}" + os.makedirs(protocol_dir, exist_ok=True) schema_file = f"{protocol_name}_schema" file_path = os.path.join(protocol_dir, schema_file) - - try: - os.makedirs(protocol_dir, exist_ok=True) - with open(file_path, "w") as file: - json.dump(protocol_schema, file, indent=4) - print("Protocol schema created") - except OSError as e: - print(f"Error creating directory {protocol_dir}: {e}") - except IOError as e: - print(f"Error writing to file {file_path}: {e}") + write_obj_jsonld(prot, file_path) + print("Protocol schema created") def parse_language_iso_codes(input_string): @@ -414,6 +398,7 @@ def process_csv( for field in datas[form_name]: field_name = field["Variable / Field Name"] order[form_name].append(f"items/{field_name}") + print("Processing field: ", field_name, " in form: ", form_name) process_row( abs_folder_path, schema_context_url, @@ -447,6 +432,7 @@ def redcap2reproschema(csv_file, yaml_file, schema_context_url=None): protocol_display_name = protocol.get("protocol_display_name") protocol_description = protocol.get("protocol_description") redcap_version = protocol.get("redcap_version") + # we can add reproschema version here (or automatically extract) if not protocol_name: raise ValueError("Protocol name not specified in the YAML file.") diff --git a/reproschema/tests/test_redcap2reproschema.py b/reproschema/tests/test_redcap2reproschema.py index bbf2df7..ac24cf5 100644 --- a/reproschema/tests/test_redcap2reproschema.py +++ b/reproschema/tests/test_redcap2reproschema.py @@ -23,7 +23,7 @@ def test_redcap2reproschema(tmpdir): shutil.copy(CSV_TEST_FILE, str(temp_csv_file)) # Convert to string shutil.copy(YAML_TEST_FILE, str(temp_yaml_file)) # Convert to string - + print("tmpdir: ", tmpdir) # Change the current working directory to tmpdir with tmpdir.as_cwd(): # Read YAML to find the expected output directory name From e5707140ff248d20c847e5c0a37e4912f8687780 Mon Sep 17 00:00:00 2001 From: ibevers Date: Wed, 15 May 2024 13:51:08 -0400 Subject: [PATCH 24/27] Start function for loading activities for easy editing --- reproschema/jsonldutils.py | 86 +++++++++++++++++++++++++++++++++++++ reproschema/subset_items.py | 40 +++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 reproschema/subset_items.py diff --git a/reproschema/jsonldutils.py b/reproschema/jsonldutils.py index c82f0d2..6db7753 100644 --- a/reproschema/jsonldutils.py +++ b/reproschema/jsonldutils.py @@ -59,6 +59,92 @@ def load_file(path_or_url, started=False, http_kwargs={}): raise Exception(f"{path_or_url} is not a valid URL or file path") return data +# def load_directory(path_or_url, load_file=load_file): +# """Creates a dictionary mirroring a directory containing only directories and +# JSON-LD files at the specified path.""" + +""" +#start the server + +#stop the server +Base URL +directory = { + +} + +""" +# loaded_directory = {} + +# directory_structure = {} + +# for root, dirs, files in os.walk(base_path): +# relative_root = os.path.relpath(root, base_path) +# if relative_root == '.': +# relative_root = '' + +# subdirs = {} +# for subdir in dirs: +# subdir_path = os.path.join(root, subdir) +# subdirs[subdir] = load_directory_structure(subdir_path, load_jsonld_function) + +# jsonld_files = {} +# for file in files: +# if file.endswith('.jsonld'): +# file_path = os.path.join(root, file) +# jsonld_files[file] = load_jsonld_function(file_path) + +# if relative_root: +# directory_structure[relative_root] = {'subdirs': subdirs, 'jsonld_files': jsonld_files} +# else: +# directory_structure.update(subdirs) +# directory_structure.update(jsonld_files) + +# return directory_structure +def load_directory_structure(base_path, started=False, http_kwargs={}): + """ + Recursively iterates over a directory structure and constructs a dictionary. + + Args: + - base_path (str): The base directory path to start iterating from. + - load_jsonld_function (function): A function that takes a file path and returns the loaded JSON-LD data. + + Returns: + - dict: A dictionary with directory names as keys and subdirectory names or loaded JSON-LD as values. + """ + + if not started: + stop_server(stop) + stop, port = start_server(**http_kwargs) + started = True + + directory_structure = {} + + for root, dirs, files in os.walk(base_path): + relative_root = os.path.relpath(root, base_path) + if relative_root == '.': + relative_root = '' + + subdirs = {} + for subdir in dirs: + subdir_path = os.path.join(root, subdir) + subdirs[subdir] = load_directory_structure(subdir_path) + + jsonld_files = {} + for file in files: + file_path = os.path.join(root, file) + jsonld_files[file] = load_file(file_path, started=True, http_kwargs={"port":port}) + + if relative_root: + directory_structure[relative_root] = {'subdirs': subdirs, 'jsonld_files': jsonld_files} + else: + directory_structure.update(subdirs) + directory_structure.update(jsonld_files) + + + stop_server(stop) + + return directory_structure + def validate_data(data): """Validate an expanded jsonld document against the pydantic model. diff --git a/reproschema/subset_items.py b/reproschema/subset_items.py new file mode 100644 index 0000000..5664c5c --- /dev/null +++ b/reproschema/subset_items.py @@ -0,0 +1,40 @@ +import sys +import os + +# Add the parent directory of reproschema to the sys.path +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +# print(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +# sys.path.append('/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-py') + + +from reproschema.jsonldutils import load_file, load_directory_structure +# from jsonldutils import load_file + +import json + + +def printj(dict_like_file): + print(json.dumps(dict_like_file, indent=4, ensure_ascii=False)) + +def subset_items(child_activity_path, parent_activity_path): + """ + Lexically matches the questions in the child activity to + those in the parent activity. Updates the references in the child + schema to refer to those in the parent schema. Deletes the overlapping + items in the child activity. + """ + child_activity = load_file(child_activity_path) + # parent_activity = load_file(parent_activity_path) + return child_activity + + +# child_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS12/items/WHODAS12_4" +# # child_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS12/" +# parent_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS36_S/" +# test = subset_items(child_activity_path, parent_activity_path) +# printj(test) + + +path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS36_S/" +loaded = load_directory_structure(path) +print(loaded.keys()) From 65590c08ab9650162a196e18e22528c597fc57c6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 17:52:52 +0000 Subject: [PATCH 25/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- reproschema/jsonldutils.py | 26 ++++++++++++++++---------- reproschema/subset_items.py | 6 ++++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/reproschema/jsonldutils.py b/reproschema/jsonldutils.py index 6db7753..cda24cf 100644 --- a/reproschema/jsonldutils.py +++ b/reproschema/jsonldutils.py @@ -59,17 +59,18 @@ def load_file(path_or_url, started=False, http_kwargs={}): raise Exception(f"{path_or_url} is not a valid URL or file path") return data + # def load_directory(path_or_url, load_file=load_file): # """Creates a dictionary mirroring a directory containing only directories and # JSON-LD files at the specified path.""" """ -#start the server +#start the server #stop the server Base URL directory = { - + } """ @@ -99,21 +100,22 @@ def load_file(path_or_url, started=False, http_kwargs={}): # directory_structure.update(subdirs) # directory_structure.update(jsonld_files) + # return directory_structure def load_directory_structure(base_path, started=False, http_kwargs={}): """ Recursively iterates over a directory structure and constructs a dictionary. - + Args: - base_path (str): The base directory path to start iterating from. - load_jsonld_function (function): A function that takes a file path and returns the loaded JSON-LD data. - + Returns: - dict: A dictionary with directory names as keys and subdirectory names or loaded JSON-LD as values. """ if not started: - stop_server(stop) + stop_server(stop) stop, port = start_server(**http_kwargs) started = True @@ -121,8 +123,8 @@ def load_directory_structure(base_path, started=False, http_kwargs={}): for root, dirs, files in os.walk(base_path): relative_root = os.path.relpath(root, base_path) - if relative_root == '.': - relative_root = '' + if relative_root == ".": + relative_root = "" subdirs = {} for subdir in dirs: @@ -132,15 +134,19 @@ def load_directory_structure(base_path, started=False, http_kwargs={}): jsonld_files = {} for file in files: file_path = os.path.join(root, file) - jsonld_files[file] = load_file(file_path, started=True, http_kwargs={"port":port}) + jsonld_files[file] = load_file( + file_path, started=True, http_kwargs={"port": port} + ) if relative_root: - directory_structure[relative_root] = {'subdirs': subdirs, 'jsonld_files': jsonld_files} + directory_structure[relative_root] = { + "subdirs": subdirs, + "jsonld_files": jsonld_files, + } else: directory_structure.update(subdirs) directory_structure.update(jsonld_files) - stop_server(stop) return directory_structure diff --git a/reproschema/subset_items.py b/reproschema/subset_items.py index 5664c5c..917637a 100644 --- a/reproschema/subset_items.py +++ b/reproschema/subset_items.py @@ -2,12 +2,13 @@ import os # Add the parent directory of reproschema to the sys.path -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) # print(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) # sys.path.append('/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-py') from reproschema.jsonldutils import load_file, load_directory_structure + # from jsonldutils import load_file import json @@ -16,9 +17,10 @@ def printj(dict_like_file): print(json.dumps(dict_like_file, indent=4, ensure_ascii=False)) + def subset_items(child_activity_path, parent_activity_path): """ - Lexically matches the questions in the child activity to + Lexically matches the questions in the child activity to those in the parent activity. Updates the references in the child schema to refer to those in the parent schema. Deletes the overlapping items in the child activity. From 03b86cb8abac4ce3dc9e594f58ad4a9cb0936b29 Mon Sep 17 00:00:00 2001 From: ibevers Date: Thu, 16 May 2024 13:48:16 -0400 Subject: [PATCH 26/27] Update provisional subsetting items code --- reproschema/jsonldutils.py | 67 ++++++++++++++++++------------------- reproschema/subset_items.py | 62 ++++++++++++++++++++++++++++++---- 2 files changed, 89 insertions(+), 40 deletions(-) diff --git a/reproschema/jsonldutils.py b/reproschema/jsonldutils.py index 6db7753..d217118 100644 --- a/reproschema/jsonldutils.py +++ b/reproschema/jsonldutils.py @@ -100,51 +100,50 @@ def load_file(path_or_url, started=False, http_kwargs={}): # directory_structure.update(jsonld_files) # return directory_structure -def load_directory_structure(base_path, started=False, http_kwargs={}): - """ - Recursively iterates over a directory structure and constructs a dictionary. +# def load_directory_structure(base_path, started=False, http_kwargs={}): +# """ +# Recursively iterates over a directory structure and constructs a dictionary. - Args: - - base_path (str): The base directory path to start iterating from. - - load_jsonld_function (function): A function that takes a file path and returns the loaded JSON-LD data. +# Args: +# - base_path (str): The base directory path to start iterating from. +# - load_jsonld_function (function): A function that takes a file path and returns the loaded JSON-LD data. - Returns: - - dict: A dictionary with directory names as keys and subdirectory names or loaded JSON-LD as values. - """ - - if not started: - stop_server(stop) - stop, port = start_server(**http_kwargs) - started = True +# Returns: +# - dict: A dictionary with directory names as keys and subdirectory names or loaded JSON-LD as values. +# """ - directory_structure = {} +# if not started: +# stop_server(stop) +# stop, port = start_server(**http_kwargs) +# started = True - for root, dirs, files in os.walk(base_path): - relative_root = os.path.relpath(root, base_path) - if relative_root == '.': - relative_root = '' +# directory_structure = {} - subdirs = {} - for subdir in dirs: - subdir_path = os.path.join(root, subdir) - subdirs[subdir] = load_directory_structure(subdir_path) +# for root, dirs, files in os.walk(base_path): +# relative_root = os.path.relpath(root, base_path) +# if relative_root == '.': +# relative_root = '' - jsonld_files = {} - for file in files: - file_path = os.path.join(root, file) - jsonld_files[file] = load_file(file_path, started=True, http_kwargs={"port":port}) +# subdirs = {} +# for subdir in dirs: +# subdir_path = os.path.join(root, subdir) +# subdirs[subdir] = load_directory_structure(subdir_path) - if relative_root: - directory_structure[relative_root] = {'subdirs': subdirs, 'jsonld_files': jsonld_files} - else: - directory_structure.update(subdirs) - directory_structure.update(jsonld_files) +# jsonld_files = {} +# for file in files: +# file_path = os.path.join(root, file) +# jsonld_files[file] = load_file(file_path, started=True, http_kwargs={"port":port}) +# if relative_root: +# directory_structure[relative_root] = {'subdirs': subdirs, 'jsonld_files': jsonld_files} +# else: +# directory_structure.update(subdirs) +# directory_structure.update(jsonld_files) - stop_server(stop) - return directory_structure +# stop_server(stop) +# return directory_structure def validate_data(data): """Validate an expanded jsonld document against the pydantic model. diff --git a/reproschema/subset_items.py b/reproschema/subset_items.py index 5664c5c..b4afbed 100644 --- a/reproschema/subset_items.py +++ b/reproschema/subset_items.py @@ -7,7 +7,7 @@ # sys.path.append('/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-py') -from reproschema.jsonldutils import load_file, load_directory_structure +# from reproschema.jsonldutils import load_file, load_directory_structure # from jsonldutils import load_file import json @@ -16,7 +16,7 @@ def printj(dict_like_file): print(json.dumps(dict_like_file, indent=4, ensure_ascii=False)) -def subset_items(child_activity_path, parent_activity_path): +def subset_items_dorota(child_activity_path, parent_activity_path): """ Lexically matches the questions in the child activity to those in the parent activity. Updates the references in the child @@ -27,14 +27,64 @@ def subset_items(child_activity_path, parent_activity_path): # parent_activity = load_file(parent_activity_path) return child_activity +def load_items(activity_path): + items_path = activity_path + "items" + items = {} + for filename in os.listdir(items_path): + # print(filename) + with open(items_path + "/" + filename, 'r', encoding='utf-8') as file: #replace with load file eventually + data = json.load(file) + items[filename] = data + return items + + +def get_question(item_dict): + if "en" in item_dict["question"]: + return item_dict["question"]["en"] + else: + return item_dict["question"] + +def clean_sentence(sentence): + return ''.join(char.lower() for char in sentence if char.isalnum()) + +def create_item_mapping(child_activity_path, parent_activity_path): + child_items = load_items(child_activity_path) + parent_items = load_items(parent_activity_path) + item_mapping = {} + for ckey in child_items: + child_question = get_question(child_items[ckey]) + for pkey in parent_items: + parent_question = get_question(parent_items[pkey]) + if clean_sentence(child_question) == clean_sentence(parent_question): + item_mapping[ckey] = item_mapping[pkey] + print(item_mapping) + return item_mapping + + + + # child_items = [] + # for filename in os.listdir(child_activity_path + "items"): + # with open(file_path, 'r', encoding='utf-8') as file: #replace with load file eventually + # data = json.load(file) + + + + +# def subset_items_old(): + # child_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS12/items/WHODAS12_4" -# # child_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS12/" +# child_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS12/" # parent_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS36_S/" +# child_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/dsm_5_parent_guardian_rated_level_1_crosscutting_s/" +child_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/DSM-5_Y/" +parent_activity_path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/DSM-5_A/" + +create_item_mapping(child_activity_path, parent_activity_path) # test = subset_items(child_activity_path, parent_activity_path) # printj(test) -path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS36_S/" -loaded = load_directory_structure(path) -print(loaded.keys()) +# path = "/Users/isaacbevers/sensein/reproschema-wrapper/reproschema-library/activities/WHODAS36_S/" +# loaded = load_directory_structure(path) +# print(loaded.keys()) From 5e80b5e2ab100b3fc5f743c853e95da66191fc32 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 17:56:25 +0000 Subject: [PATCH 27/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- reproschema/jsonldutils.py | 7 ++++--- reproschema/subset_items.py | 16 +++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/reproschema/jsonldutils.py b/reproschema/jsonldutils.py index 442e7ca..3961fc1 100644 --- a/reproschema/jsonldutils.py +++ b/reproschema/jsonldutils.py @@ -105,17 +105,17 @@ def load_file(path_or_url, started=False, http_kwargs={}): # def load_directory_structure(base_path, started=False, http_kwargs={}): # """ # Recursively iterates over a directory structure and constructs a dictionary. - + # Args: # - base_path (str): The base directory path to start iterating from. # - load_jsonld_function (function): A function that takes a file path and returns the loaded JSON-LD data. - + # Returns: # - dict: A dictionary with directory names as keys and subdirectory names or loaded JSON-LD as values. # """ # if not started: -# stop_server(stop) +# stop_server(stop) # stop, port = start_server(**http_kwargs) # started = True @@ -148,6 +148,7 @@ def load_file(path_or_url, started=False, http_kwargs={}): # return directory_structure + def validate_data(data): """Validate an expanded jsonld document against the pydantic model. diff --git a/reproschema/subset_items.py b/reproschema/subset_items.py index b4d1f7f..f983af6 100644 --- a/reproschema/subset_items.py +++ b/reproschema/subset_items.py @@ -16,6 +16,7 @@ def printj(dict_like_file): print(json.dumps(dict_like_file, indent=4, ensure_ascii=False)) + def subset_items_dorota(child_activity_path, parent_activity_path): """ Lexically matches the questions in the child activity to @@ -27,13 +28,16 @@ def subset_items_dorota(child_activity_path, parent_activity_path): # parent_activity = load_file(parent_activity_path) return child_activity + def load_items(activity_path): items_path = activity_path + "items" items = {} for filename in os.listdir(items_path): # print(filename) - with open(items_path + "/" + filename, 'r', encoding='utf-8') as file: #replace with load file eventually - data = json.load(file) + with open( + items_path + "/" + filename, "r", encoding="utf-8" + ) as file: # replace with load file eventually + data = json.load(file) items[filename] = data return items @@ -44,8 +48,10 @@ def get_question(item_dict): else: return item_dict["question"] + def clean_sentence(sentence): - return ''.join(char.lower() for char in sentence if char.isalnum()) + return "".join(char.lower() for char in sentence if char.isalnum()) + def create_item_mapping(child_activity_path, parent_activity_path): child_items = load_items(child_activity_path) @@ -60,16 +66,12 @@ def create_item_mapping(child_activity_path, parent_activity_path): print(item_mapping) return item_mapping - - # child_items = [] # for filename in os.listdir(child_activity_path + "items"): # with open(file_path, 'r', encoding='utf-8') as file: #replace with load file eventually # data = json.load(file) - - # def subset_items_old():