Exemple #1
0
    def bind_element_children(
        cls, params: Dict, meta: XmlMeta, position: int, objects: List,
    ):
        """Return a dictionary of qualified object names and their values for
        the given queue item."""

        while len(objects) > position:
            qname, value = objects.pop(position)
            arg = meta.find_var(qname, FindMode.NOT_WILDCARD) or meta.find_var(
                qname, FindMode.WILDCARD
            )

            if not arg:
                raise ParserError("Impossible exception!")

            if not arg.init:
                continue

            if value is None:
                value = ""

            if not cls.bind_element_param(params, arg, value):
                lookup = QName(value.qname) if isinstance(value, AnyElement) else qname
                wild = cls.find_eligible_wildcard(meta, lookup, params)

                if not wild:
                    logger.warning("Unassigned parsed object %s", qname)
                else:
                    cls.bind_element_wildcard_param(params, wild, qname, value)
Exemple #2
0
    def process(self, uris: List[str], package: str):
        """
        Run main processes.

        :param uris: list of uris to process
        :param package: package name eg foo.bar.xxx
        """

        collections.apply(uris, self.process_schema)

        classes = [
            cls for classes in self.class_map.values() for cls in classes
        ]
        class_num, inner_num = self.count_classes(classes)
        if class_num:
            logger.info("Analyzer input: %d main and %d inner classes",
                        class_num, inner_num)
            self.assign_packages(package)

            classes = self.analyze_classes(classes)
            class_num, inner_num = self.count_classes(classes)
            logger.info("Analyzer output: %d main and %d inner classes",
                        class_num, inner_num)

            writer.designate(classes, self.output)
            if self.print:
                writer.print(classes, self.output)
            else:
                writer.write(classes, self.output)
        else:
            logger.warning("Analyzer returned zero classes!")
Exemple #3
0
    def bind_element_children(self, params: Dict, item: ClassQueueItem,
                              element: Element):
        """Return a dictionary of qualified object names and their values for
        the given queue item."""

        while len(self.objects) > item.position:
            qname, value = self.objects.pop(item.position)
            arg = item.meta.vars[qname]

            if not arg.init:
                continue

            if value is None:
                value = ""

            if not self.bind_element_param(params, arg, value):
                lookup = QName(value.qname) if isinstance(
                    value, AnyElement) else qname
                wild = self.find_eligible_wildcard(item.meta, lookup, params)

                if not wild:
                    logger.warning("Unassigned parsed object %s", qname)
                else:
                    self.bind_element_wildcard_param(params, wild, qname,
                                                     value)
Exemple #4
0
    def flatten_extension(self, target: Class, extension: Extension):
        """
        Flatten target class extension based on the extension type.

        Types:
            1. Native primitive type (int, str, float, etc)
            2. Simple source type (simpleType, Extension)
            3. Complex source type (ComplexType, Element)
            4. Unknown type
        """
        if extension.type.native:
            self.flatten_extension_native(target, extension)
        else:
            qname = target.source_qname(extension.type.name)
            simple_source = self.find_simple_class(qname)
            complex_source = None if simple_source else self.find_class(qname)

            if simple_source:
                self.flatten_extension_simple(simple_source, target, extension)
            elif complex_source:
                self.flatten_extension_complex(complex_source, target,
                                               extension)
            else:
                logger.warning("Missing extension type: %s",
                               extension.type.name)
                target.extensions.remove(extension)
Exemple #5
0
    def process_attribute_default_enum(self, target: Class, attr: Attr):
        """
        Convert string literal default value for enum fields.

        Loop through all attributes types and search for enum sources.
        If an enum source exist map the default string literal value to
        a qualified name. If the source class in inner promote it to
        root classes.
        """

        source_found = False
        for attr_type in attr.types:
            source = self.find_enum(target, attr_type)
            if not source:
                continue

            source_found = True
            source_attr = next(
                (x for x in source.attrs if x.default == attr.default), None)
            if source_attr:
                if attr_type.forward:
                    self.promote_inner_class(target, source)

                attr.default = f"@enum@{source.name}::{source_attr.name}"
                return

        if source_found:
            logger.warning(
                "No enumeration member matched %s.%s default value `%s`",
                target.name,
                attr.local_name,
                attr.default,
            )
            attr.default = None
