fields: add explicit typing of (some) attributes in export/import (#59756)

This commit is contained in:
Frédéric Péters 2021-12-15 17:46:14 +01:00
parent caccc2f0eb
commit 22e2b58123
2 changed files with 26 additions and 4 deletions

View File

@ -135,6 +135,15 @@ def test_a_field(pub):
assert len(f2.fields) == len(formdef.fields)
def test_field_with_True_as_label(pub):
formdef = FormDef()
formdef.name = 'Foo'
formdef.url_name = 'foo'
formdef.fields = [fields.StringField(type='string', id=1, label='True', size='40')]
f2 = assert_xml_import_export_works(formdef)
assert f2.fields[0].label == 'True'
def test_more_fields(pub):
formdef = FormDef()
formdef.name = 'Blah'
@ -371,8 +380,7 @@ def test_invalid_data_source(pub):
formdef = FormDef()
formdef.name = 'foo'
formdef.fields = [fields.StringField(id='1', type='string', data_source={'type': 'xxx'})]
export = ET.tostring(export_to_indented_xml(formdef))
export = export.replace(b'\n', b'').replace(b' ', b'')
export = ET.tostring(formdef.export_to_xml(include_id=False))
export = export.replace(
b'<data_source><type>xxx</type></data_source>', b'<data_source><type/></data_source>'
)

View File

@ -268,6 +268,10 @@ class Field:
anonymise = True
stats = None
# declarations for serialization, they are mostly for legacy files,
# new exports directly include typing attributes.
TEXT_ATTRIBUTES = ['label', 'type', 'hint', 'varname', 'extra_css_class']
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k.replace('-', '_'), v)
@ -358,9 +362,14 @@ class Field:
for v in val:
ET.SubElement(el, atname).text = force_text(v, charset, errors='replace')
elif isinstance(val, str):
el.attrib['type'] = 'str'
el.text = force_text(val, charset, errors='replace')
else:
el.text = str(val)
if isinstance(val, bool):
el.attrib['type'] = 'bool'
elif isinstance(val, int):
el.attrib['type'] = 'int'
return field
def init_with_xml(self, elem, charset, include_id=False, snapshot=False):
@ -387,14 +396,19 @@ class Field:
raise AssertionError
setattr(self, attribute, v)
else:
if attribute in self.TEXT_ATTRIBUTES:
elem_type = 'str'
else:
elem_type = el.attrib.get('type')
if el.text is None:
if isinstance(getattr(self, attribute), list):
setattr(self, attribute, [])
else:
setattr(self, attribute, None)
elif el.text in ('False', 'True'): # bools
elif elem_type == 'bool' or (not elem_type and el.text in ('False', 'True')):
# boolean
setattr(self, attribute, el.text == 'True')
elif isinstance(getattr(self, attribute), int):
elif elem_type == 'int' or (not elem_type and isinstance(getattr(self, attribute), int)):
setattr(self, attribute, int(el.text))
else:
setattr(self, attribute, xml_node_text(el))