def process(self, target: Class): """ Merge enumeration unions attributes. Lookup for the source class in the local namespace or inner class list. """ if len(target.attrs) != 1 or target.attrs[0].tag != Tag.UNION: return enums: List[Any] = [] for attr_type in target.attrs[0].types: if attr_type.forward: enums.extend(target.inner) elif not attr_type.native: qname = target.source_qname(attr_type.name) enums.append(self.container.find(qname)) else: enums.append(None) merge = all(isinstance(x, Class) and x.is_enumeration for x in enums) if merge: target.attrs.clear() target.inner.clear() target.attrs.extend(attr.clone() for enum in enums for attr in enum.attrs)
def is_invalid(source: Class, ext: Extension) -> bool: """Check if given type declaration is not native and is missing.""" if ext.type.native: return False qname = source.source_qname(ext.type.name) return qname not in self.container
def apply_aliases(self, obj: Class): """Walk the attributes tree and set the type aliases.""" for attr in obj.attrs: for attr_type in attr.types: attr_type_qname = obj.source_qname(attr_type.name) attr_type.alias = self.aliases.get(attr_type_qname) collections.apply(obj.inner, self.apply_aliases)
def process_attribute(self, target: Class, attr: Attr): """ Find the source class the attribute refers to and copy its attributes to the target class. :raises AnalyzerValueError: if source class is not found. """ qname = target.source_qname(attr.name) source = self.container.find( qname, condition=lambda x: x.type in (AttributeGroup, Group) ) if not source: raise AnalyzerValueError(f"Group attribute not found: `{qname}`") if source is target: target.attrs.remove(attr) else: ClassUtils.copy_group_attributes(source, target, attr)
def find_enum(self, source: Class, attr_type: AttrType) -> Optional[Class]: """ Find the enumeration source class for the given class and attribute type. Search in root classes an inner class and exclude native types. """ if attr_type.native: return None if attr_type.forward: return self.find_inner( source, condition=lambda x: x.is_enumeration and x.name == attr_type. name, ) qname = source.source_qname(attr_type.name) return self.container.find(qname, condition=lambda x: x.is_enumeration)
def find_dependency(self, target: Class, attr_type: AttrType) -> Optional[Class]: """ Find dependency for the given extension type with priority. Search priority: xs:SimpleType > xs:ComplexType """ conditions = ( lambda x: x.type is SimpleType, lambda x: x.type is ComplexType, ) qname = target.source_qname(attr_type.name) for condition in conditions: result = self.container.find(qname, condition=condition) if result: return result return None
def find_dependency(self, target: Class, attr_type: AttrType) -> Optional[Class]: """ Find dependency for the given attribute. Avoid conflicts by search in order: 1. Non element/complexType 2. Non abstract 3. anything """ qname = target.source_qname(attr_type.name) conditions = (lambda obj: not obj.is_complex, lambda x: not x.abstract, None) for condition in conditions: result = self.container.find(qname, condition=condition) if result: return result return None
def process_attribute(self, target: Class, attr: Attr): """ Check if the given attribute matches any substitution class in order to clone it's attributes to the target class. The cloned attributes are placed below the attribute the are supposed to substitute. """ index = target.attrs.index(attr) qname = target.source_qname(attr.name) assert self.substitutions is not None for substitution in self.substitutions.get(qname, []): pos = collections.find(target.attrs, substitution) index = pos + 1 if pos > -1 else index clone = substitution.clone() clone.restrictions.merge(attr.restrictions) target.attrs.insert(index, clone) self.process_attribute(target, clone)
def add(self, item: Class): """Add class item to the container.""" self.data.setdefault(item.source_qname(), []).append(item)