Skip to content

Commit

Permalink
Merge pull request #636 from lognaturel/entities-in-repeat
Browse files Browse the repository at this point in the history
Show error when there are `save_to`s in a repeat, simplify entities tests
  • Loading branch information
lognaturel authored Jan 19, 2023
2 parents 16b25b5 + cefd5a4 commit 3c9448a
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 103 deletions.
11 changes: 9 additions & 2 deletions pyxform/entities/entities_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def get_entity_declaration(workbook_dict: Dict, warnings: List) -> Dict:
return {}
elif len(entities_sheet) > 1:
raise PyXFormError(
"This version of pyxform only supports declaring a single entity per form. Please make sure your entities sheet only declares one entity."
"Currently, you can only declare a single entity per form. Please make sure your entities sheet only declares one entity."
)

entity = entities_sheet[0]
Expand Down Expand Up @@ -57,7 +57,9 @@ def get_entity_declaration(workbook_dict: Dict, warnings: List) -> Dict:
}


def validate_entity_saveto(row: Dict, row_number: int, entity_declaration: Dict):
def validate_entity_saveto(
row: Dict, row_number: int, entity_declaration: Dict, in_repeat: bool
):
save_to = row.get("bind", {}).get("entities:saveto", "")
if not save_to:
return
Expand All @@ -74,6 +76,11 @@ def validate_entity_saveto(row: Dict, row_number: int, entity_declaration: Dict)
f"{constants.ROW_FORMAT_STRING % row_number} Groups and repeats can't be saved as entity properties."
)

if in_repeat:
raise PyXFormError(
f"{constants.ROW_FORMAT_STRING % row_number} Currently, you can't create entities from repeats. You may only specify save_to values for form fields outside of repeats."
)

error_start = f"{constants.ROW_FORMAT_STRING % row_number} Invalid save_to name:"

if save_to == "name" or save_to == "label":
Expand Down
3 changes: 2 additions & 1 deletion pyxform/xls2json.py
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,8 @@ def workbook_to_json(
f"{ROW_FORMAT_STRING % row_number} Invalid question name '{question_name}'. Names {XML_IDENTIFIER_ERROR_MESSAGE}"
)

validate_entity_saveto(row, row_number, entity_declaration)
in_repeat = any(ancestor["control_type"] == "repeat" for ancestor in stack)
validate_entity_saveto(row, row_number, entity_declaration, in_repeat)

# Try to parse question as begin control statement
# (i.e. begin loop/repeat/group):
Expand Down
151 changes: 51 additions & 100 deletions tests/test_entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@


class EntitiesTest(PyxformTestCase):
def test_dataset_in_entities_sheet__adds_meta_entity_block(self):
def test_basic_entity_creation_building_blocks(self):
self.assertPyxformXform(
name="data",
debug=True,
md="""
| survey | | | |
| | type | name | label |
Expand All @@ -14,7 +15,19 @@ def test_dataset_in_entities_sheet__adds_meta_entity_block(self):
| | dataset | label | |
| | trees | a | |
""",
xml__xpath_match=["/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity"],
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"]',
# defaults to always creating
'/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity[@create = "1"]',
'/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity[@id = ""]',
'/h:html/h:head/x:model/x:bind[@nodeset = "/data/meta/entity/@id" and @type = "string" and @readonly = "true()"]',
'/h:html/h:head/x:model/x:setvalue[@event = "odk-instance-first-load" and @type = "string" and @ref = "/data/meta/entity/@id" and @value = "uuid()"]',
"/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity/x:label",
'/h:html/h:head/x:model/x:bind[@nodeset = "/data/meta/entity/label" and @type = "string" and @readonly = "true()" and @calculate = "a"]',
'/h:html/h:head/x:model[@entities:entities-version = "2022.1.0"]',
],
xml__contains=['xmlns:entities="http://www.opendatakit.org/xforms/entities"'],
)

def test_multiple_dataset_rows_in_entities_sheet__errors(self):
Expand All @@ -31,23 +44,7 @@ def test_multiple_dataset_rows_in_entities_sheet__errors(self):
""",
errored=True,
error__contains=[
"This version of pyxform only supports declaring a single entity per form. Please make sure your entities sheet only declares one entity."
],
)

def test_dataset_in_entities_sheet__adds_dataset_attribute_to_entity(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | |
| | type | name | label |
| | text | a | A |
| entities | | | |
| | dataset | label | |
| | trees | a | |
""",
xml__xpath_match=[
'/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity[@dataset = "trees"]'
"Currently, you can only declare a single entity per form. Please make sure your entities sheet only declares one entity."
],
)

