Esempio n. 1
0
    def copy_attributes(cls, source: Class, target: Class,
                        extension: Extension):
        """
        Copy the attributes and inner classes from the source class to the
        target class and remove the extension that links the two classes
        together.

        The new attributes are prepended in the list unless if they are
        supposed to be last in a sequence.
        """
        prefix = text.prefix(extension.type.name)
        target.extensions.remove(extension)
        target_attr_names = {text.suffix(attr.name) for attr in target.attrs}

        index = 0
        for attr in source.attrs:
            if text.suffix(attr.name) not in target_attr_names:
                clone = cls.clone_attribute(attr, extension.restrictions,
                                            prefix)

                if attr.index == sys.maxsize:
                    target.attrs.append(clone)
                    continue

                target.attrs.insert(index, clone)
            index += 1

        cls.copy_inner_classes(source, target)
Esempio n. 2
0
    def map_port(cls, definitions: Definitions, port: ServicePort) -> Iterator[Class]:
        """Step 2: Match a ServicePort to a Binding and PortType object and
        delegate the process to the next entry point."""

        binding = definitions.find_binding(text.suffix(port.binding))
        port_type = definitions.find_port_type(text.suffix(binding.type))

        elements = collections.concat(binding.extended_elements, port.extended_elements)
        config = cls.attributes(elements)

        yield from cls.map_binding(definitions, binding, port_type, config)
Esempio n. 3
0
    def sanitize_attribute_name(cls, attrs: List[Attr], index: int):
        """Check if the attribute at the given index has a duplicate name and
        prepend if exists the attribute namespace."""

        current = attrs[index]
        current.name = text.suffix(current.name)
        exists = any(
            attr is not current and current.name == text.suffix(attr.name)
            for attr in attrs)

        if exists and current.namespace:
            current.name = f"{current.namespace}_{current.name}"
Esempio n. 4
0
    def map_binding_message_parts(cls, definitions: Definitions, message: str,
                                  extended: AnyElement,
                                  ns_map: Dict) -> Iterator[Attr]:
        """Find a Message instance and map its parts to attributes according to
        the the extensible element.."""
        parts = []
        if "part" in extended.attributes:
            parts.append(extended.attributes["part"])
        elif "parts" in extended.attributes:
            parts.extend(extended.attributes["parts"].split())

        if "message" in extended.attributes:
            message_name = local_name(extended.attributes["message"])
        else:
            message_name = text.suffix(message)

        definition_message = definitions.find_message(message_name)
        message_parts = definition_message.parts

        if parts:
            message_parts = [
                part for part in message_parts if part.name in parts
            ]

        yield from cls.build_parts_attributes(message_parts, ns_map)
Esempio n. 5
0
    def build_envelope_fault(
        cls,
        definitions: Definitions,
        port_type_operation: PortTypeOperation,
        target: Class,
    ):
        """Build inner fault class with default fields."""
        ns_map: Dict = {}
        body = next(inner for inner in target.inner if inner.name == "Body")
        fault_class = cls.build_inner_class(body, "Fault", target.namespace)

        detail_attrs: List[Attr] = []
        for fault in port_type_operation.faults:
            message = definitions.find_message(text.suffix(fault.message))
            detail_attrs.extend(
                cls.build_parts_attributes(message.parts, ns_map))

        default_fields = ["faultcode", "faultstring", "faultactor"]
        if detail_attrs:
            detail = cls.build_inner_class(fault_class, "detail", namespace="")
            detail.attrs.extend(detail_attrs)
        else:
            default_fields.append("detail")

        collections.prepend(
            fault_class.attrs,
            *[
                cls.build_attr(f,
                               str(DataType.STRING),
                               native=True,
                               namespace="") for f in default_fields
            ],
        )
