def test_sanitize_attribute_sequence(self): def len_sequential(target): return len( [attr for attr in attrs if attr.restrictions.sequential]) restrictions = Restrictions(max_occurs=2, sequential=True) attrs = [ AttrFactory.create(restrictions=restrictions.clone()), AttrFactory.create(restrictions=restrictions.clone()), ] attrs_clone = [attr.clone() for attr in attrs] ClassUtils.sanitize_attribute_sequence(attrs, 0) self.assertEqual(2, len_sequential(attrs)) attrs[0].restrictions.sequential = False ClassUtils.sanitize_attribute_sequence(attrs, 0) self.assertEqual(1, len_sequential(attrs)) ClassUtils.sanitize_attribute_sequence(attrs, 1) self.assertEqual(0, len_sequential(attrs)) attrs_clone[1].restrictions.sequential = False ClassUtils.sanitize_attribute_sequence(attrs_clone, 0) self.assertEqual(0, len_sequential(attrs_clone))
def test_sanitize_restrictions(self): restrictions = [ Restrictions(min_occurs=0, max_occurs=0, required=True), Restrictions(min_occurs=0, max_occurs=1, required=True), Restrictions(min_occurs=1, max_occurs=1, required=False), Restrictions(max_occurs=2, required=True), Restrictions(min_occurs=2, max_occurs=2, required=True), ] expected = [ {}, {}, { "required": True }, { "max_occurs": 2, "min_occurs": 0 }, { "max_occurs": 2, "min_occurs": 2 }, ] for idx, res in enumerate(restrictions): ClassUtils.sanitize_restrictions(res) self.assertEqual(expected[idx], res.asdict())
def test_create_default_attribute_with_any_type(self): extension = ExtensionFactory.create( type=AttrTypeFactory.xs_any(), restrictions=Restrictions(min_occurs=1, max_occurs=1, required=True), ) item = ClassFactory.create(extensions=[extension]) ClassUtils.create_default_attribute(item, extension) expected = AttrFactory.create( name="any_element", index=0, wildcard=True, default=None, types=[extension.type.clone()], local_type=TagType.ANY, namespace="##any", restrictions=Restrictions(min_occurs=1, max_occurs=1, required=True), ) self.assertEqual(1, len(item.attrs)) self.assertEqual(0, len(item.extensions)) self.assertEqual(expected, item.attrs[0])
def test_property_is_list(self): restrictions = Restrictions() self.assertFalse(restrictions.is_list) restrictions.max_occurs = 1 self.assertFalse(restrictions.is_list) restrictions.max_occurs = 2 self.assertTrue(restrictions.is_list)
def test_update(self): source = Restrictions(min_length=2, max_length=10) target = Restrictions(min_length=1, pattern=r"[A-Z]") target.merge(source) self.assertEqual(2, target.min_length) self.assertEqual(10, target.max_length) self.assertEqual(r"[A-Z]", target.pattern)
def test_element_children(self): sequence_one = Sequence.create(elements=[Element.create(), Element.create()]) sequence_two = Sequence.create( max_occurs=2, elements=[Element.create(), Element.create()] ) restriction = Restriction.create( enumerations=[Enumeration.create(value=x) for x in "abc"], sequence=sequence_two, ) complex_type = ComplexType.create( attributes=[Attribute.create(), Attribute.create()], sequence=sequence_one, simple_content=SimpleContent.create(restriction=Restriction.create()), complex_content=ComplexContent.create(restriction=restriction,), ) children = self.builder.element_children(complex_type) expected = [ (sequence_two.elements[0], Restrictions.from_element(sequence_two)), (sequence_two.elements[1], Restrictions.from_element(sequence_two)), (restriction.enumerations[0], Restrictions.from_element(restriction)), (restriction.enumerations[1], Restrictions.from_element(restriction)), (restriction.enumerations[2], Restrictions.from_element(restriction)), (sequence_one.elements[0], Restrictions.from_element(sequence_one)), (sequence_one.elements[1], Restrictions.from_element(sequence_one)), (complex_type.attributes[0], Restrictions.from_element(complex_type)), (complex_type.attributes[1], Restrictions.from_element(complex_type)), ] self.assertIsInstance(children, GeneratorType) self.assertEqual(expected, list(children))
def element_children( self, obj: ElementBase, restrictions: Optional[Restrictions] = None ) -> Iterator[Tuple[AttributeElement, Restrictions]]: """Recursively find and return all child elements that are qualified to be class attributes.""" for child in obj.children(): if child.is_attribute: yield child, restrictions or Restrictions() else: yield from self.element_children( child, restrictions=Restrictions.from_element(child) )
def build_class_attribute(self, target: Class, obj: ElementBase, parent_restrictions: Restrictions): """Generate and append an attribute target to the target class.""" types = self.build_class_attribute_types(target, obj) restrictions = Restrictions.from_element(obj) if obj.class_name in (Tag.ELEMENT, Tag.ANY): restrictions.merge(parent_restrictions) if restrictions.prohibited: return name = obj.real_name target.ns_map.update(obj.ns_map) target.attrs.append( Attr( index=obj.index, name=name, local_name=name, default=obj.default_value, fixed=obj.is_fixed, types=types, tag=obj.class_name, help=obj.display_help, namespace=self.element_namespace(obj), restrictions=restrictions, ))
def build_class_extension( self, target: Class, name: str, index: int, restrictions: Dict ): return Extension( type=self.build_data_type(target, name, index=index), restrictions=Restrictions(**restrictions), )
def test_build_class_attribute( self, mock_real_name, mock_display_help, mock_prefix, mock_default_value, mock_is_fixed, mock_is_wildcard, mock_get_restrictions, mock_element_namespace, mock_build_class_attribute_types, ): item = ClassFactory.create(ns_map={"bar": "foo"}) mock_build_class_attribute_types.return_value = AttrTypeFactory.list( 1, name="xs:int") mock_real_name.return_value = item.name mock_display_help.return_value = "sos" mock_prefix.return_value = "com" mock_default_value.return_value = "default" mock_is_fixed.return_value = True mock_is_wildcard.return_value = True mock_element_namespace.return_value = "http://something/common" mock_get_restrictions.return_value = {"required": True} attribute = Attribute.create(default="false", index=66, ns_map={"foo": "bar"}) self.builder.build_class_attribute(item, attribute, Restrictions()) expected = AttrFactory.create( name=mock_real_name.return_value, types=mock_build_class_attribute_types.return_value, local_type=Attribute.__name__, namespace=mock_element_namespace.return_value, help=mock_display_help.return_value, default=mock_default_value.return_value, fixed=mock_is_fixed.return_value, wildcard=mock_is_wildcard.return_value, index=66, restrictions=Restrictions(required=True), ) self.assertEqual(expected, item.attrs[0]) self.assertEqual({"bar": "foo", "foo": "bar"}, item.ns_map) mock_build_class_attribute_types.assert_called_once_with( item, attribute) mock_element_namespace.assert_called_once_with(attribute)
def test_asdict(self): restrictions = Restrictions( required=True, prohibited=None, min_occurs=1, max_occurs=1, min_exclusive=1.1, min_inclusive=1, min_length=1, max_exclusive=1, max_inclusive=1.1, max_length=10, total_digits=333, fraction_digits=2, length=5, white_space="collapse", pattern=r"[A-Z]", explicit_timezone="+1", nillable=True, ) expected = { "explicit_timezone": "+1", "fraction_digits": 2, "length": 5, "max_exclusive": 1, "max_inclusive": 1.1, "max_length": 10, "max_occurs": 1, "min_exclusive": 1.1, "min_inclusive": 1, "min_length": 1, "min_occurs": 1, "nillable": True, "pattern": "[A-Z]", "required": True, "total_digits": 333, "white_space": "collapse", } self.assertEqual(expected, restrictions.asdict())
def sanitize_restrictions(cls, restrictions: Restrictions): min_occurs = restrictions.min_occurs or 0 max_occurs = restrictions.max_occurs or 0 if min_occurs == 0 and max_occurs <= 1: restrictions.required = None restrictions.min_occurs = None restrictions.max_occurs = None if min_occurs == 1 and max_occurs == 1: restrictions.required = True restrictions.min_occurs = None restrictions.max_occurs = None elif restrictions.max_occurs and max_occurs > 1: restrictions.min_occurs = min_occurs restrictions.required = None
def test_merge_duplicate_attributes(self): one = AttrFactory.attribute(fixed=True) one_clone = one.clone() restrictions = Restrictions(min_occurs=10, max_occurs=15) two = AttrFactory.element(restrictions=restrictions, fixed=True) two_clone = two.clone() two_clone.restrictions.min_occurs = 5 two_clone.restrictions.max_occurs = 5 two_clone_two = two.clone() two_clone_two.restrictions.min_occurs = 4 two_clone_two.restrictions.max_occurs = 4 three = AttrFactory.element() four = AttrFactory.enumeration() four_clone = four.clone() five = AttrFactory.element() five_clone = five.clone() five_clone_two = five.clone() target = ClassFactory.create(attrs=[ one, one_clone, two, two_clone, two_clone_two, three, four, four_clone, five, five_clone, five_clone_two, ]) winners = [one, two, three, four, five] ClassUtils.merge_duplicate_attributes(target) self.assertEqual(winners, target.attrs) self.assertTrue(one.fixed) self.assertIsNone(one.restrictions.min_occurs) self.assertIsNone(one.restrictions.max_occurs) self.assertFalse(two.fixed) self.assertEqual(4, two.restrictions.min_occurs) self.assertEqual(24, two.restrictions.max_occurs) self.assertIsNone(three.restrictions.min_occurs) self.assertIsNone(three.restrictions.max_occurs) self.assertIsNone(four.restrictions.min_occurs) self.assertIsNone(four.restrictions.max_occurs) self.assertEqual(0, five.restrictions.min_occurs) self.assertEqual(3, five.restrictions.max_occurs)
def test_merge_redefined_classes_copies_extensions(self): class_a = ClassFactory.create() class_c = class_a.clone() type_int = AttrTypeFactory.xs_int() ext_a = ExtensionFactory.create( type=type_int, restrictions=Restrictions(max_inclusive=10, min_inclusive=1, required=True), ) ext_c = ExtensionFactory.create( type=AttrTypeFactory.create(name=class_a.name), restrictions=Restrictions(max_inclusive=0, min_inclusive=-10), ) class_a.extensions.append(ext_a) class_c.extensions.append(ext_c) classes = [class_a, class_c] expected = {"max_inclusive": 0, "min_inclusive": -10, "required": True} self.analyzer.merge_redefined_classes(classes) self.assertEqual(1, len(classes)) self.assertEqual(1, len(classes[0].extensions)) self.assertEqual(expected, classes[0].extensions[0].restrictions.asdict())
def test_build_class_extensions(self, mock_children_extensions): bar_type = AttrTypeFactory.create(name="bar", index=3) foo_type = AttrTypeFactory.create(name="foo", index=1) some_type = AttrTypeFactory.create(name="something", index=0) bar = ExtensionFactory.create(type=bar_type) double = ExtensionFactory.create(type=bar_type) foo = ExtensionFactory.create(type=foo_type) mock_children_extensions.return_value = [bar, double, foo] self_ext = ExtensionFactory.create(type=some_type, restrictions=Restrictions( min_occurs=1, max_occurs=1)) item = ClassFactory.create() element = Element.create(type="something") self.builder.build_class_extensions(element, item) self.assertEqual(3, len(item.extensions)) self.assertEqual(self_ext, item.extensions[0]) self.assertIs(foo, item.extensions[1]) self.assertIs(double, item.extensions[2])
def test_property_is_optional(self): attr = AttrFactory.create(restrictions=Restrictions(min_occurs=0)) self.assertTrue(attr.is_optional) attr.restrictions.min_occurs = 1 self.assertFalse(attr.is_optional)
def test_property_is_list(self): attr = AttrFactory.create(restrictions=Restrictions(max_occurs=2)) self.assertTrue(attr.is_list) attr.restrictions.max_occurs = 1 self.assertFalse(attr.is_list)
def test_clone(self): restrictions = Restrictions(max_occurs=2) clone = restrictions.clone() self.assertEqual(clone, restrictions) self.assertIsNot(clone, restrictions)