Hello community, here is the log from the commit of package python-zeep for openSUSE:Factory checked in at 2019-02-26 22:21:09 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-zeep (Old) and /work/SRC/openSUSE:Factory/.python-zeep.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-zeep" Tue Feb 26 22:21:09 2019 rev:2 rq:679181 version:3.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-zeep/python-zeep.changes 2019-01-03 18:09:51.907964891 +0100 +++ /work/SRC/openSUSE:Factory/.python-zeep.new.28833/python-zeep.changes 2019-02-26 22:22:47.610057802 +0100 @@ -1,0 +2,16 @@ +Tue Feb 26 06:11:48 UTC 2019 - John Vandenberg <[email protected]> + +- Remove from builds undesirable pytest plugins suited for development +- Add minimum build version for tornado +- Remove inappropriate runtime dependency on aioresponses +- Update to v3.2.0 + * Fix abstract message check for NoneType before attempting to access parts + * Improve support for 'Chameleon' XSD schemas (#879, #888) + * Fix resolving qualified references (#879) + * Fix issue with duplicate soap:body tags when multiple parts used (#879) + * Fix Choice with unbound Any element (#871) + * Add xsd_ignore_sequence_order flag (#880) + * Add support for timestamp token in WSS headers (#817) + * Accept strings for xsd.DateTime (#886) + +------------------------------------------------------------------- Old: ---- zeep-3.1.0.tar.gz New: ---- zeep-3.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-zeep.spec ++++++ --- /var/tmp/diff_new_pack.qZowW0/_old 2019-02-26 22:22:48.106057625 +0100 +++ /var/tmp/diff_new_pack.qZowW0/_new 2019-02-26 22:22:48.110057624 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-zeep # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-zeep -Version: 3.1.0 +Version: 3.2.0 Release: 0 Summary: A Python SOAP client based on lxml/requests License: MIT @@ -46,32 +46,25 @@ BuildRequires: %{python_module attrs >= 17.2.0} BuildRequires: %{python_module cached-property >= 1.3.0} BuildRequires: %{python_module defusedxml >= 0.4.1} -BuildRequires: %{python_module flake8 >= 3.3.0} -BuildRequires: %{python_module flake8-blind-except >= 0.1.1} -BuildRequires: %{python_module flake8-debugger >= 1.4.0} -BuildRequires: %{python_module flake8-imports >= 0.1.1} BuildRequires: %{python_module freezegun >= 0.3.8} BuildRequires: %{python_module isodate >= 0.5.4} -BuildRequires: %{python_module isort >= 4.2.15} BuildRequires: %{python_module lxml >= 3.1.0} BuildRequires: %{python_module mock >= 2.0.0} BuildRequires: %{python_module pretend >= 1.0.8} BuildRequires: %{python_module pytest >= 3.1.3} -BuildRequires: %{python_module pytest-cov >= 2.5.1} BuildRequires: %{python_module pytest-tornado >= 0.4.5} BuildRequires: %{python_module pytz} BuildRequires: %{python_module requests >= 2.7.0} BuildRequires: %{python_module requests-mock >= 0.7.0} BuildRequires: %{python_module requests-toolbelt >= 0.7.1} BuildRequires: %{python_module six >= 1.9.0} -BuildRequires: %{python_module tornado} +BuildRequires: %{python_module tornado >= 4.0.2} BuildRequires: %{python_module xmlsec >= 0.6.1} BuildRequires: python3-aiohttp >= 1.0 BuildRequires: python3-aioresponses >= 0.4.1 # /SECTION %ifpython3 Requires: python-aiohttp >= 1.0 -Requires: python-aioresponses >= 0.4.1 %endif %python_subpackages ++++++ zeep-3.1.0.tar.gz -> zeep-3.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/CHANGES new/zeep-3.2.0/CHANGES --- old/zeep-3.1.0/CHANGES 2018-07-28 09:49:57.000000000 +0200 +++ new/zeep-3.2.0/CHANGES 2018-12-17 09:47:28.000000000 +0100 @@ -1,3 +1,15 @@ +3.2.0 (2018-12-17) +------------------ + - Fix abstract message check for NoneType before attempting to access parts + - Improve support for 'Chameleon' XSD schemas (#879, #888) + - Fix resolving qualified references (#879) + - Fix issue with duplicate soap:body tags when multiple parts used (#879) + - Fix Choice with unbound Any element (#871) + - Add xsd_ignore_sequence_order flag (#880) + - Add support for timestamp token in WSS headers (#817) + - Accept strings for xsd.DateTime (#886) + + 3.1.0 (2018-07-28) ------------------ - Fix SSL issue on with `TornadoAsyncTransport` (#792) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/PKG-INFO new/zeep-3.2.0/PKG-INFO --- old/zeep-3.1.0/PKG-INFO 2018-07-28 09:50:37.000000000 +0200 +++ new/zeep-3.2.0/PKG-INFO 2018-12-17 10:05:53.000000000 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: zeep -Version: 3.1.0 +Version: 3.2.0 Summary: A modern/fast Python SOAP client based on lxml / requests Home-page: http://docs.python-zeep.org Author: Michael van Tellingen @@ -13,7 +13,7 @@ A fast and modern Python SOAP client Highlights: - * Compatible with Python 2.7, 3.3, 3.4, 3.5, 3.6 and PyPy + * Compatible with Python 2.7, 3.3, 3.4, 3.5, 3.6, 3.7 and PyPy * Build on top of lxml and requests * Support for Soap 1.1, Soap 1.2 and HTTP bindings * Support for WS-Addressing headers @@ -62,10 +62,7 @@ If you want to report a bug then please first read http://docs.python-zeep.org/en/master/reporting_bugs.html - I'm also able to offer commercial support. As in contracting work. Please - contact me at [email protected] for more information. Note that asking - questions or reporting bugs via this e-mail address will be ignored. Pleae use - the appropriate channels for that (e.g. stackoverflow) + Please only report bugs and not support requests to the GitHub issue tracker. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable @@ -76,5 +73,11 @@ Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy +Provides-Extra: async +Provides-Extra: tornado +Provides-Extra: docs +Provides-Extra: xmlsec +Provides-Extra: test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/README.rst new/zeep-3.2.0/README.rst --- old/zeep-3.1.0/README.rst 2017-11-04 09:15:21.000000000 +0100 +++ new/zeep-3.2.0/README.rst 2018-12-17 09:52:45.000000000 +0100 @@ -5,7 +5,7 @@ A fast and modern Python SOAP client Highlights: - * Compatible with Python 2.7, 3.3, 3.4, 3.5, 3.6 and PyPy + * Compatible with Python 2.7, 3.3, 3.4, 3.5, 3.6, 3.7 and PyPy * Build on top of lxml and requests * Support for Soap 1.1, Soap 1.2 and HTTP bindings * Support for WS-Addressing headers @@ -77,7 +77,4 @@ If you want to report a bug then please first read http://docs.python-zeep.org/en/master/reporting_bugs.html -I'm also able to offer commercial support. As in contracting work. Please -contact me at [email protected] for more information. Note that asking -questions or reporting bugs via this e-mail address will be ignored. Pleae use -the appropriate channels for that (e.g. stackoverflow) +Please only report bugs and not support requests to the GitHub issue tracker. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/setup.cfg new/zeep-3.2.0/setup.cfg --- old/zeep-3.1.0/setup.cfg 2018-07-28 09:50:37.000000000 +0200 +++ new/zeep-3.2.0/setup.cfg 2018-12-17 10:05:53.000000000 +0100 @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.1.0 +current_version = 3.2.0 commit = true tag = true tag_name = {new_version} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/setup.py new/zeep-3.2.0/setup.py --- old/zeep-3.1.0/setup.py 2018-07-28 09:50:09.000000000 +0200 +++ new/zeep-3.2.0/setup.py 2018-12-17 09:59:37.000000000 +0100 @@ -59,7 +59,7 @@ setup( name='zeep', - version='3.1.0', + version='3.2.0', description='A modern/fast Python SOAP client based on lxml / requests', long_description=long_description, author="Michael van Tellingen", @@ -89,6 +89,7 @@ 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/__init__.py new/zeep-3.2.0/src/zeep/__init__.py --- old/zeep-3.1.0/src/zeep/__init__.py 2018-07-28 09:50:09.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/__init__.py 2018-12-17 09:59:27.000000000 +0100 @@ -4,4 +4,4 @@ from zeep.settings import Settings # noqa from zeep.xsd.valueobjects import AnyObject # noqa -__version__ = '3.1.0' +__version__ = '3.2.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/asyncio/transport.py new/zeep-3.2.0/src/zeep/asyncio/transport.py --- old/zeep-3.1.0/src/zeep/asyncio/transport.py 2018-06-16 09:52:47.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/asyncio/transport.py 2018-12-03 17:52:42.000000000 +0100 @@ -31,7 +31,7 @@ ] def __init__(self, loop, cache=None, timeout=300, operation_timeout=None, - session=None): + session=None, verify_ssl=True, proxy=None): self.loop = loop if loop else asyncio.get_event_loop() self.cache = cache @@ -39,6 +39,8 @@ self.operation_timeout = operation_timeout self.logger = logging.getLogger(__name__) + self.verify_ssl = verify_ssl + self.proxy = proxy self.session = session or aiohttp.ClientSession(loop=self.loop) self._close_session = session is None self.session._default_headers['User-Agent'] = ( @@ -81,7 +83,8 @@ self.logger.debug("HTTP Post to %s:\n%s", address, message) with aio_timeout(self.operation_timeout): response = await self.session.post( - address, data=message, headers=headers) + address, data=message, headers=headers, + verify_ssl=self.verify_ssl, proxy=self.proxy) self.logger.debug( "HTTP Response from %s (status: %d):\n%s", address, response.status, await response.read()) @@ -95,7 +98,8 @@ async def get(self, address, params, headers): with aio_timeout(self.operation_timeout): response = await self.session.get( - address, params=params, headers=headers) + address, params=params, headers=headers, + verify_ssl=self.verify_ssl, proxy=self.proxy) return await self.new_response(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/proxy.py new/zeep-3.2.0/src/zeep/proxy.py --- old/zeep-3.1.0/src/zeep/proxy.py 2018-06-16 09:53:25.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/proxy.py 2018-12-06 17:41:39.000000000 +0100 @@ -70,6 +70,10 @@ except KeyError: raise AttributeError('Service has no operation %r' % key) + def __iter__(self): + """ Return iterator over the services and their callables. """ + return iter(self._operations.items()) + def __dir__(self): """ Return the names of the operations. """ return list(itertools.chain( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/settings.py new/zeep-3.2.0/src/zeep/settings.py --- old/zeep-3.1.0/src/zeep/settings.py 2018-06-16 09:53:25.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/settings.py 2018-12-07 21:38:28.000000000 +0100 @@ -34,6 +34,10 @@ approach to add http headers for specific calls. :type extra_headers: list + :param xsd_ignore_sequence_order: boolean to indicate whether to enforce sequence + order when parsing complex types. This is a workaround for servers that + don't respect sequence order. + :type xsd_ignore_sequence_order: boolean """ strict = attr.ib(default=True) raw_response = attr.ib(default=False) @@ -48,6 +52,9 @@ forbid_entities = attr.ib(default=True) forbid_external = attr.ib(default=True) + # xsd workarounds + xsd_ignore_sequence_order = attr.ib(default=False) + _tls = attr.ib(default=attr.Factory(threading.local)) @contextmanager diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/tornado/transport.py new/zeep-3.2.0/src/zeep/tornado/transport.py --- old/zeep-3.1.0/src/zeep/tornado/transport.py 2018-07-28 08:21:16.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/tornado/transport.py 2018-11-18 11:58:12.000000000 +0100 @@ -124,11 +124,12 @@ kwargs['body'] = message http_req = httpclient.HTTPRequest(address, **kwargs) - response = yield async_client.fetch(http_req) + response = yield async_client.fetch(http_req, raise_error=False) raise gen.Return(self.new_response(response)) - def new_response(self, response): + @staticmethod + def new_response(response): """Convert an tornado.HTTPResponse object to a requests.Response object""" new = Response() new._content = response.body diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/transports.py new/zeep-3.2.0/src/zeep/transports.py --- old/zeep-3.1.0/src/zeep/transports.py 2018-07-28 09:46:50.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/transports.py 2018-11-18 11:17:39.000000000 +0100 @@ -75,7 +75,7 @@ else: log_message = response.content if isinstance(log_message, bytes): - log_message = log_message.decode('utf-8') + log_message = log_message.decode(response.encoding or 'utf-8') self.logger.debug( "HTTP Response from %s (status: %d):\n%s", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/utils.py new/zeep-3.2.0/src/zeep/utils.py --- old/zeep-3.1.0/src/zeep/utils.py 2018-05-13 10:13:32.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/utils.py 2018-12-17 09:25:21.000000000 +0100 @@ -86,4 +86,4 @@ def get_media_type(value): """Parse a HTTP content-type header and return the media-type""" main_value, parameters = cgi.parse_header(value) - return main_value + return main_value.lower() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/wsdl/messages/soap.py new/zeep-3.2.0/src/zeep/wsdl/messages/soap.py --- old/zeep-3.1.0/src/zeep/wsdl/messages/soap.py 2018-06-16 11:27:54.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/wsdl/messages/soap.py 2018-12-07 21:34:15.000000000 +0100 @@ -41,6 +41,7 @@ self.abstract = None # Set during resolve() self.type = type + self._is_body_wrapped = False self.body = None self.header = None self.envelope = None @@ -54,21 +55,30 @@ soap = ElementMaker(namespace=self.nsmap['soap-env'], nsmap=nsmap) + # Create the soap:envelope + envelope = soap.Envelope() + # Create the soap:header element headers_value = kwargs.pop('_soapheaders', None) header = self._serialize_header(headers_value, nsmap) + if header is not None: + envelope.append(header) - # Create the soap:body element - body = soap.Body() + # Create the soap:body element. The _is_body_wrapped attribute signals + # that the self.body element is of type soap:body, so we don't have to + # create it in that case. Otherwise we create a Element soap:body and + # render the content into this. if self.body: body_value = self.body(*args, **kwargs) - self.body.render(body, body_value) - - # Create the soap:envelope - envelope = soap.Envelope() - if header is not None: - envelope.append(header) - envelope.append(body) + if self._is_body_wrapped: + self.body.render(envelope, body_value) + else: + body = soap.Body() + envelope.append(body) + self.body.render(body, body_value) + else: + body = soap.Body() + envelope.append(body) # XXX: This is only used in Soap 1.1 so should be moved to the the # Soap11Binding._set_http_headers(). But let's keep it like this for @@ -279,7 +289,7 @@ # If this message has no parts then we have nothing to do. This might # happen for output messages which don't return anything. - if not abstract_message.parts and self.type != 'input': + if (abstract_message is None or not abstract_message.parts) and self.type != 'input': return self.abstract = abstract_message @@ -399,7 +409,6 @@ def __init__(self, *args, **kwargs): super(DocumentMessage, self).__init__(*args, **kwargs) - self._is_body_wrapped = False def _deserialize_body(self, xmlelement): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/wsdl/parse.py new/zeep-3.2.0/src/zeep/wsdl/parse.py --- old/zeep-3.1.0/src/zeep/wsdl/parse.py 2018-06-16 11:13:16.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/wsdl/parse.py 2018-12-17 09:25:21.000000000 +0100 @@ -39,8 +39,8 @@ for part in xmlelement.findall('wsdl:part', namespaces=NSMAP): part_name = part.get('name') - part_element = qname_attr(part, 'element', tns) - part_type = qname_attr(part, 'type', tns) + part_element = qname_attr(part, 'element') + part_type = qname_attr(part, 'type') try: if part_element is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/wsse/__init__.py new/zeep-3.2.0/src/zeep/wsse/__init__.py --- old/zeep-3.1.0/src/zeep/wsse/__init__.py 2017-03-12 13:53:30.000000000 +0100 +++ new/zeep-3.2.0/src/zeep/wsse/__init__.py 2018-11-18 10:08:17.000000000 +0100 @@ -1,3 +1,3 @@ from .compose import Compose # noqa -from .signature import Signature # noqa +from .signature import BinarySignature, Signature # noqa from .username import UsernameToken # noqa diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/wsse/signature.py new/zeep-3.2.0/src/zeep/wsse/signature.py --- old/zeep-3.1.0/src/zeep/wsse/signature.py 2017-11-04 09:15:21.000000000 +0100 +++ new/zeep-3.2.0/src/zeep/wsse/signature.py 2018-11-18 11:17:39.000000000 +0100 @@ -71,6 +71,17 @@ _read_file(key_file), _read_file(certfile), password) +class BinarySignature(Signature): + """Sign given SOAP envelope with WSSE sig usign given key file and cert file. + + Place the key information into BinarySecurityElement.""" + + def apply(self, envelope, headers): + key = _make_sign_key(self.key_data, self.cert_data, self.password) + _sign_envelope_with_key_binary(envelope, key) + return envelope, headers + + def check_xmlsec_import(): if xmlsec is None: raise ImportError( @@ -173,7 +184,8 @@ return _sign_envelope_with_key(envelope, key) -def _sign_envelope_with_key(envelope, key): +def _signature_prepare(envelope, key): + """Prepare envelope and sign.""" soap_env = detect_soap_env(envelope) # Create the Signature node. @@ -208,9 +220,31 @@ # the X509 data (because it doesn't understand WSSE). sec_token_ref = etree.SubElement( key_info, QName(ns.WSSE, 'SecurityTokenReference')) + return security, sec_token_ref, x509_data + + +def _sign_envelope_with_key(envelope, key): + _, sec_token_ref, x509_data = _signature_prepare(envelope, key) sec_token_ref.append(x509_data) +def _sign_envelope_with_key_binary(envelope, key): + security, sec_token_ref, x509_data = _signature_prepare(envelope, key) + ref = etree.SubElement(sec_token_ref, QName(ns.WSSE, 'Reference'), + {'ValueType': 'http://docs.oasis-open.org/wss/2004/01/' + 'oasis-200401-wss-x509-token-profile-1.0#X509v3'}) + ref_id = ensure_id(ref) + bintok = etree.Element(QName(ns.WSSE, 'BinarySecurityToken'), { + QName(ns.WSU, 'Id'): ref_id, + 'ValueType': 'http://docs.oasis-open.org/wss/2004/01/' + 'oasis-200401-wss-x509-token-profile-1.0#X509v3', + 'EncodingType': 'http://docs.oasis-open.org/wss/2004/01/' + 'oasis-200401-wss-soap-message-security-1.0#Base64Binary'}) + bintok.text = x509_data.find(QName(ns.DS, 'X509Certificate')).text + security.insert(1, bintok) + x509_data.getparent().remove(x509_data) + + def verify_envelope(envelope, certfile): """Verify WS-Security signature on given SOAP envelope with given cert. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/wsse/username.py new/zeep-3.2.0/src/zeep/wsse/username.py --- old/zeep-3.1.0/src/zeep/wsse/username.py 2017-09-29 17:15:39.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/wsse/username.py 2018-12-07 21:40:00.000000000 +0100 @@ -38,13 +38,14 @@ soap_message_secutity_ns = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0' # noqa def __init__(self, username, password=None, password_digest=None, - use_digest=False, nonce=None, created=None): + use_digest=False, nonce=None, created=None, timestamp_token=None): self.username = username self.password = password self.password_digest = password_digest self.nonce = nonce self.created = created self.use_digest = use_digest + self.timestamp_token = timestamp_token def apply(self, envelope, headers): security = utils.get_security_header(envelope) @@ -56,6 +57,9 @@ token = utils.WSSE.UsernameToken() security.append(token) + if self.timestamp_token is not None: + security.append(self.timestamp_token) + # Create the sub elements of the UsernameToken element elements = [ utils.WSSE.Username(self.username) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/xsd/elements/element.py new/zeep-3.2.0/src/zeep/xsd/elements/element.py --- old/zeep-3.1.0/src/zeep/xsd/elements/element.py 2018-06-17 08:56:38.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/xsd/elements/element.py 2018-12-07 21:38:28.000000000 +0100 @@ -159,6 +159,18 @@ item = self.parse( xmlelement, schema, allow_none=True, context=context) result.append(item) + elif ( + schema is not None and + schema.settings.xsd_ignore_sequence_order and + list(filter(lambda elem: etree.QName(elem.tag).localname == self.qname.localname, xmlelements)) + ): + # Search for the field in remaining elements, not only the leftmost + xmlelement = list(filter(lambda elem: etree.QName(elem.tag).localname == self.qname.localname, xmlelements))[0] + xmlelements.remove(xmlelement) + num_matches += 1 + item = self.parse( + xmlelement, schema, allow_none=True, context=context) + result.append(item) else: # If the element passed doesn't match and the current one is # not optional then throw an error diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/xsd/elements/indicators.py new/zeep-3.2.0/src/zeep/xsd/elements/indicators.py --- old/zeep-3.1.0/src/zeep/xsd/elements/indicators.py 2018-05-11 09:16:20.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/xsd/elements/indicators.py 2018-12-03 17:52:42.000000000 +0100 @@ -426,7 +426,10 @@ result.append(choice_value) break else: - if element.name in value: + if isinstance(element, Any): + result.append(value) + break + elif element.name in value: choice_value = value.get(element.name) result.append({element.name: choice_value}) break @@ -539,7 +542,7 @@ if name is not None: try: choice_value = value[name] - except KeyError: + except (KeyError, TypeError): choice_value = value else: choice_value = value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/xsd/schema.py new/zeep-3.2.0/src/zeep/xsd/schema.py --- old/zeep-3.1.0/src/zeep/xsd/schema.py 2018-07-28 08:18:55.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/xsd/schema.py 2018-12-17 09:25:21.000000000 +0100 @@ -102,6 +102,13 @@ seen.add(type_.qname) def add_documents(self, schema_nodes, location): + """ + + :type schema_nodes: List[lxml.etree._Element] + :type location: str + :type target_namespace: Optional[str] + + """ resolve_queue = [] for node in schema_nodes: document = self.create_new_document(node, location) @@ -133,6 +140,7 @@ :rtype: zeep.xsd.ComplexType or zeep.xsd.AnySimpleType + """ qname = self._create_qname(qname) try: @@ -191,16 +199,17 @@ return 'soap-env' return namespace - def create_new_document(self, node, url, base_url=None): + def create_new_document(self, node, url, base_url=None, target_namespace=None): """ :rtype: zeep.xsd.schema.SchemaDocument """ namespace = node.get('targetNamespace') if node is not None else None + if not namespace: + namespace = target_namespace if base_url is None: base_url = url - schema = SchemaDocument(namespace, url, base_url) self.documents.add(schema) schema.load(self, node) @@ -377,6 +386,7 @@ self._location = location self._target_namespace = namespace self._is_internal = False + self._has_empty_import = False # Containers for specific types self._attribute_groups = {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/xsd/types/builtins.py new/zeep-3.2.0/src/zeep/xsd/types/builtins.py --- old/zeep-3.1.0/src/zeep/xsd/types/builtins.py 2018-05-12 12:09:30.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/xsd/types/builtins.py 2018-12-17 09:25:21.000000000 +0100 @@ -123,6 +123,8 @@ @check_no_collection def xmlvalue(self, value): + if isinstance(value, six.string_types): + return value # Bit of a hack, since datetime is a subclass of date we can't just # test it with an isinstance(). And actually, we should not really diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep/xsd/visitor.py new/zeep-3.2.0/src/zeep/xsd/visitor.py --- old/zeep-3.1.0/src/zeep/xsd/visitor.py 2018-07-28 08:17:11.000000000 +0200 +++ new/zeep-3.2.0/src/zeep/xsd/visitor.py 2018-12-17 09:25:21.000000000 +0100 @@ -91,6 +91,8 @@ if not ref: return + ref = self._create_qname(ref) + if node.tag == tags.element: cls = xsd_elements.RefElement elif node.tag == tags.attribute: @@ -129,7 +131,12 @@ """ assert node is not None - self.document._target_namespace = node.get('targetNamespace') + # A schema should always have a targetNamespace attribute, otherwise + # it is called a chameleon schema. In that case the schema will inherit + # the namespace of the enclosing schema/node. + tns = node.get('targetNamespace') + if tns: + self.document._target_namespace = tns self.document._element_form = node.get('elementFormDefault', 'unqualified') self.document._attribute_form = node.get('attributeFormDefault', 'unqualified') @@ -168,6 +175,16 @@ filename=self._document.location, sourceline=node.sourceline) + # We found an empty <import/> statement, this needs to trigger 4.1.2 + # from https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#src-resolve + # for QName resolving. + # In essence this means we will resolve QNames without a namespace to no + # namespace instead of the target namespace. + # The following code snippet works because imports have to occur before we + # visit elements. + if not namespace and not location: + self.document._has_empty_import = True + # Check if the schema is already imported before based on the # namespace. Schema's without namespace are registered as 'None' document = self.schema.documents.get_by_namespace_and_location(namespace, location) @@ -207,7 +224,13 @@ filename=self.document._location, sourceline=node.sourceline) - schema = self.schema.create_new_document(schema_node, location) + # If the imported schema doesn't define a target namespace and the + # node doesn't specify it either then inherit the existing target + # namespace. + elif not schema_tns and not namespace: + namespace = self.document._target_namespace + + schema = self.schema.create_new_document(schema_node, location, target_namespace=namespace) self.register_import(namespace, schema) return schema @@ -1157,6 +1180,9 @@ namespace=name.namespace, schemaLocation=name.namespace) self.visit_import(import_node, None) + if (not name.namespace and self.document._element_form == 'qualified' and + self.document._target_namespace and not self.document._has_empty_import): + name = etree.QName(self.document._target_namespace, name.localname) return name def _pop_annotation(self, items): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep.egg-info/PKG-INFO new/zeep-3.2.0/src/zeep.egg-info/PKG-INFO --- old/zeep-3.1.0/src/zeep.egg-info/PKG-INFO 2018-07-28 09:50:37.000000000 +0200 +++ new/zeep-3.2.0/src/zeep.egg-info/PKG-INFO 2018-12-17 10:05:52.000000000 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: zeep -Version: 3.1.0 +Version: 3.2.0 Summary: A modern/fast Python SOAP client based on lxml / requests Home-page: http://docs.python-zeep.org Author: Michael van Tellingen @@ -13,7 +13,7 @@ A fast and modern Python SOAP client Highlights: - * Compatible with Python 2.7, 3.3, 3.4, 3.5, 3.6 and PyPy + * Compatible with Python 2.7, 3.3, 3.4, 3.5, 3.6, 3.7 and PyPy * Build on top of lxml and requests * Support for Soap 1.1, Soap 1.2 and HTTP bindings * Support for WS-Addressing headers @@ -62,10 +62,7 @@ If you want to report a bug then please first read http://docs.python-zeep.org/en/master/reporting_bugs.html - I'm also able to offer commercial support. As in contracting work. Please - contact me at [email protected] for more information. Note that asking - questions or reporting bugs via this e-mail address will be ignored. Pleae use - the appropriate channels for that (e.g. stackoverflow) + Please only report bugs and not support requests to the GitHub issue tracker. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable @@ -76,5 +73,11 @@ Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy +Provides-Extra: async +Provides-Extra: tornado +Provides-Extra: docs +Provides-Extra: xmlsec +Provides-Extra: test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep.egg-info/SOURCES.txt new/zeep-3.2.0/src/zeep.egg-info/SOURCES.txt --- old/zeep-3.1.0/src/zeep.egg-info/SOURCES.txt 2018-07-28 09:50:37.000000000 +0200 +++ new/zeep-3.2.0/src/zeep.egg-info/SOURCES.txt 2018-12-17 10:05:52.000000000 +0100 @@ -109,6 +109,7 @@ tests/test_wsdl_messages_document.py tests/test_wsdl_messages_http.py tests/test_wsdl_messages_rpc.py +tests/test_wsdl_no_output_message_part.py tests/test_wsdl_soap.py tests/test_wsse_signature.py tests/test_wsse_username.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/src/zeep.egg-info/requires.txt new/zeep-3.2.0/src/zeep.egg-info/requires.txt --- old/zeep-3.1.0/src/zeep.egg-info/requires.txt 2018-07-28 09:50:37.000000000 +0200 +++ new/zeep-3.2.0/src/zeep.egg-info/requires.txt 2018-12-17 10:05:52.000000000 +0100 @@ -31,7 +31,7 @@ aioresponses>=0.4.1 [tornado] -tornado>=4.0.2,<5 +tornado<5,>=4.0.2 [xmlsec] xmlsec>=0.6.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_tornado_transport.py new/zeep-3.2.0/tests/test_tornado_transport.py --- old/zeep-3.1.0/tests/test_tornado_transport.py 2017-11-04 09:15:21.000000000 +0100 +++ new/zeep-3.2.0/tests/test_tornado_transport.py 2018-12-03 17:13:14.000000000 +0100 @@ -9,6 +9,22 @@ from zeep.tornado import TornadoAsyncTransport [email protected] +@patch('tornado.httpclient.HTTPClient.fetch') +def test_tornado_load(mock_httpclient_fetch): + cache = stub(get=lambda url: None, add=lambda url, content: None) + response = HTTPResponse(HTTPRequest('http://tests.python-zeep.org/test.xml'), 200) + response.buffer = True + response._body = 'x' + mock_httpclient_fetch.return_value = response + + transport = TornadoAsyncTransport(cache=cache) + + result = transport.load('http://tests.python-zeep.org/test.xml') + + assert result == 'x' + + class TornadoAsyncTransportTest(AsyncTestCase): @pytest.mark.requests def test_no_cache(self): @@ -16,22 +32,6 @@ assert transport.cache is None @pytest.mark.requests - @patch('tornado.httpclient.HTTPClient.fetch') - @gen_test - def test_load(self, mock_httpclient_fetch): - cache = stub(get=lambda url: None, add=lambda url, content: None) - response = HTTPResponse(HTTPRequest('http://tests.python-zeep.org/test.xml'), 200) - response.buffer = True - response._body = 'x' - mock_httpclient_fetch.return_value = response - - transport = TornadoAsyncTransport(cache=cache) - - result = transport.load('http://tests.python-zeep.org/test.xml') - - assert result == 'x' - - @pytest.mark.requests @patch('tornado.httpclient.AsyncHTTPClient.fetch') @gen_test def test_post(self, mock_httpclient_fetch): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_wsdl.py new/zeep-3.2.0/tests/test_wsdl.py --- old/zeep-3.1.0/tests/test_wsdl.py 2018-06-16 09:53:25.000000000 +0200 +++ new/zeep-3.2.0/tests/test_wsdl.py 2018-12-17 09:25:21.000000000 +0100 @@ -1034,3 +1034,125 @@ assert headers['Authorization'] == 'Bearer 1234' + +def test_wsdl_no_schema_namespace(): + wsdl_main = StringIO(""" + <wsdl:definitions + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:tns="http://Example.org" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://Example.org" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> + <wsdl:types> + <xsd:schema elementFormDefault="qualified" > + <xsd:element name="AddResponse"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="1" ref="demo" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="Add"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" name="a" type="xsd:int" /> + <xsd:element minOccurs="1" name="b" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="AddResponse"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="0" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <xsd:schema elementFormDefault="qualified" > + <xsd:element name="demo"> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="ICalculator_Add_InputMessage"> + <wsdl:part name="parameters" element="Add" /> + </wsdl:message> + <wsdl:message name="ICalculator_Add_OutputMessage"> + <wsdl:part name="parameters" element="AddResponse" /> + </wsdl:message> + <wsdl:portType name="ICalculator"> + <wsdl:operation name="Add"> + <wsdl:input message="tns:ICalculator_Add_InputMessage" /> + <wsdl:output message="tns:ICalculator_Add_OutputMessage" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="DefaultBinding_ICalculator" type="tns:ICalculator"> + <soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="Add"> + <soap:operation soapAction="http://Example.org/ICalculator/Add" style="document" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="CalculatorService"> + <wsdl:port name="ICalculator" binding="tns:DefaultBinding_ICalculator"> + <soap:address location="http://Example.org/ICalculator" /> + </wsdl:port> + </wsdl:service> + </wsdl:definitions> + """) + client = stub(settings=Settings(), plugins=[], wsse=None) + + transport = DummyTransport() + document = wsdl.Document(wsdl_main, transport) + binding = document.services.get('CalculatorService').ports.get('ICalculator').binding + + envelope, headers = binding._create( + 'Add', + args=[3, 4], + kwargs={}, + client=client, + options={'address': 'http://tests.python-zeep.org/test'}) + + expected = """ + <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> + <soap-env:Body> + <Add> + <a>3</a> + <b>4</b> + </Add> + </soap-env:Body> + </soap-env:Envelope> + """ + assert_nodes_equal(expected, envelope) + + +def test_namespaced_wsdl_with_empty_import(): + # See https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#src-resolve for details + wsdl_main = StringIO(""" + <wsdl:definitions xmlns:s="http://www.w3.org/2001/XMLSchema" targetNamespace="weird_wsdl" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> + <wsdl:types> + <s:schema elementFormDefault="qualified" targetNamespace="weird_wsdl"> + <s:import /> + <s:element name="GetVTInfoResponse"> + <s:complexType> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" ref="GetVTInfoResult" /> + </s:sequence> + </s:complexType> + </s:element> + </s:schema> + <s:schema elementFormDefault="qualified"> + <s:element name="GetVTInfoResult" /> + </s:schema> + </wsdl:types> + </wsdl:definitions> + """) + + transport = DummyTransport() + document = wsdl.Document(wsdl_main, transport) + document.dump() + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_wsdl_messages_document.py new/zeep-3.2.0/tests/test_wsdl_messages_document.py --- old/zeep-3.1.0/tests/test_wsdl_messages_document.py 2017-11-04 09:15:21.000000000 +0100 +++ new/zeep-3.2.0/tests/test_wsdl_messages_document.py 2018-12-07 21:32:00.000000000 +0100 @@ -332,6 +332,78 @@ assert_nodes_equal(expected, serialized.content) +def test_serialize_multiple_parts(): + wsdl_content = StringIO(""" + <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" + xmlns:tns="http://tests.python-zeep.org/tns" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://tests.python-zeep.org/tns"> + <types> + <xsd:schema targetNamespace="http://tests.python-zeep.org/tns" + elementFormDefault="qualified"> + <xsd:element name="Request"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="arg1" type="xsd:string"/> + <xsd:element name="arg2" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </types> + + <message name="Input"> + <part name="request1" element="tns:Request"/> + <part name="request2" element="tns:Request"/> + </message> + + <portType name="TestPortType"> + <operation name="TestOperation"> + <input message="Input"/> + </operation> + </portType> + + <binding name="TestBinding" type="tns:TestPortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> + <operation name="TestOperation"> + <soap:operation soapAction=""/> + <input> + <soap:body use="literal"/> + </input> + </operation> + </binding> + </definitions> + """.strip()) + + root = wsdl.Document(wsdl_content, None) + + binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding'] + operation = binding.get('TestOperation') + + serialized = operation.input.serialize( + request1={'arg1': 'ah1', 'arg2': 'ah2'}, + request2={'arg1': 'ah1', 'arg2': 'ah2'} + ) + expected = """ + <?xml version="1.0"?> + <soap-env:Envelope + xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> + <soap-env:Body> + <ns0:Request xmlns:ns0="http://tests.python-zeep.org/tns"> + <ns0:arg1>ah1</ns0:arg1> + <ns0:arg2>ah2</ns0:arg2> + </ns0:Request> + <ns1:Request xmlns:ns1="http://tests.python-zeep.org/tns"> + <ns1:arg1>ah1</ns1:arg1> + <ns1:arg2>ah2</ns1:arg2> + </ns1:Request> + </soap-env:Body> + </soap-env:Envelope> + """ + assert_nodes_equal(expected, serialized.content) + + def test_serialize_with_header(): wsdl_content = StringIO(""" <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" @@ -394,8 +466,6 @@ serialized = operation.input.serialize( arg1='ah1', arg2='ah2', _soapheaders=[auth_header]) - serialized = operation.input.serialize( - arg1='ah1', arg2='ah2', _soapheaders=[auth_header]) expected = """ <?xml version="1.0"?> <soap-env:Envelope diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_wsdl_no_output_message_part.py new/zeep-3.2.0/tests/test_wsdl_no_output_message_part.py --- old/zeep-3.1.0/tests/test_wsdl_no_output_message_part.py 1970-01-01 01:00:00.000000000 +0100 +++ new/zeep-3.2.0/tests/test_wsdl_no_output_message_part.py 2018-12-07 21:23:22.000000000 +0100 @@ -0,0 +1,56 @@ +from six import StringIO +from zeep.wsdl import wsdl + + +def test_wsdl_parses_operations_with_no_output(): + + wsdl_content = StringIO(""" + <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" + xmlns:tns="http://tests.python-zeep.org/tns" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://tests.python-zeep.org/tns"> + <types> + <xsd:schema targetNamespace="http://tests.python-zeep.org/tns"> + <xsd:element name="Request" type="xsd:string"/> + <xsd:element name="Response" type="xsd:string"/> + </xsd:schema> + </types> + + <message name="Input"> + <part element="tns:Request"/> + </message> + <message name="Output"> + <part element="tns:Response"/> + </message> + + <portType name="TestPortType"> + <operation name="TestOperation"> + <input message="Input"/> + </operation> + </portType> + + <binding name="TestBinding" type="tns:TestPortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> + <operation name="TestOperation"> + <soap:operation soapAction=""/> + <input> + <soap:body use="literal"/> + </input> + <output> + <soap:body use="literal"/> + </output> + </operation> + </binding> + </definitions> + """) + # parse the content + root = wsdl.Document(wsdl_content, None) + + binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding'] + operation = binding.get('TestOperation') + # General assertions on the input + assert operation.input.body.signature(schema=root.types) == 'ns0:Request(xsd:string)' + assert operation.input.header.signature(schema=root.types) == 'soap-env:Header()' + assert operation.input.envelope.signature(schema=root.types) == 'soap-env:envelope(body: xsd:string)' + assert operation.input.signature(as_output=False) == 'xsd:string' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_wsse_signature.py new/zeep-3.2.0/tests/test_wsse_signature.py --- old/zeep-3.1.0/tests/test_wsse_signature.py 2017-11-04 09:15:21.000000000 +0100 +++ new/zeep-3.2.0/tests/test_wsse_signature.py 2018-11-18 10:08:17.000000000 +0100 @@ -16,9 +16,14 @@ KEY_FILE_PW = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'cert_valid_pw.pem') +# Check whether xmlsec library has been installed +from zeep.wsse.signature import xmlsec as xmlsec_installed +skip_if_no_xmlsec = pytest.mark.skipif(sys.platform == 'win32', + reason="does not run on windows") and \ + pytest.mark.skipif(xmlsec_installed is None, + reason="xmlsec library not installed") [email protected](sys.platform == 'win32', - reason="does not run on windows") +@skip_if_no_xmlsec def test_sign(): envelope = load_xml(""" <soapenv:Envelope @@ -39,8 +44,7 @@ signature.verify_envelope(envelope, KEY_FILE) [email protected](sys.platform == 'win32', - reason="does not run on windows") +@skip_if_no_xmlsec def test_sign_pw(): envelope = load_xml(""" <soapenv:Envelope @@ -61,8 +65,7 @@ signature.verify_envelope(envelope, KEY_FILE_PW) [email protected](sys.platform == 'win32', - reason="does not run on windows") +@skip_if_no_xmlsec def test_verify_error(): envelope = load_xml(""" <soapenv:Envelope @@ -89,8 +92,7 @@ signature.verify_envelope(envelope, KEY_FILE) [email protected](sys.platform == 'win32', - reason="does not run on windows") +@skip_if_no_xmlsec def test_signature(): envelope = load_xml(""" <soapenv:Envelope @@ -110,3 +112,26 @@ plugin = wsse.Signature(KEY_FILE_PW, KEY_FILE_PW, 'geheim') envelope, headers = plugin.apply(envelope, {}) plugin.verify(envelope) + + [email protected](sys.platform == 'win32', + reason="does not run on windows") +def test_signature_binary(): + envelope = load_xml(""" + <soapenv:Envelope + xmlns:tns="http://tests.python-zeep.org/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> + <soapenv:Header></soapenv:Header> + <soapenv:Body> + <tns:Function> + <tns:Argument>OK</tns:Argument> + </tns:Function> + </soapenv:Body> + </soapenv:Envelope> + """) + + plugin = wsse.BinarySignature(KEY_FILE_PW, KEY_FILE_PW, 'geheim') + envelope, headers = plugin.apply(envelope, {}) + plugin.verify(envelope) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_wsse_username.py new/zeep-3.2.0/tests/test_wsse_username.py --- old/zeep-3.1.0/tests/test_wsse_username.py 2017-09-29 17:24:42.000000000 +0200 +++ new/zeep-3.2.0/tests/test_wsse_username.py 2018-12-07 21:40:00.000000000 +0100 @@ -1,13 +1,13 @@ import datetime import os - import pytest import requests_mock -from freezegun import freeze_time +from freezegun import freeze_time from tests.utils import assert_nodes_equal, load_xml from zeep import client from zeep.wsse import UsernameToken +from zeep.wsse.utils import WSU @pytest.mark.requests @@ -236,3 +236,67 @@ </soap-env:Envelope> """ # noqa assert_nodes_equal(envelope, expected) + + +def test_timestamp_token(): + envelope = load_xml(""" + <soap-env:Envelope + xmlns:ns0="http://example.com/stockquote.xsd" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + xmlns:wsu="http://schemas.xmlsoap.org/ws/2003/06/utility" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + > + <soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> + <ns0:Security> + <ns0:UsernameToken/> + </ns0:Security> + </soap-env:Header> + <soap-env:Body> + <ns0:TradePriceRequest> + <tickerSymbol>foobar</tickerSymbol> + <ns0:country/> + </ns0:TradePriceRequest> + </soap-env:Body> + </soap-env:Envelope> + """) # noqa + + timestamp_token = WSU.Timestamp() + timestamp_token.attrib['Id'] = 'id-21a27a50-9ebf-49cc-96bf-fcf7131e7858' + some_date_obj = datetime.datetime(2018, 11, 18, 15, 44, 27, 440252) + timestamp_elements = [WSU.Created(some_date_obj.strftime("%Y-%m-%dT%H:%M:%SZ")), + WSU.Expires((some_date_obj + datetime.timedelta(minutes=10)).strftime("%Y-%m-%dT%H:%M:%SZ"))] + timestamp_token.extend(timestamp_elements) + + token = UsernameToken('Vishu', 'Guntupalli', timestamp_token=timestamp_token) + envelope, headers = token.apply(envelope, {}) + expected = """ + <soap-env:Envelope + xmlns:ns0="http://example.com/stockquote.xsd" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + xmlns:wsu="http://schemas.xmlsoap.org/ws/2003/06/utility" + xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> + <ns0:Security> + <ns0:UsernameToken> + <ns0:Username>Vishu</ns0:Username> + <ns0:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Guntupalli</ns0:Password> + </ns0:UsernameToken> + <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" Id="id-21a27a50-9ebf-49cc-96bf-fcf7131e7858"> + <wsu:Created>2018-11-18T15:44:27Z</wsu:Created> + <wsu:Expires>2018-11-18T15:54:27Z</wsu:Expires> + </wsu:Timestamp> + </ns0:Security> + </soap-env:Header> + <soap-env:Body> + <ns0:TradePriceRequest> + <tickerSymbol>foobar</tickerSymbol> + <ns0:country/> + </ns0:TradePriceRequest> + </soap-env:Body> + </soap-env:Envelope> + """ # noqa + assert_nodes_equal(envelope, expected) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_xsd_builtins.py new/zeep-3.2.0/tests/test_xsd_builtins.py --- old/zeep-3.1.0/tests/test_xsd_builtins.py 2018-05-12 12:06:55.000000000 +0200 +++ new/zeep-3.2.0/tests/test_xsd_builtins.py 2018-12-17 09:25:21.000000000 +0100 @@ -131,6 +131,9 @@ value = value.astimezone(pytz.timezone('Europe/Amsterdam')) assert instance.xmlvalue(value) == '2016-03-04T22:14:42+01:00' + assert instance.xmlvalue('2016-03-04T22:14:42+01:00') == '2016-03-04T22:14:42+01:00' + assert instance.xmlvalue('2016-03-04') == '2016-03-04' + def test_pythonvalue(self): instance = builtins.DateTime() value = datetime.datetime(2016, 3, 4, 21, 14, 42) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_xsd_complex_types.py new/zeep-3.2.0/tests/test_xsd_complex_types.py --- old/zeep-3.1.0/tests/test_xsd_complex_types.py 2018-05-11 09:16:20.000000000 +0200 +++ new/zeep-3.2.0/tests/test_xsd_complex_types.py 2018-12-07 21:38:28.000000000 +0100 @@ -2,7 +2,7 @@ from lxml import etree from tests.utils import assert_nodes_equal, load_xml, render_node -from zeep import xsd +from zeep import exceptions, xsd def test_xml_xml_single_node(): @@ -330,3 +330,56 @@ obj = container_elm.parse(result[0], schema) assert obj._value_1 is None + + +def test_ignore_sequence_order(): + schema_doc = load_xml(b""" + <?xml version="1.0" encoding="utf-8"?> + <xsd:schema xmlns:tns="http://tests.python-zeep.org/attr" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + elementFormDefault="qualified" + targetNamespace="http://tests.python-zeep.org/attr"> + <xsd:complexType name="Result"> + <xsd:attribute name="id" type="xsd:int" use="required"/> + </xsd:complexType> + <xsd:element name="Response"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="1" name="Foo" type="tns:Result"/> + <xsd:element minOccurs="0" maxOccurs="1" name="Bar" type="tns:Result"/> + <xsd:element minOccurs="0" maxOccurs="1" name="Baz" type="tns:Result"/> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + """) + + response_doc = load_xml(b""" + <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> + <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Response xmlns="http://tests.python-zeep.org/attr"> + <Foo id="1"/> + <Baz id="3"/> + <Bar id="2"/> + </Response> + </s:Body> + </s:Envelope> + """) + + schema = xsd.Schema(schema_doc) + elm = schema.get_element('{http://tests.python-zeep.org/attr}Response') + schema.settings.xsd_ignore_sequence_order = False + + node = response_doc.xpath( + '//ns0:Response', namespaces={ + 'xsd': 'http://www.w3.org/2001/XMLSchema', + 'ns0': 'http://tests.python-zeep.org/attr', + }) + with pytest.raises(exceptions.XMLParseError) as exc: + response = elm.parse(node[0], schema) + assert str(exc) is not None + + schema.settings.xsd_ignore_sequence_order = True + + response = elm.parse(node[0], schema) + assert response.Baz.id == 3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zeep-3.1.0/tests/test_xsd_indicators_choice.py new/zeep-3.2.0/tests/test_xsd_indicators_choice.py --- old/zeep-3.1.0/tests/test_xsd_indicators_choice.py 2018-05-12 10:46:19.000000000 +0200 +++ new/zeep-3.2.0/tests/test_xsd_indicators_choice.py 2018-12-03 17:52:42.000000000 +0100 @@ -308,6 +308,50 @@ assert result.item_1 == 'foo' +def test_choice_element_with_only_any(): + node = etree.fromstring(""" + <?xml version="1.0"?> + <xsd:schema + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tns="http://tests.python-zeep.org/" + elementFormDefault="qualified" + targetNamespace="http://tests.python-zeep.org/"> + <xsd:element name="container"> + <xsd:complexType> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:any processContents="lax"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:QName" use="required" /> + <xsd:attribute name="something" type="xsd:boolean" use="required" /> + <xsd:anyAttribute namespace="##other" processContents="lax"/> + </xsd:complexType> + </xsd:element> + <xsd:element name="item_1" type="xsd:string" /> + </xsd:schema> + """.strip()) + schema = xsd.Schema(node) + element = schema.get_element('ns0:container') + item_1 = schema.get_element('ns0:item_1') + any_object = xsd.AnyObject(item_1, item_1('foo')) + value = element(_value_1=[any_object], name="foo", something="bar") + + expected = """ + <document> + <ns0:container xmlns:ns0="http://tests.python-zeep.org/" name="foo" something="true"> + <ns0:item_1>foo</ns0:item_1> + </ns0:container> + </document> + """ + node = etree.Element('document') + element.render(node, value) + assert_nodes_equal(expected, node) + + result = element.parse(node[0], schema) + assert result.name == 'foo' + assert result.something is True + assert result._value_1 == ['foo'] + + def test_choice_element_with_any_max_occurs(): schema = xsd.Schema(load_xml(""" <schema targetNamespace="http://tests.python-zeep.org/"