Esempio n. 6
0
    def process_attribute_name(cls, attr: Attr):
        """
        Sanitize attribute name in preparation for duplicate attribute names
        handler.

        Steps:
            1. Remove non alpha numerical values
            2. Handle Enum negative numerical values
            3. Remove namespaces prefixes
            4. Ensure name not empty
            5. Ensure name starts with a letter
        """
        if attr.is_enumeration:
            attr.name = attr.default
            if re.match(r"^-\d*\.?\d+$", attr.name):
                attr.name = f"value_minus_{attr.name}"
            else:
                attr.name = re.sub("[^0-9a-zA-Z]", " ", attr.name).strip()
        else:
            attr.name = re.sub("[^0-9a-zA-Z]", " ",
                               text.suffix(attr.name)).strip()

        if not attr.name:
            attr.name = "value"
        elif not attr.name[0].isalpha():
            attr.name = f"value_{attr.name}"
Esempio n. 7
0
    def merge_redefined_classes(cls, classes: List[Class]):
        """Merge original and redefined classes."""
        grouped: Dict[str, List[Class]] = defaultdict(list)
        for item in classes:
            grouped[f"{item.type.__name__}{item.source_qname()}"].append(item)

        for items in grouped.values():
            if len(items) == 1:
                continue

            winner: Class = items.pop()
            for item in items:
                classes.remove(item)

                self_extension = next(
                    (ext for ext in winner.extensions
                     if text.suffix(ext.type.name) == winner.name),
                    None,
                )

                if not self_extension:
                    continue

                cls.copy_attributes(item, winner, self_extension)
                for looser_ext in item.extensions:
                    new_ext = looser_ext.clone()
                    new_ext.restrictions.merge(self_extension.restrictions)
                    winner.extensions.append(new_ext)
