From f61833e2ecc35e14fb94c9be6fa6b9e3156a0885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne=20Martin?= Date: Thu, 14 Sep 2023 21:11:19 -0700 Subject: [PATCH 1/4] Update gitignore for new versions --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0bd95956..508f675a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,12 +15,14 @@ tests/test_output build dist pyxform.egg-info +pip-wheel-metadata # By having build ignored above, this ignores documents created by # sphinx. Overall, I think this is a good thing. # a virtual environment env +venv # ignore pypi manifest MANIFEST From 038177064ae093ac0af00c20a28f85d4286d6a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne=20Martin?= Date: Thu, 14 Sep 2023 21:14:48 -0700 Subject: [PATCH 2/4] Add list_name alias for dataset --- pyxform/aliases.py | 3 +++ pyxform/entities/entities_parsing.py | 6 +++--- pyxform/xls2json.py | 6 +++++- tests/test_entities.py | 18 +++++++++++++++++- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/pyxform/aliases.py b/pyxform/aliases.py index 7af0d388..d7ca05d8 100644 --- a/pyxform/aliases.py +++ b/pyxform/aliases.py @@ -108,6 +108,9 @@ "parameters": "parameters", constants.ENTITIES_SAVETO: "bind::entities:saveto", } + +entities_header = {"list_name": "dataset"} + # Key is the pyxform internal name, Value is the name used in error/warning messages. TRANSLATABLE_SURVEY_COLUMNS = { constants.LABEL: constants.LABEL, diff --git a/pyxform/entities/entities_parsing.py b/pyxform/entities/entities_parsing.py index 42ee7ac9..578485c9 100644 --- a/pyxform/entities/entities_parsing.py +++ b/pyxform/entities/entities_parsing.py @@ -5,9 +5,9 @@ from pyxform.xlsparseutils import find_sheet_misspellings, is_valid_xml_tag -def get_entity_declaration(workbook_dict: Dict, warnings: List) -> Dict: - entities_sheet = workbook_dict.get(constants.ENTITIES, []) - +def get_entity_declaration( + entities_sheet: Dict, workbook_dict: Dict, warnings: List +) -> Dict: if len(entities_sheet) == 0: similar = find_sheet_misspellings( key=constants.ENTITIES, keys=workbook_dict.keys() diff --git a/pyxform/xls2json.py b/pyxform/xls2json.py index 1559bcd9..889b5099 100644 --- a/pyxform/xls2json.py +++ b/pyxform/xls2json.py @@ -538,7 +538,11 @@ def workbook_to_json( ) # noqa # ########## Entities sheet ########### - entity_declaration = get_entity_declaration(workbook_dict, warnings) + entities_sheet = workbook_dict.get(constants.ENTITIES, []) + entities_sheet = dealias_and_group_headers( + entities_sheet, aliases.entities_header, False + ) + entity_declaration = get_entity_declaration(entities_sheet, workbook_dict, warnings) # ########## Survey sheet ########### survey_sheet = workbook_dict[constants.SURVEY] diff --git a/tests/test_entities.py b/tests/test_entities.py index 01a0e705..c4ab300f 100644 --- a/tests/test_entities.py +++ b/tests/test_entities.py @@ -6,7 +6,6 @@ class EntitiesTest(PyxformTestCase): def test_basic_entity_creation_building_blocks(self): self.assertPyxformXform( name="data", - debug=True, md=""" | survey | | | | | | type | name | label | @@ -336,3 +335,20 @@ def test_saveto_in_group__works(self): """, errored=False, ) + + def test_list_name_alias_to_dataset(self): + self.assertPyxformXform( + name="data", + md=""" + | survey | | | | + | | type | name | label | + | | text | a | A | + | entities | | | | + | | list_name | label | | + | | trees | a | | + """, + xml__xpath_match=[ + "/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity", + '/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity[@dataset = "trees"]', + ], + ) From c67c0aa899cf5b3881ba8a5302f3bbbb32cb12e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne=20Martin?= Date: Fri, 15 Sep 2023 12:12:11 -0700 Subject: [PATCH 3/4] Use "entity list" in error messages --- pyxform/entities/entities_parsing.py | 6 +++--- tests/test_entities.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyxform/entities/entities_parsing.py b/pyxform/entities/entities_parsing.py index 578485c9..09cb8149 100644 --- a/pyxform/entities/entities_parsing.py +++ b/pyxform/entities/entities_parsing.py @@ -25,12 +25,12 @@ def get_entity_declaration( if dataset.startswith(constants.ENTITIES_RESERVED_PREFIX): raise PyXFormError( - f"Invalid dataset name: '{dataset}' starts with reserved prefix {constants.ENTITIES_RESERVED_PREFIX}." + f"Invalid entity list name: '{dataset}' starts with reserved prefix {constants.ENTITIES_RESERVED_PREFIX}." ) if "." in dataset: raise PyXFormError( - f"Invalid dataset name: '{dataset}'. Dataset names may not include periods." + f"Invalid entity list name: '{dataset}'. Names may not include periods." ) if not is_valid_xml_tag(dataset): @@ -38,7 +38,7 @@ def get_entity_declaration( dataset = dataset.encode("utf-8") raise PyXFormError( - f"Invalid dataset name: '{dataset}'. Dataset names must begin with a letter, colon, or underscore. Other characters can include numbers or dashes." + f"Invalid entity list name: '{dataset}'. Names must begin with a letter, colon, or underscore. Other characters can include numbers or dashes." ) if not ("label" in entity): diff --git a/tests/test_entities.py b/tests/test_entities.py index c4ab300f..794a327e 100644 --- a/tests/test_entities.py +++ b/tests/test_entities.py @@ -60,7 +60,7 @@ def test_dataset_with_reserved_prefix__errors(self): """, errored=True, error__contains=[ - "Invalid dataset name: '__sweet' starts with reserved prefix __." + "Invalid entity list name: '__sweet' starts with reserved prefix __." ], ) @@ -77,7 +77,7 @@ def test_dataset_with_invalid_xml_name__errors(self): """, errored=True, error__contains=[ - "Invalid dataset name: '$sweet'. Dataset names must begin with a letter, colon, or underscore. Other characters can include numbers or dashes." + "Invalid entity list name: '$sweet'. Names must begin with a letter, colon, or underscore. Other characters can include numbers or dashes." ], ) @@ -94,7 +94,7 @@ def test_dataset_with_period_in_name__errors(self): """, errored=True, error__contains=[ - "Invalid dataset name: 's.w.eet'. Dataset names may not include periods." + "Invalid entity list name: 's.w.eet'. Names may not include periods." ], ) From 56f9906a2352c0ecea6e3011da574b47afbbf258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne=20Martin?= Date: Fri, 15 Sep 2023 12:36:38 -0700 Subject: [PATCH 4/4] Make check for reserved entity properties case-insensitive --- pyxform/entities/entities_parsing.py | 2 +- tests/test_entities.py | 34 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/pyxform/entities/entities_parsing.py b/pyxform/entities/entities_parsing.py index 09cb8149..7a629d17 100644 --- a/pyxform/entities/entities_parsing.py +++ b/pyxform/entities/entities_parsing.py @@ -83,7 +83,7 @@ def validate_entity_saveto( error_start = f"{constants.ROW_FORMAT_STRING % row_number} Invalid save_to name:" - if save_to == "name" or save_to == "label": + if save_to.lower() == "name" or save_to.lower() == "label": raise PyXFormError( f"{error_start} the entity property name '{save_to}' is reserved." ) diff --git a/tests/test_entities.py b/tests/test_entities.py index 794a327e..6127f616 100644 --- a/tests/test_entities.py +++ b/tests/test_entities.py @@ -232,6 +232,23 @@ def test_name_in_saveto_column__errors(self): ], ) + def test_naMe_in_saveto_column__errors(self): + self.assertPyxformXform( + name="data", + md=""" + | survey | | | | | + | | type | name | label | save_to | + | | text | a | A | naMe | + | entities | | | | | + | | dataset | label | | | + | | trees | a | | | + """, + errored=True, + error__contains=[ + "[row : 2] Invalid save_to name: the entity property name 'naMe' is reserved." + ], + ) + def test_label_in_saveto_column__errors(self): self.assertPyxformXform( name="data", @@ -249,6 +266,23 @@ def test_label_in_saveto_column__errors(self): ], ) + def test_lAbEl_in_saveto_column__errors(self): + self.assertPyxformXform( + name="data", + md=""" + | survey | | | | | + | | type | name | label | save_to | + | | text | a | A | lAbEl | + | entities | | | | | + | | dataset | label | | | + | | trees | a | | | + """, + errored=True, + error__contains=[ + "[row : 2] Invalid save_to name: the entity property name 'lAbEl' is reserved." + ], + ) + def test_system_prefix_in_saveto_column__errors(self): self.assertPyxformXform( name="data",