def test_equal(self): class SubObj(xmlmap.XmlObject): baz = xmlmap.StringField('baz') class XmlObj(xmlmap.XmlObject): bar = xmlmap.NodeField('bar', SubObj) bar_list = xmlmap.NodeListField('bar', SubObj) generic = xmlmap.NodeField('bar', xmlmap.XmlObject) obj = xmlmap.load_xmlobject_from_string(TestXsl.FIXTURE_TEXT, XmlObj) self.assertTrue(obj == obj, 'xmlobject identity equals obj == obj should return True') self.assertFalse(obj.bar != obj.bar, 'xmlobject identity not-equals obj != obj should return False') self.assertTrue(obj.bar == obj.bar_list[0], 'xmlobject equal should return True for objects pointing at same document node') self.assertFalse(obj.bar != obj.bar_list[0], 'xmlobject not equal should return False for objects pointing at same document node') self.assertTrue(obj.bar != obj.bar_list[1], 'xmlobject not equal should return True for objects pointing at different nodes') self.assertFalse(obj.bar == obj.bar_list[1], 'xmlobject equal should return False for object pointing at different nodes') obj2 = xmlmap.load_xmlobject_from_string(TestXsl.FIXTURE_TEXT, XmlObj) self.assertTrue(obj == obj2, 'two different xmlobjects that serialize the same should be considered equal') # compare to None self.assertTrue(obj != None, 'xmlobject not equal to None should return True') self.assertFalse(obj.bar == None, 'xmlobject equal None should return False') # FIXME: is this really what we want? # should different xmlobject classes pointing at the same node be considered equal? self.assertTrue(obj.generic == obj.bar, 'different xmlobject classes pointing at the same node are considered equal')
def test_isvalid(self): # attempting schema-validation on an xmlobject with no schema should raise an exception self.assertRaises(Exception, self.obj.schema_valid) # generic validation with no schema -- assumed True self.assertTrue(self.obj.is_valid()) # very simple xsd schema and valid/invalid xml taken from lxml docs: # http://codespeak.net/lxml/validation.html#xmlschema xsd = '''<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="a" type="AType"/> <xsd:complexType name="AType"> <xsd:sequence> <xsd:element name="b" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:schema> ''' FILE = tempfile.NamedTemporaryFile(mode="w") FILE.write(xsd) FILE.flush() valid_xml = '<a><b></b></a>' invalid_xml = '<a foo="1"><c></c></a>' class TestSchemaObject(xmlmap.XmlObject): XSD_SCHEMA = FILE.name valid = xmlmap.load_xmlobject_from_string(valid_xml, TestSchemaObject) self.assertTrue(valid.is_valid()) self.assertTrue(valid.schema_valid()) invalid = xmlmap.load_xmlobject_from_string(invalid_xml, TestSchemaObject) self.assertFalse(invalid.is_valid()) invalid.is_valid() self.assertEqual(2, len(invalid.validation_errors())) # do schema validation at load time valid = xmlmap.load_xmlobject_from_string(valid_xml, TestSchemaObject, validate=True) self.assert_(isinstance(valid, TestSchemaObject)) self.assertRaises(etree.XMLSyntaxError, xmlmap.load_xmlobject_from_string, invalid_xml, TestSchemaObject, validate=True) FILE.close()
def test_equal(self): class SubObj(xmlmap.XmlObject): baz = xmlmap.StringField('baz') class XmlObj(xmlmap.XmlObject): bar = xmlmap.NodeField('bar', SubObj) bar_list = xmlmap.NodeListField('bar', SubObj) generic = xmlmap.NodeField('bar', xmlmap.XmlObject) obj = xmlmap.load_xmlobject_from_string(TestXsl.FIXTURE_TEXT, XmlObj) self.assertTrue( obj == obj, 'xmlobject identity equals obj == obj should return True') self.assertFalse( obj.bar != obj.bar, 'xmlobject identity not-equals obj != obj should return False') self.assertTrue( obj.bar == obj.bar_list[0], 'xmlobject equal should return True for objects pointing at same document node' ) self.assertFalse( obj.bar != obj.bar_list[0], 'xmlobject not equal should return False for objects pointing at same document node' ) self.assertTrue( obj.bar != obj.bar_list[1], 'xmlobject not equal should return True for objects pointing at different nodes' ) self.assertFalse( obj.bar == obj.bar_list[1], 'xmlobject equal should return False for object pointing at different nodes' ) obj2 = xmlmap.load_xmlobject_from_string(TestXsl.FIXTURE_TEXT, XmlObj) self.assertTrue( obj == obj2, 'two different xmlobjects that serialize the same should be considered equal' ) # compare to None self.assertTrue(obj != None, 'xmlobject not equal to None should return True') self.assertFalse(obj.bar == None, 'xmlobject equal None should return False') # FIXME: is this really what we want? # should different xmlobject classes pointing at the same node be considered equal? self.assertTrue( obj.generic == obj.bar, 'different xmlobject classes pointing at the same node are considered equal' )
def test_serializeDocument(self): obj = xmlmap.load_xmlobject_from_string(TestXmlObjectStringInit.VALID_XML) xmlstr = obj.serializeDocument() self.assert_("encoding='UTF-8'" in xmlstr, "XML generated by serializeDocument should include xml character encoding") self.assert_('<!DOCTYPE a' in xmlstr, "XML generated by serializeDocument should include DOCTYPE declaration")
def prepared_ead(request, archive, filename, mode): """Display information about changes made by preparing an EAD file for publication. If no changes are made, user will be redirected to main admin page with a message to that effect. In **summary** mode, displays a brief, color-coded summary of changes between original and prepped version of the file. In **diff** mode, displays a full, side-by-side diff generated by :class:`difflib.HtmlDiff`. (Note: because it is very large, the full diff is *not* embedded in the site template, and is intended to be opened in a new window.) :param filename: name of the file to prep; should be base filename only, document will be pulled from the configured source directory. :param mode: one of **diff** or **summary** """ # determine full path based on archive / svn arch = Archive.objects.get(slug=archive) # arch = get_object_or_404(Archive, slug=archive) fullpath = os.path.join(arch.svn_local_path, filename) changes = [] # TODO: expire cache if file has changed since prepped eadxml was cached prep_ead = prepared_eadxml(request, arch.slug, filename) if prep_ead.status_code == 200: orig_ead = load_xmlobject_from_file(fullpath, FindingAid) # validate or not? original_xml = orig_ead.serializeDocument() # store as serialized by xml object, so xml output will be the same prep_xml = prep_ead.content ead = load_xmlobject_from_string(prep_xml, FindingAid) # validate? if mode == 'diff': diff = difflib.HtmlDiff(8, 80) # set columns to wrap at 80 characters # generate a html table with line-by-line comparison (meant to be called in a new window) changes = diff.make_file(original_xml.split('\n'), prep_xml.split('\n')) return HttpResponse(changes) elif mode == 'summary': # prepared EAD should pass sanity checks required for publication errors = utils.check_eadxml(ead) changes = list(difflib.unified_diff(original_xml.split('\n'), prep_xml.split('\n'))) if not changes: messages.info(request, 'No changes made to <b>%s</b>; EAD is already prepared.' % filename) # redirect to main admin page with code 303 (See Other) return HttpResponseSeeOtherRedirect(reverse('fa-admin:index')) elif prep_ead.status_code == 500: # something went wrong with generating prep xml; could be one of: # - non-well-formed xml (failed to load original document at all) # - error generating an ARK for the document errors = [prep_ead.content] else: # this shouldn't happen; not 200 or 500 == something went dreadfully wrong errors = ['Something went wrong trying to load the specified document.', prep_ead.content] # pass along the output in case it is useful? return render(request, 'fa_admin/prepared.html', { 'filename': filename, 'changes': changes, 'errors': errors, 'xml_status': prep_ead.status_code, 'archive': arch})
def test_serializeDocument(self): obj = xmlmap.load_xmlobject_from_string(TestXmlObjectStringInit.VALID_XML) xmlstr = obj.serializeDocument() self.assert_(b"encoding='UTF-8'" in xmlstr, "XML generated by serializeDocument should include xml character encoding") self.assert_(b'<!DOCTYPE a' in xmlstr, "XML generated by serializeDocument should include DOCTYPE declaration")
def get_section_elements(self): def include_sort(detail_type, detail): return detail_type.endswith( 'short') or detail.sort_nodeset_columns_for_detail() r = [] if not self.app.use_custom_suite: for module in self.modules: for detail_type, detail, enabled in module.get_details(): if enabled: if detail.custom_xml: d = load_xmlobject_from_string(detail.custom_xml, xmlclass=Detail) r.append(d) else: detail_column_infos = get_detail_column_infos( detail_type, detail, include_sort=include_sort(detail_type, detail), ) # list of DetailColumnInfo named tuples if detail_column_infos: if detail.use_case_tiles: helper = CaseTileHelper( self.app, module, detail, detail_type, self.build_profile_id) r.append(helper.build_case_tile_detail()) else: print_template_path = None if detail.print_template: print_template_path = detail.print_template[ 'path'] locale_id = id_strings.detail_title_locale( detail_type) title = Text(locale_id=locale_id ) if locale_id else Text() d = self.build_detail( module, detail_type, detail, detail_column_infos, tabs=list(detail.get_tabs()), id=id_strings.detail( module, detail_type), title=title, print_template=print_template_path, ) if d: r.append(d) # add the persist case context if needed and if # case tiles are present and have their own persistent block if (detail.persist_case_context and not (detail.use_case_tiles and detail.persist_tile_on_forms)): d = self._get_persistent_case_context_detail( module, detail.persistent_case_context_xml) r.append(d) if module.fixture_select.active: d = self._get_fixture_detail(module) r.append(d) return r
def test_load_from_string_with_classname(self): """Test using shortcut to initialize named XmlObject class from string""" class TestObject(xmlmap.XmlObject): pass obj = xmlmap.load_xmlobject_from_string(TestXsl.FIXTURE_TEXT, TestObject) self.assert_(isinstance(obj, TestObject))
def test_load_from_string_with_validation(self): self.assertRaises(Exception, xmlmap.load_xmlobject_from_string, self.INVALID_XML, validate=True) # fixture with no doctype also causes a validation error self.assertRaises(Exception, xmlmap.load_xmlobject_from_string, TestXsl.FIXTURE_TEXT, validate=True) obj = xmlmap.load_xmlobject_from_string(self.VALID_XML) self.assert_(isinstance(obj, xmlmap.XmlObject))
def get_section_elements(self): r = [] if not self.app.use_custom_suite: for module in self.modules: for detail_type, detail, enabled in module.get_details(): if enabled: if detail.custom_xml: d = load_xmlobject_from_string( detail.custom_xml, xmlclass=Detail ) r.append(d) else: detail_column_infos = get_detail_column_infos( detail, include_sort=detail_type.endswith('short'), ) if detail_column_infos: if detail.use_case_tiles: r.append(self.build_case_tile_detail( module, detail, detail_type )) else: d = self.build_detail( module, detail_type, detail, detail_column_infos, list(detail.get_tabs()), id_strings.detail(module, detail_type), Text(locale_id=id_strings.detail_title_locale( module, detail_type )), 0, len(detail_column_infos) ) if d: r.append(d) if module.fixture_select.active: d = Detail( id=id_strings.fixture_detail(module), title=Text(), ) xpath = Xpath(function=module.fixture_select.display_column) if module.fixture_select.localize: template_text = Text(locale=Locale(child_id=Id(xpath=xpath))) else: template_text = Text(xpath_function=module.fixture_select.display_column) fields = [Field(header=Header(text=Text()), template=Template(text=template_text), sort_node='')] d.fields = fields r.append(d) return r
def test_load_from_string_with_duplicate_ids(self): """ Test using shortcut to initialize XmlObject from string. When the source has duplicate IDs. """ self.assertRaises(etree.XMLSyntaxError, xmlmap.load_xmlobject_from_string, self.DUPLICATE_IDS, validate=True) obj = xmlmap.load_xmlobject_from_string(self.DUPLICATE_IDS) self.assert_(isinstance(obj, xmlmap.XmlObject))
def _add_custom_variables(self, detail, d): custom_variables = detail.custom_variables if custom_variables: custom_variable_elements = [ variable for variable in etree.fromstring("<variables>{}</variables>".format(custom_variables)) ] d.variables.extend([ load_xmlobject_from_string(etree.tostring(e), xmlclass=DetailVariable) for e in custom_variable_elements ])
def get_section_elements(self): def include_sort(detail_type, detail): return detail_type.endswith('short') or detail.sort_nodeset_columns_for_detail() r = [] if not self.app.use_custom_suite: for module in self.modules: for detail_type, detail, enabled in module.get_details(): if enabled: if detail.custom_xml: d = load_xmlobject_from_string( detail.custom_xml, xmlclass=Detail ) r.append(d) else: detail_column_infos = get_detail_column_infos( detail_type, detail, include_sort=include_sort(detail_type, detail), ) # list of DetailColumnInfo named tuples if detail_column_infos: if detail.use_case_tiles: helper = CaseTileHelper(self.app, module, detail, detail_type, self.build_profile_id) r.append(helper.build_case_tile_detail()) else: print_template_path = None if detail.print_template: print_template_path = detail.print_template['path'] locale_id = id_strings.detail_title_locale(detail_type) title = Text(locale_id=locale_id) if locale_id else Text() d = self.build_detail( module, detail_type, detail, detail_column_infos, tabs=list(detail.get_tabs()), id=id_strings.detail(module, detail_type), title=title, print_template=print_template_path, ) if d: r.append(d) # add the persist case context if needed and if # case tiles are present and have their own persistent block if (detail.persist_case_context and not (detail.use_case_tiles and detail.persist_tile_on_forms)): d = self._get_persistent_case_context_detail(module, detail.persistent_case_context_xml) r.append(d) if module.fixture_select.active: d = self._get_fixture_detail(module) r.append(d) return r
def _get_custom_xml_detail(self, module, detail, detail_type): d = load_xmlobject_from_string(detail.custom_xml, xmlclass=Detail) expected = id_strings.detail(module, detail_type) if not id_strings.is_custom_app_string(d.id) and d.id != expected: raise SuiteValidationError( "Menu {}, \"{}\", uses custom case list xml. The " "specified detail ID is '{}', expected '{}'".format( module.id, module.default_name(), d.id, expected)) return d
def build_case_tile_detail(self, module, detail, detail_type): """ Return a Detail node from an apps.app_manager.models.Detail that is configured to use case tiles. This method does so by injecting the appropriate strings into a template string. """ from corehq.apps.app_manager.detail_screen import get_column_xpath_generator template_args = { "detail_id": id_strings.detail(module, detail_type), "title_text_id": id_strings.detail_title_locale( module, detail_type ) } # Get field/case property mappings cols_by_tile = {col.case_tile_field: col for col in detail.columns} for template_field in ["header", "top_left", "sex", "bottom_left", "date"]: column = cols_by_tile.get(template_field, None) if column is None: raise SuiteError( 'No column was mapped to the "{}" case tile field'.format( template_field ) ) template_args[template_field] = { "prop_name": get_column_xpath_generator( self.app, module, detail, column ).xpath, "locale_id": id_strings.detail_column_header_locale( module, detail_type, column, ), # Just using default language for now # The right thing to do would be to reference the app_strings.txt I think "prefix": escape( column.header.get(self.app.default_language, "") ) } if column.format == "enum": template_args[template_field]["enum_keys"] = {} for mapping in column.enum: template_args[template_field]["enum_keys"][mapping.key] = \ id_strings.detail_column_enum_variable( module, detail_type, column, mapping.key_as_variable ) # Populate the template detail_as_string = self._case_tile_template_string.format(**template_args) return load_xmlobject_from_string(detail_as_string, xmlclass=Detail)
def get_section_elements(self): r = [] if not self.app.use_custom_suite: for module in self.modules: for detail_type, detail, enabled in module.get_details(): if enabled: if detail.custom_xml: d = load_xmlobject_from_string(detail.custom_xml, xmlclass=Detail) r.append(d) else: detail_column_infos = get_detail_column_infos( detail, include_sort=detail_type.endswith('short'), ) # list of DetailColumnInfo named tuples if detail_column_infos: if detail.use_case_tiles: helper = CaseTileHelper( self.app, module, detail, detail_type, self.build_profile_id) r.append(helper.build_case_tile_detail()) else: print_template_path = None if detail.print_template: print_template_path = detail.print_template[ 'path'] d = self.build_detail( module, detail_type, detail, detail_column_infos, tabs=list(detail.get_tabs()), id=id_strings.detail( module, detail_type), title=Text(locale_id=id_strings. detail_title_locale( module, detail_type)), print_template=print_template_path, ) if d: r.append(d) if detail.persist_case_context and not detail.persist_tile_on_forms: d = self._get_persistent_case_context_detail( module, detail.persistent_case_context_xml) r.append(d) if module.fixture_select.active: d = self._get_fixture_detail(module) r.append(d) return r
def build_case_tile_detail(self): """ Return a Detail node from an apps.app_manager.models.Detail that is configured to use case tiles. This method does so by injecting the appropriate strings into a template string. """ # Get template context context = self._get_base_context() for template_field in self.tile_fields: column = self._get_matched_detail_column(template_field) context[template_field] = self._get_column_context(column) # Populate the template detail_as_string = self._case_tile_template_string.format(**context) return load_xmlobject_from_string(detail_as_string, xmlclass=Detail)
def testSchemaField(self): # very simple xsd schema and valid/invalid xml based on the one from lxml docs: # http://codespeak.net/lxml/validation.html#xmlschema xsd = '''<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="a" type="AType"/> <xsd:complexType name="AType"> <xsd:sequence> <xsd:element name="b" type="BType" /> </xsd:sequence> </xsd:complexType> <xsd:simpleType name="BType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="c"/> <xsd:enumeration value="d"/> <xsd:enumeration value="e"/> </xsd:restriction> </xsd:simpleType> </xsd:schema> ''' FILE = tempfile.NamedTemporaryFile(mode="w") FILE.write(xsd) FILE.flush() valid_xml = '<a><b>some text</b></a>' class TestSchemaObject(xmlmap.XmlObject): XSD_SCHEMA = FILE.name txt = xmlmap.SchemaField('/a/b', 'BType', required=True) valid = xmlmap.load_xmlobject_from_string(valid_xml, TestSchemaObject) self.assertEqual('some text', valid.txt, 'schema field value is accessible as text') self.assert_( isinstance(valid._fields['txt'], xmlmap.StringField), 'txt SchemaField with base string in schema initialized as StringField' ) self.assertEqual( ['', 'c', 'd', 'e'], valid._fields['txt'].choices, 'txt SchemaField has choices based on restriction enumeration in schema' ) # check required self.assertTrue(valid._fields['txt'].required) FILE.close()
def get_section_elements(self): r = [] if not self.app.use_custom_suite: for module in self.modules: for detail_type, detail, enabled in module.get_details(): if enabled: if detail.custom_xml: d = load_xmlobject_from_string( detail.custom_xml, xmlclass=Detail ) r.append(d) else: detail_column_infos = get_detail_column_infos( detail, include_sort=detail_type.endswith('short'), ) if detail_column_infos: if detail.use_case_tiles: helper = CaseTileHelper(self.app, module, detail, detail_type, self.build_profile_id) r.append(helper.build_case_tile_detail()) else: d = self.build_detail( module, detail_type, detail, detail_column_infos, tabs=list(detail.get_tabs()), id=id_strings.detail(module, detail_type), title=Text(locale_id=id_strings.detail_title_locale( module, detail_type )), ) if d: r.append(d) if detail.persist_case_context and not detail.persist_tile_on_forms: d = self._get_persistent_case_context_detail(module, detail.persistent_case_context_xml) r.append(d) if module.fixture_select.active: d = self._get_fixture_detail(module) r.append(d) return r
def testSchemaField(self): # very simple xsd schema and valid/invalid xml based on the one from lxml docs: # http://codespeak.net/lxml/validation.html#xmlschema xsd = '''<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="a" type="AType"/> <xsd:complexType name="AType"> <xsd:sequence> <xsd:element name="b" type="BType" /> </xsd:sequence> </xsd:complexType> <xsd:simpleType name="BType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="c"/> <xsd:enumeration value="d"/> <xsd:enumeration value="e"/> </xsd:restriction> </xsd:simpleType> </xsd:schema> ''' FILE = tempfile.NamedTemporaryFile(mode="w") FILE.write(xsd) FILE.flush() valid_xml = '<a><b>some text</b></a>' class TestSchemaObject(xmlmap.XmlObject): XSD_SCHEMA = FILE.name txt = xmlmap.SchemaField('/a/b', 'BType', required=True) valid = xmlmap.load_xmlobject_from_string(valid_xml, TestSchemaObject) self.assertEqual('some text', valid.txt, 'schema field value is accessible as text') self.assert_(isinstance(valid._fields['txt'], xmlmap.StringField), 'txt SchemaField with base string in schema initialized as StringField') self.assertEqual(['', 'c', 'd', 'e'], valid._fields['txt'].choices, 'txt SchemaField has choices based on restriction enumeration in schema') # check required self.assertTrue(valid._fields['txt'].required) FILE.close()
def setUp(self): self.obj = xmlmap.load_xmlobject_from_string(TestXsl.FIXTURE_TEXT)
def test_load_from_string(self): """Test using shortcut to initialize XmlObject from string""" obj = xmlmap.load_xmlobject_from_string(TestXsl.FIXTURE_TEXT) self.assert_(isinstance(obj, xmlmap.XmlObject))
def test__string(self): self.assertEqual('42 13', self.obj.__string__()) # convert xml with unicode content obj = xmlmap.load_xmlobject_from_string(u'<text>unicode \u2026</text>') self.assertEqual('unicode …', obj.__string__())
def test__string(self): self.assertEqual(b'42 13', self.obj.__string__()) # convert xml with unicode content obj = xmlmap.load_xmlobject_from_string(u'<text>unicode \u2026</text>') self.assertEqual(b'unicode …', obj.__string__())