Esempio n. 8
0
    def build_class_attribute(
        self, target: Class, obj: ElementBase, parent_restrictions: Restrictions
    ):
        """Generate and append an attribute field 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=text.suffix(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,
            )
        )
Esempio n. 9
0
    def find_circular_group(cls, target: Class) -> Optional[Attr]:
        """Search for any target class attributes that is a circular
        reference."""
        for attr in target.attrs:
            if text.suffix(attr.name) == target.name:
                return attr

        return None
Esempio n. 10
0
    def find_circular_extension(cls, target: Class) -> Optional[Extension]:
        """Search for any target class extensions that is a circular
        reference."""
        for ext in target.extensions:
            if text.suffix(ext.type.name) == target.name:
                return ext

        return None
Esempio n. 11
0
    def attribute_name(cls, name: str) -> str:
        """
        Strip reference prefix and turn to snake case.

        If the name is one of the python reserved words append the
        prefix _value
        """
        local_name = text.suffix(name)
        return text.snake_case(safe_snake(local_name))
Esempio n. 12
0
    def process_attribute(cls, target: Class, attr: Attr, parents: List[str]):
        """Normalize attribute properties."""
        attr.name = cls.attribute_name(attr.name)
        attr.display_type = cls.attribute_display_type(attr, parents)
        attr.default = cls.attribute_default(attr, target.ns_map)
        attr.xml_type = cls.xml_type_map.get(attr.tag)

        if attr.local_name:
            attr.local_name = text.suffix(attr.local_name)
Esempio n. 13
0
    def copy_attributes(cls, source: Class, target: Class,
                        extension: Extension):
        prefix = text.prefix(extension.type.name)
        target.extensions.remove(extension)
        target_attr_names = {text.suffix(attr.name) for attr in target.attrs}

        index = 0
        for attr in source.attrs:
            if text.suffix(attr.name) not in target_attr_names:
                clone = cls.clone_attribute(attr, extension.restrictions,
                                            prefix)

                if attr.index == sys.maxsize:
                    target.attrs.append(clone)
                    continue

                target.attrs.insert(index, clone)
            index += 1

        cls.copy_inner_classes(source, target)
Esempio n. 14
0
    def rename_attr_dependencies(self, attr: Attr, reference: int, replace: str):
        """Search and replace the old qualified attribute type name with the
        new one in the attr types, choices and default value."""
        for attr_type in attr.types:
            if attr_type.reference == reference:
                attr_type.qname = replace

                if isinstance(attr.default, str) and attr.default.startswith("@enum@"):
                    member = text.suffix(attr.default, "::")
                    attr.default = f"@enum@{replace}::{member}"

        for choice in attr.choices:
            self.rename_attr_dependencies(choice, reference, replace)
Esempio n. 15
0
    def real_name(self) -> str:
        """
        Return the real name for this element by looking by looking either to
        the name or ref attribute value.

        :raises SchemaValueError: when instance has no name/ref attribute.
        """
        name = getattr(self, "name", None) or getattr(self, "ref", None)
        if name:
            return text.suffix(name)

        raise SchemaValueError(
            f"Schema class `{self.class_name}` unknown real name.")
Esempio n. 16
0
    def build_message_class(cls, definitions: Definitions,
                            port_type_message: PortTypeMessage) -> Class:
        """Step 6.2: Build the input/output message class of an rpc style
        operation."""
        message_name = text.suffix(port_type_message.message)
        definition_message = definitions.find_message(message_name)
        ns_map = definition_message.ns_map.copy()

        return Class(
            qname=build_qname(definitions.target_namespace, message_name),
            status=Status.PROCESSED,
            tag=Tag.ELEMENT,
            module=definitions.module,
            ns_map=ns_map,
            attrs=list(
                cls.build_parts_attributes(definition_message.parts, ns_map)),
        )
Esempio n. 17
0
def attribute_default(attr: Attr, ns_map: Optional[Dict] = None) -> Any:
    """Generate the field default value/factory for the given attribute."""
    if attr.is_list:
        return "list"
    if attr.is_map:
        return "dict"
    if not isinstance(attr.default, str):
        return attr.default

    data_types = {
        attr_type.native_code: attr_type.native_type
        for attr_type in attr.types if attr_type.native
    }

    local_types = list(set(data_types.values()))
    default_value = to_python(local_types,
                              attr.default,
                              ns_map,
                              in_order=False)

    if isinstance(default_value, str):
        if DataType.NMTOKENS.code in data_types:
            default_value = quoteattr(" ".join(
                filter(None, map(str.strip, re.split(r"\s+", default_value)))))
        elif default_value.startswith("@enum@"):
            source, enumeration = default_value[6:].split("::", 1)
            attr_type = next(attr_type for attr_type in attr.types
                             if text.suffix(attr_type.name) == source)
            if attr_type.alias:
                source = attr_type.alias

            default_value = f"{class_name(source)}.{constant_name(enumeration)}"
        else:
            default_value = quoteattr(default_value)
    elif isinstance(default_value, float) and math.isinf(default_value):
        default_value = f"float('{default_value}')"
    elif isinstance(default_value, Decimal):
        default_value = repr(default_value)
    elif isinstance(default_value, QName):
        default_value = (
            f'QName("{default_value.namespace}", "{default_value.localname}")')
    return default_value
Esempio n. 18
0
def attribute_name(name: str) -> str:
    """Apply python conventions for instance variable names."""
    return text.snake_case(utils.safe_snake(text.suffix(name)))
Esempio n. 19
0
    def type_name(cls, attr_type: AttrType) -> str:
        """Convert xsd types to python or apply class name conventions after
        stripping any reference prefix."""

        return attr_type.native_name or cls.class_name(text.suffix(attr_type.name))
Esempio n. 20
0
def type_name(attr_type: AttrType) -> str:
    """Return native python type name or apply class name conventions."""
    return attr_type.native_name or class_name(text.suffix(attr_type.name))
Esempio n. 21
0
 def is_xsi_type(self) -> bool:
     return (QNames.XSI_TYPE.namespace == self.namespace
             and QNames.XSI_TYPE.localname == text.suffix(self.name))
Esempio n. 22
0
 def is_xsi_type(self) -> bool:
     """Return whether this attribute qualified name is equal to
     xsi:type."""
     return (QNames.XSI_TYPE.namespace == self.namespace
             and QNames.XSI_TYPE.localname == text.suffix(self.name))