-
Notifications
You must be signed in to change notification settings - Fork 138
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial support for entity creation (#624)
- Loading branch information
1 parent
2b150d3
commit d9413b5
Showing
13 changed files
with
649 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
from typing import Dict, List | ||
|
||
from pyxform import constants | ||
from pyxform.errors import PyXFormError | ||
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, []) | ||
|
||
if len(entities_sheet) == 0: | ||
similar = find_sheet_misspellings( | ||
key=constants.ENTITIES, keys=workbook_dict.keys() | ||
) | ||
if similar is not None: | ||
warnings.append(similar + constants._MSG_SUPPRESS_SPELLING) | ||
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." | ||
) | ||
|
||
entity = entities_sheet[0] | ||
dataset = entity["dataset"] | ||
|
||
if dataset.startswith(constants.ENTITIES_RESERVED_PREFIX): | ||
raise PyXFormError( | ||
f"Invalid dataset 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." | ||
) | ||
|
||
if not is_valid_xml_tag(dataset): | ||
if isinstance(dataset, bytes): | ||
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." | ||
) | ||
|
||
if not ("label" in entity): | ||
raise PyXFormError("The entities sheet is missing the required label column.") | ||
|
||
creation_condition = entity["create_if"] if "create_if" in entity else "1" | ||
|
||
return { | ||
"name": "entity", | ||
"type": "entity", | ||
"parameters": { | ||
"dataset": dataset, | ||
"create": creation_condition, | ||
"label": entity["label"], | ||
}, | ||
} | ||
|
||
|
||
def validate_entity_saveto(row: Dict, row_number: int, entity_declaration: Dict): | ||
save_to = row.get("bind", {}).get("entities:saveto", "") | ||
if not save_to: | ||
return | ||
|
||
if len(entity_declaration) == 0: | ||
raise PyXFormError( | ||
"To save entity properties using the save_to column, you must add an entities sheet and declare an entity." | ||
) | ||
|
||
if constants.GROUP in row.get(constants.TYPE) or constants.REPEAT in row.get( | ||
constants.TYPE | ||
): | ||
raise PyXFormError( | ||
f"{constants.ROW_FORMAT_STRING % row_number} Groups and repeats can't be saved as entity properties." | ||
) | ||
|
||
error_start = f"{constants.ROW_FORMAT_STRING % row_number} Invalid save_to name:" | ||
|
||
if save_to == "name" or save_to == "label": | ||
raise PyXFormError( | ||
f"{error_start} the entity property name '{save_to}' is reserved." | ||
) | ||
|
||
if save_to.startswith(constants.ENTITIES_RESERVED_PREFIX): | ||
raise PyXFormError( | ||
f"{error_start} the entity property name '{save_to}' starts with reserved prefix {constants.ENTITIES_RESERVED_PREFIX}." | ||
) | ||
|
||
if not is_valid_xml_tag(save_to): | ||
if isinstance(save_to, bytes): | ||
save_to = save_to.encode("utf-8") | ||
|
||
raise PyXFormError( | ||
f"{error_start} '{save_to}'. Entity property names {constants.XML_IDENTIFIER_ERROR_MESSAGE}" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
from pyxform.survey_element import SurveyElement | ||
from pyxform.utils import node | ||
|
||
|
||
class EntityDeclaration(SurveyElement): | ||
def xml_instance(self, **kwargs): | ||
attributes = {} | ||
attributes["dataset"] = self.get("parameters", {}).get("dataset", "") | ||
attributes["create"] = "1" | ||
attributes["id"] = "" | ||
|
||
label_node = node("label") | ||
return node("entity", label_node, **attributes) | ||
|
||
def xml_bindings(self): | ||
survey = self.get_root() | ||
|
||
create_expr = survey.insert_xpaths( | ||
self.get("parameters", {}).get("create", "true()"), context=self | ||
) | ||
create_bind = { | ||
"calculate": create_expr, | ||
"type": "string", | ||
"readonly": "true()", | ||
} | ||
create_node = node("bind", nodeset=self.get_xpath() + "/@create", **create_bind) | ||
|
||
id_bind = {"type": "string", "readonly": "true()"} | ||
id_node = node("bind", nodeset=self.get_xpath() + "/@id", **id_bind) | ||
|
||
id_setvalue_attrs = { | ||
"event": "odk-instance-first-load", | ||
"type": "string", | ||
"readonly": "true()", | ||
"value": "uuid()", | ||
} | ||
id_setvalue = node("setvalue", ref=self.get_xpath() + "/@id", **id_setvalue_attrs) | ||
|
||
label_expr = survey.insert_xpaths( | ||
self.get("parameters", {}).get("label", ""), context=self | ||
) | ||
label_bind = { | ||
"calculate": label_expr, | ||
"type": "string", | ||
"readonly": "true()", | ||
} | ||
label_node = node("bind", nodeset=self.get_xpath() + "/label", **label_bind) | ||
return [create_node, id_node, id_setvalue, label_node] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.