def test_build_message_class(self, mock_create_message_attributes): message = Message(name="bar", parts=[Part()]) message.ns_map["foo"] = "bar" definitions = Definitions( messages=[message], target_namespace="xsdata", location="foo.wsdl" ) port_type_message = PortTypeMessage(message="foo:bar") attrs = AttrFactory.list(2) mock_create_message_attributes.return_value = attrs actual = DefinitionsMapper.build_message_class(definitions, port_type_message) expected = Class( qname=build_qname("xsdata", "bar"), status=Status.PROCESSED, type=Element, module="foo", ns_map=message.ns_map, attrs=attrs, ) self.assertEqual(expected, actual)
def map_binding_operation( cls, definitions: Definitions, binding_operation: BindingOperation, port_type_operation: PortTypeOperation, config: Dict, name: str, ) -> Iterator[Class]: """Step 4: Convert a BindingOperation to a service class and delegate the process of all the message classes to the next entry point.""" attrs = [ cls.build_attr(key, str(DataType.STRING), native=True, default=config[key]) for key in sorted(config.keys(), key=len) if config[key] ] style = config.get("style", "document") name = f"{name}_{binding_operation.name}" namespace = cls.operation_namespace(config) operation_messages = cls.map_binding_operation_messages( definitions, binding_operation, port_type_operation, name, style, namespace) for message_class in operation_messages: yield message_class # Only Envelope classes need to be added in service input/output if message_class.meta_name: message_type = message_class.name.split("_")[-1] attrs.append(cls.build_attr(message_type, message_class.qname)) yield Class( qname=build_qname(definitions.target_namespace, name), status=Status.PROCESSED, tag=type(binding_operation).__name__, module=definitions.module, ns_map=binding_operation.ns_map, attrs=attrs, )
def promote_inner_class(self, parent: Class, inner: Class): """ Convert inner class to root class. Steps: 1. Remove inner class from parent 2. Prepend parent name to inner class name. 3. Search and replace all matching attribute types. 4. Add inner class to the global class index. """ name = f"{parent.name}_{inner.name}" parent.inner.remove(inner) for attr in parent.attrs: for attr_type in attr.types: if attr_type.name == inner.name: attr_type.forward = False attr_type.qname = QName(inner.qname.namespace, name) inner.qname = QName(inner.qname.namespace, name) self.container.add(inner)
def build_class(self, obj: ElementBase, container: Optional[str] = None) -> Class: """Build and return a class instance.""" name = obj.real_name namespace = self.element_namespace(obj) instance = Class( name=name, abstract=obj.is_abstract, namespace=namespace, mixed=obj.is_mixed, nillable=obj.is_nillable, type=type(obj), container=container, help=obj.display_help, ns_map=obj.ns_map, source_namespace=self.schema.target_namespace, module=self.schema.module, substitutions=obj.substitutions, ) self.build_class_extensions(obj, instance) self.build_class_attributes(obj, instance) return instance
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 process(cls, target: Class): """Process classes that contain attributes derived from xs:enumeration and any other xs element.""" if target.is_enumeration or not any(attr.is_enumeration for attr in target.attrs): return enumerations = [] for attr in list(target.attrs): if attr.is_enumeration: target.attrs.remove(attr) enumerations.append(attr) if len(target.attrs) > 1: raise AnalyzerValueError( "Mixed enumeration with more than one normal field.") enum_inner = next( (inner for inner in target.inner if inner.is_enumeration), None) if not enum_inner: enum_inner = Class( qname=QName(target.qname.namespace, "value"), type=SimpleType, module=target.module, package=target.package, mixed=False, abstract=False, nillable=False, ) target.attrs[0].types.append( AttrType( qname=QName(target.qname.namespace, "value"), forward=True, )) target.inner.append(enum_inner) enum_inner.attrs.extend(enumerations)
def build_envelope_class( cls, definitions: Definitions, binding_message: BindingMessage, port_type_message: PortTypeMessage, name: str, style: str, namespace: Optional[str], ) -> Class: """Step 6.1: Build Envelope class for the given binding message with attributes from the port type message.""" target = Class( qname=build_qname(definitions.target_namespace, name), meta_name="Envelope", type=type(binding_message), module=definitions.module, ns_map=binding_message.ns_map, namespace=namespace, ) message = port_type_message.message for ext in binding_message.extended_elements: assert ext.qname is not None local_name = split_qname(ext.qname)[1].title() inner = cls.build_inner_class(target, local_name) if style == "rpc" and local_name == "Body": namespace = ext.attributes.get("namespace") attrs = cls.map_port_type_message(port_type_message, namespace) else: attrs = cls.map_binding_message_parts( definitions, message, ext, inner.ns_map ) inner.attrs.extend(attrs) return target
def build_inner_class( cls, target: Class, name: str, namespace: Optional[str] = None ) -> Class: """ Build or retrieve an inner class for the given target class by the given name. This helper will also create a forward reference attribute for the parent class. """ inner = first(inner for inner in target.inner if inner.name == name) if not inner: inner = Class( qname=build_qname(name), type=BindingMessage, module=target.module, ns_map=target.ns_map.copy(), ) attr = cls.build_attr(name, inner.qname, forward=True, namespace=namespace) target.inner.append(inner) target.attrs.append(attr) return inner
def process_class(x: Class): x.status = Status.PROCESSED
def process_class(x: Class): x.status = Status.PROCESSED if x is first: first.attrs.clear()
def add(self, item: Class): """Add class item to the container.""" self.data.setdefault(item.source_qname(), []).append(item)
def test_build_envelope_class_with_style_rpc( self, mock_get_or_create_inner_class, mock_map_binding_message_parts, mock_map_port_type_message, ): mock_get_or_create_inner_class.side_effect = mock_create_inner mock_map_binding_message_parts.side_effect = mock_create_attr mock_map_port_type_message.side_effect = mock_create_attr name = "some_operation_bindings" style = "rpc" namespace = "xsdata" definitions = Definitions(location="foo.wsdl", target_namespace="bar") port_type_message = PortTypeMessage(message="some_operation") binding_message = BindingMessage(extended=[ AnyElement(qname="body", attributes={"namespace": "bodyns"}), AnyElement(qname="header"), AnyElement(qname="header"), ]) binding_message.ns_map["foo"] = "bar" result = DefinitionsMapper.build_envelope_class( definitions, binding_message, port_type_message, name, style, namespace) expected = Class( qname=build_qname("bar", name), meta_name="Envelope", tag=Tag.BINDING_MESSAGE, module="foo", ns_map={"foo": "bar"}, namespace="xsdata", ) self.assertEqual(2, len(result.inner)) self.assertEqual(1, len(result.inner[0].attrs)) self.assertEqual(2, len(result.inner[1].attrs)) self.maxDiff = None mock_map_port_type_message.assert_called_once_with( port_type_message, "bodyns") mock_map_binding_message_parts.assert_has_calls([ mock.call( definitions, port_type_message.message, binding_message.extended[1], result.inner[1].ns_map, ), mock.call( definitions, port_type_message.message, binding_message.extended[2], result.inner[1].ns_map, ), ]) mock_get_or_create_inner_class.assert_has_calls([ mock.call(mock.ANY, "Body"), mock.call(mock.ANY, "Header"), mock.call(mock.ANY, "Header"), ]) result.inner.clear() self.assertEqual(expected, result)
def process(cls, target: Class): """Drop non enum attributes from enum classes.""" enumerations = [attr for attr in target.attrs if attr.is_enumeration] if enumerations: target.attrs = enumerations
def clone_enumeration(cls, inner: Class, name: str) -> Class: clone = inner.clone() clone.qname = build_qname(clone.target_namespace, f"{name}_{clone.name}") return clone
def filter(cls, target: Class): """Filter attrs not derived from xs:enumeration if there are any xs:enumeration attrs.""" enumerations = [attr for attr in target.attrs if attr.is_enumeration] if enumerations: target.attrs = enumerations
def test_build_envelope_class( self, mock_get_or_create_inner_class, mock_map_binding_message_parts, mock_map_port_type_message, ): mock_get_or_create_inner_class.side_effect = mock_create_inner mock_map_binding_message_parts.side_effect = mock_create_attr name = "some_operation_bindings" style = "document" namespace = "xsdata" definitions = Definitions(location="foo.wsdl", target_namespace="bar") port_type_message = PortTypeMessage(message="some_operation") binding_message = BindingMessage( extended=[ AnyElement(qname="body"), AnyElement(qname="header"), AnyElement(qname="header"), ] ) binding_message.ns_map["foo"] = "bar" result = DefinitionsMapper.build_envelope_class( definitions, binding_message, port_type_message, name, style, namespace ) expected = Class( qname=build_qname("bar", name), meta_name="Envelope", type=BindingMessage, module="foo", ns_map={"foo": "bar"}, namespace="xsdata", ) self.assertEqual(2, len(result.inner)) self.assertEqual(1, len(result.inner[0].attrs)) self.assertEqual(2, len(result.inner[1].attrs)) self.assertEqual(0, mock_map_port_type_message.call_count) mock_map_binding_message_parts.assert_has_calls( [ mock.call( definitions, port_type_message.message, binding_message.extended[0], result.inner[0].ns_map, ), mock.call( definitions, port_type_message.message, binding_message.extended[1], result.inner[1].ns_map, ), mock.call( definitions, port_type_message.message, binding_message.extended[2], result.inner[1].ns_map, ), ] ) mock_get_or_create_inner_class.assert_has_calls( [ mock.call(mock.ANY, "Body"), mock.call(mock.ANY, "Header"), mock.call(mock.ANY, "Header"), ] ) result.inner.clear() self.assertEqual(expected, result)