Exemple #6
0
    def build_parts_attributes(cls, parts: List[Part],
                               ns_map: Dict) -> Iterator[Attr]:
        """
        Build attributes for the given list of parts.

        :param parts: List of parts
        :param ns_map: Namespace prefix-URI map
        """
        for part in parts:
            if part.element:
                prefix, type_name = text.split(part.element)
                name = type_name
            elif part.type:
                prefix, type_name = text.split(part.type)
                name = part.name
            else:
                logger.warning("Skip untyped message part %s", part.name)
                continue

            ns_map.update(part.ns_map)
            namespace = part.ns_map.get(prefix)
            type_qname = build_qname(namespace, type_name)
            native = namespace == Namespace.XS.uri
            namespace = "" if part.type else namespace

            yield cls.build_attr(name,
                                 type_qname,
                                 namespace=namespace,
                                 native=native)
Exemple #7
0
    def process_dependency_type(self, target: Class, attr: Attr,
                                attr_type: AttrType):
        """
        Process an attributes type that depends on any global type.

        Strategies:
            1. Reset absent or dummy attribute types with a warning
            2. Copy attribute properties from a simple type
            3. Copy format restriction from an enumeration
            4. Set circular flag for the rest
        """

        source = self.find_dependency(attr_type, attr.tag)
        if not source or (not source.attrs and not source.extensions):
            logger.warning("Reset dummy type: %s", attr_type.name)
            use_str = not source or not source.is_complex
            self.reset_attribute_type(attr_type, use_str)
        elif source.is_simple_type:
            self.copy_attribute_properties(source, target, attr, attr_type)
        elif source.is_enumeration:
            attr.restrictions.format = collections.first(
                x.restrictions.format for x in source.attrs
                if x.restrictions.format)
        else:
            self.set_circular_flag(source, target, attr_type)
Exemple #8
0
 def process_included(
     self,
     included: Union[Import, Include, Redefine, Override],
     package: str,
     target_namespace: Optional[str],
 ) -> List[Class]:
     """Prepare the given included schema location and send it for
     processing."""
     classes = []
     if not included.location:
         logger.warning(
             "%s: %s unresolved schema location..",
             included.class_name,
             included.schema_location,
         )
     elif included.location in self.processed:
         logger.debug(
             "%s: %s already included skipping..",
             included.class_name,
             included.schema_location,
         )
     else:
         package = self.adjust_package(package, included.schema_location)
         classes = self.process_schema(included.location, package,
                                       target_namespace)
     return classes
Exemple #9
0
 def process_dependency_extension(self, target: Class, extension: Extension):
     """User defined type flatten handler."""
     source = self.find_dependency(extension.type)
     if not source:
         logger.warning("Missing extension type: %s", extension.type.name)
         target.extensions.remove(extension)
     elif not source.is_complex or source.is_enumeration:
         self.process_simple_extension(source, target, extension)
     else:
         self.process_complex_extension(source, target, extension)
Exemple #10
0
    def load_resource(self, uri: str) -> Optional[bytes]:
        """Read and return the contents of the given uri."""
        if uri not in self.processed:
            try:
                self.processed.append(uri)
                return self.preloaded.pop(uri, None) or urlopen(uri).read()  # nosec
            except OSError:
                logger.warning("Resource not found %s", uri)
        else:
            logger.debug("Skipping already processed: %s", os.path.basename(uri))

        return None
Exemple #11
0
    def find_class(self,
                   qname: QName,
                   condition: Optional[Callable] = None) -> Optional[Class]:
        candidates = list(filter(condition, self.class_index.get(qname, [])))
        if candidates:
            candidate = candidates.pop(0)
            if candidates:
                logger.warning("More than one candidate found for %s", qname)

            if id(candidate) not in self.processed:
                self.flatten_class(candidate)
            return candidate

        return None
Exemple #12
0
 def flatten_attribute_type(self, target: Class, attr: Attr,
                            attr_type: AttrType):
     """Flatten attribute type if it's a simple type otherwise check for
     circular reference or missing type."""
     simple_source = self.find_attr_simple_type(target, attr_type)
     if simple_source:
         self.merge_attribute_type(simple_source, target, attr, attr_type)
     else:
         complex_source = self.find_attr_type(target, attr_type)
         if complex_source:
             attr_type.self_ref = self.class_depends_on(
                 complex_source, target)
         else:
             logger.warning("Missing type: %s", attr_type.name)
             self.reset_attribute_type(attr_type)