Expand Down Expand Up @@ -118,22 +115,6 @@ def test_worksheet_name_close_to_entities__produces_warning(self):
],
)

def test_dataset_in_entities_sheet__defaults_to_always_creating(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | |
| | type | name | label |
| | text | a | A |
| entities | | | |
| | dataset | label | |
| | trees | a | |
""",
xml__xpath_match=[
'/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity[@create = "1"]'
],
)

def test_create_if_in_entities_sheet__puts_expression_on_bind(self):
self.assertPyxformXform(
name="data",
Expand All @@ -151,41 +132,6 @@ def test_create_if_in_entities_sheet__puts_expression_on_bind(self):
],
)

def test_dataset_in_entities_sheet__adds_id_attribute_and_model_nodes_to_entity(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | |
| | type | name | label |
| | text | a | A |
| entities | | | |
| | dataset | label | |
| | trees | a | |
""",
xml__xpath_match=[
'/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity[@id = ""]',
'/h:html/h:head/x:model/x:bind[@nodeset = "/data/meta/entity/@id" and @type = "string" and @readonly = "true()"]',
'/h:html/h:head/x:model/x:setvalue[@event = "odk-instance-first-load" and @type = "string" and @ref = "/data/meta/entity/@id" and @value = "uuid()"]',
],
)

def test_label_in_entities_sheet__adds_label_and_bind_to_entity(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | |
| | type | name | label |
| | text | a | A |
| entities | | | |
| | dataset | label | |
| | trees | a | |
""",
xml__xpath_match=[
"/h:html/h:head/x:model/x:instance/x:data/x:meta/x:entity/x:label",
'/h:html/h:head/x:model/x:bind[@nodeset = "/data/meta/entity/label" and @type = "string" and @readonly = "true()" and @calculate = "a"]',
],
)

def test_label_and_create_if_in_entities_sheet__expand_node_selectors_to_xpath(self):
self.assertPyxformXform(
name="data",
Expand Down Expand Up @@ -218,20 +164,6 @@ def test_entity_label__required(self):
error__contains=["The entities sheet is missing the required label column."],
)

def test_dataset_in_entities_sheet__adds_entities_namespace(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | |
| | type | name | label |
| | text | a | A |
| entities | | | |
| | dataset | label | |
| | trees | a | |
""",
xml__contains=['xmlns:entities="http://www.opendatakit.org/xforms/entities"'],
)

def test_entities_namespace__omitted_if_no_entities_sheet(self):
self.assertPyxformXform(
name="data",
Expand All @@ -243,22 +175,6 @@ def test_entities_namespace__omitted_if_no_entities_sheet(self):
xml__excludes=['xmlns:entities="http://www.opendatakit.org/xforms/entities"'],
)

def test_dataset_in_entities_sheet__adds_entities_version(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | |
| | type | name | label |
| | text | a | A |
| entities | | | |
| | dataset | label | |
| | trees | a | |
""",
xml__xpath_match=[
'/h:html/h:head/x:model[@entities:entities-version = "2022.1.0"]'
],
)

def test_entities_version__omitted_if_no_entities_sheet(self):
self.assertPyxformXform(
name="data",
Expand Down Expand Up @@ -385,3 +301,38 @@ def test_saveto_on_group__errors(self):
"[row : 2] Groups and repeats can't be saved as entity properties."
],
)

def test_saveto_in_repeat__errors(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | | |
| | type | name | label | save_to |
| | begin_repeat| a | A | |
| | text | size | Size | size |
| | end_repeat | | | |
| entities | | | | |
| | dataset | label | | |
| | trees | ${size}| | |
""",
errored=True,
error__contains=[
"[row : 3] Currently, you can't create entities from repeats. You may only specify save_to values for form fields outside of repeats."
],
)

def test_saveto_in_group__works(self):
self.assertPyxformXform(
name="data",
md="""
| survey | | | | |
| | type | name | label | save_to |
| | begin_group | a | A | |
| | text | size | Size | size |
| | end_group | | | |
| entities | | | | |
| | dataset | label | | |
| | trees | ${size}| | |
""",
errored=False,
)

0 comments on commit 3c9448a

Please sign in to comment.