Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show error when there are save_tos in a repeat, simplify entities tests #636

Merged
merged 3 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
)