Exemple #13
0
    def process(self, schemas: List[Path], package: str):
        classes = self.process_schemas(schemas, package)
        classes = self.analyze_classes(classes)
        class_num, inner_num = self.count_classes(classes)

        if class_num:
            logger.info("Analyzer: %d main and %d inner classes", class_num,
                        inner_num)

            writer.designate(classes, self.output)
            if self.print:
                writer.print(classes, self.output)
            else:
                writer.write(classes, self.output)
        else:
            logger.warning("Analyzer returned zero classes!")
Exemple #14
0
    def bind_objects(cls, params: Dict, meta: XmlMeta, position: int,
                     objects: List):
        """Return a dictionary of qualified object names and their values for
        the given queue item."""

        while len(objects) > position:
            qname, value = objects.pop(position)

            arg = meta.find_var(qname, FindMode.ELEMENT)
            if arg and cls.bind_var(params, arg, value):
                continue

            arg = meta.find_var(qname, FindMode.WILDCARD)
            if arg and cls.bind_wild_var(params, arg, qname, value):
                continue

            logger.warning("Unassigned parsed object %s", qname)
Exemple #15
0
    def parse_schema(uri: str, namespace: Optional[str] = None) -> Optional[Schema]:
        """
        Parse the given schema uri and return the schema tree object.

        Optionally add the target namespace if the schema is included
        and is missing a target namespace.
        """

        try:
            schema = urlopen(uri).read()
        except OSError:
            logger.warning("Schema not found %s", uri)
        else:
            parser = SchemaParser(target_namespace=namespace, location=uri)
            return parser.from_bytes(schema, Schema)

        return None
Exemple #16
0
    def parse_schema(cls, uri: str,
                     namespace: Optional[str]) -> Optional[Schema]:
        """
        Parse the given schema uri and return the schema tree object.

        Optionally add the target namespace if the schema is included
        and is missing a target namespace.
        """

        try:
            input_stream = cls.load_resource(uri)
        except OSError:
            logger.warning("Schema not found %s", uri)
        else:
            parser = SchemaParser(target_namespace=namespace, location=uri)
            return parser.from_bytes(input_stream, Schema)

        return None
Exemple #17
0
    def merge_attribute_type(cls, source: Class, target: Class, attr: Attr,
                             attr_type: AttrType):
        if len(source.attrs) != 1:
            logger.warning("Missing implementation: %s", source.type.__name__)
            cls.reset_attribute_type(attr_type)
        else:
            source_attr = source.attrs[0]
            index = attr.types.index(attr_type)
            attr.types.pop(index)

            for source_attr_type in source_attr.types:
                clone_type = source_attr_type.clone()
                attr.types.insert(index, clone_type)
                index += 1

            restrictions = source_attr.restrictions.clone()
            restrictions.merge(attr.restrictions)
            attr.restrictions = restrictions
            cls.copy_inner_classes(source, target)
Exemple #18
0
    def process_dependency_type(self, target: Class, attr: Attr, attr_type: AttrType):
        """
        Process user defined attribute types, split process between complex and
        simple types.

        Reset absent attribute types with a warning.

        Complex Type: xs:Element and xs:ComplexType
        Simple stype: the rest
        """

        source = self.find_dependency(attr_type)
        if not source:
            logger.warning("Missing type: %s", attr_type.name)
            self.reset_attribute_type(attr_type)
        elif source.is_complex and not source.is_enumeration:
            self.process_complex_dependency(source, target, attr_type)
        else:
            self.process_simple_dependency(source, target, attr, attr_type)
Exemple #19
0
    def flatten_attribute_types(self, target: Class, attr: Attr):
        """
        Flatten attribute types by using the source attribute type.

        Steps:
            * Skip xsd native types
            * Detect circular references if no source is found
            * Skip enumeration types
            * Overwrite attribute type from source
        """
        types = []
        for attr_type in attr.types:
            source = None
            if not attr_type.native:
                type_qname = target.source_qname(attr_type.name)
                source = self.find_class(type_qname)

            if source is None:
                attr_type.self_ref = self.attr_depends_on(attr_type, target)
                types.append(attr_type)
            elif self.is_qname(source):
                types.append(source.extensions[0].type.clone())
            elif source.is_enumeration:
                types.append(attr_type)
            elif len(source.attrs) == 1:
                source_attr = source.attrs[0]
                types.extend(source_attr.types)
                restrictions = source_attr.restrictions.clone()
                restrictions.merge(attr.restrictions)
                attr.restrictions = restrictions
                self.copy_inner_classes(source, target)
            else:
                types.append(AttrType(name=DataType.STRING.code, native=True))
                logger.warning("Missing type implementation: %s",
                               source.type.__name__)

        attr.types = types