From f98da13f7c6e247cf6e333ffbc8bf1be9cbb44d6 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 19 Sep 2021 23:49:58 +0300 Subject: [PATCH 01/41] Add support for Python 3.10 --- .github/workflows/python-test.yml | 11 +++++++---- README.rst | 2 +- setup.py | 4 +++- tox.ini | 11 ++++++----- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 2e82c6cd..399c4ff1 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python 3.7 - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.7 - name: Install dependencies @@ -23,7 +23,10 @@ jobs: max-parallel: 4 matrix: platform: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.6", "3.7", "3.8", "3.9"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev"] + # TODO: Remove Windows exclusion when binary wheel available for lxml + exclude: + - { platform: windows-latest, python-version: "3.10-dev" } steps: - name: Install system dependencies @@ -37,7 +40,7 @@ jobs: brew install libxmlsec1 libxslt pkgconfig - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -65,7 +68,7 @@ jobs: name: coverage-data path: . - name: Set up Python 3.7 - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.7 - name: Install dependencies diff --git a/README.rst b/README.rst index f3af7b4f..6a05eca4 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Zeep: Python SOAP client A fast and modern Python SOAP client Highlights: - * Compatible with Python 3.6, 3.7, 3.8, 3.9 and PyPy + * Compatible with Python 3.6, 3.7, 3.8, 3.9, 3.10 and PyPy3 * Build on top of lxml and requests * Support for Soap 1.1, Soap 1.2 and HTTP bindings * Support for WS-Addressing headers diff --git a/setup.py b/setup.py index 8ef81b6a..04ed3dea 100755 --- a/setup.py +++ b/setup.py @@ -55,7 +55,7 @@ long_description=long_description, author="Michael van Tellingen", author_email="michaelvantellingen@gmail.com", - url="http://docs.python-zeep.org", + url="https://docs.python-zeep.org", python_requires=">=3.6", install_requires=install_requires, tests_require=tests_require, @@ -74,10 +74,12 @@ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ], diff --git a/tox.ini b/tox.ini index 3a36b4a7..221f1e65 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{36,37,38,39}-{mac,linux,windows},pypy +envlist = py{36,37,38,39,310}-{mac,linux,windows},pypy [gh-actions] python = @@ -7,6 +7,7 @@ python = 3.7: py37 3.8: py38 3.9: py39 + 3.10: py310 [testenv] @@ -17,11 +18,11 @@ platform = extras = test {mac,linux}: xmlsec - py{36,37,38,39}: async + py{36,37,38,39,310}: async deps = - py{36,37,38,39}: aioresponses==0.5.0 - py{36,37,38,39}: aiohttp==3.4.4 - py{36,37,38,39}: pytest-asyncio==0.11.0 + py{36,37,38,39,310}: aioresponses==0.5.0 + py{36,37,38,39,310}: aiohttp==3.4.4 + py{36,37,38,39,310}: pytest-asyncio==0.11.0 commands = coverage run --parallel -m pytest {posargs} From 1db30cbb318b34afc7744f85523953d3a4fe7665 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 19 Sep 2021 23:54:08 +0300 Subject: [PATCH 02/41] fail-fast: false --- .github/workflows/python-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 399c4ff1..902c15e7 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -20,6 +20,7 @@ jobs: test: runs-on: ${{ matrix.platform }} strategy: + fail-fast: false max-parallel: 4 matrix: platform: [ubuntu-latest, macos-latest, windows-latest] From 8a788765a0e301abeceef254ec9f8f26a811cacd Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 20 Sep 2021 00:00:31 +0300 Subject: [PATCH 03/41] Bump pytest pin to support Python 3.10 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 04ed3dea..dfa79a58 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ "pytest-cov==2.8.1", "pytest-httpx", "pytest-asyncio", - "pytest==6.0.1", + "pytest==6.2.5", "requests_mock>=0.7.0", # Linting "isort==5.3.2", From 84f968ce0e22ec1ee4e7cd2e127c182df73ce9e8 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 20 Sep 2021 00:18:15 +0300 Subject: [PATCH 04/41] Bump aiohttp pin to support Python 3.10 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 221f1e65..f6d1331e 100644 --- a/tox.ini +++ b/tox.ini @@ -21,7 +21,7 @@ extras = py{36,37,38,39,310}: async deps = py{36,37,38,39,310}: aioresponses==0.5.0 - py{36,37,38,39,310}: aiohttp==3.4.4 + py{36,37,38,39,310}: aiohttp==3.7.4 py{36,37,38,39,310}: pytest-asyncio==0.11.0 commands = coverage run --parallel -m pytest {posargs} From 1ddd118956870f9c68a24c9494207dc17441b416 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 20 Sep 2021 00:28:03 +0300 Subject: [PATCH 05/41] Remove redundant backport and code --- setup.py | 1 - tests/conftest.py | 4 ---- tests/test_main.py | 3 ++- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index dfa79a58..4cf9073b 100755 --- a/setup.py +++ b/setup.py @@ -27,7 +27,6 @@ tests_require = [ "coverage[toml]==5.2.1", "freezegun==0.3.15", - "mock==2.0.0", "pretend==1.0.9", "pytest-cov==2.8.1", "pytest-httpx", diff --git a/tests/conftest.py b/tests/conftest.py index 64c9bf95..4bd41de0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,10 +2,6 @@ import pytest -# Don't try to test asyncio since it is py3 only syntax -if sys.version_info < (3, 5): - collect_ignore = ["test_asyncio_transport.py"] - pytest.register_assert_rewrite("tests.utils") diff --git a/tests/test_main.py b/tests/test_main.py index bffc7230..f4504820 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,4 +1,5 @@ -from mock import patch +from unittest.mock import patch + from pretend import stub from zeep import __main__, client From f1920301b17e4fd42d5fb13603cd889f19255c29 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 5 Oct 2021 16:04:58 +0300 Subject: [PATCH 06/41] Test on Python 3.10 final --- .github/workflows/python-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 902c15e7..6ee31cbc 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -24,10 +24,10 @@ jobs: max-parallel: 4 matrix: platform: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] # TODO: Remove Windows exclusion when binary wheel available for lxml exclude: - - { platform: windows-latest, python-version: "3.10-dev" } + - { platform: windows-latest, python-version: "3.10" } steps: - name: Install system dependencies From 2f35b7d29355ba646f5e3c6e9925033d5d6df8bb Mon Sep 17 00:00:00 2001 From: Dmitry Ryzhikov Date: Fri, 17 Dec 2021 22:33:19 +0100 Subject: [PATCH 07/41] Minor AsyncTransport cleanup Remove unused session argument. Remove import of unused and not installed libs: aioresponses, aiohttp. --- src/zeep/transports.py | 1 - tests/test_async_transport.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/zeep/transports.py b/src/zeep/transports.py index f9b46f77..0841e2f1 100644 --- a/src/zeep/transports.py +++ b/src/zeep/transports.py @@ -175,7 +175,6 @@ def __init__( cache=None, timeout=300, operation_timeout=None, - session=None, verify_ssl=True, proxy=None, ): diff --git a/tests/test_async_transport.py b/tests/test_async_transport.py index 940b48a3..f5e8d1b0 100644 --- a/tests/test_async_transport.py +++ b/tests/test_async_transport.py @@ -1,6 +1,4 @@ -import aiohttp import pytest -from aioresponses import aioresponses from lxml import etree from pretend import stub from pytest_httpx import HTTPXMock From e8fb1e27f44a0720cedf0f3866f1b5b9e8d6a5d5 Mon Sep 17 00:00:00 2001 From: Jean-Denis Girard Date: Wed, 14 Sep 2022 14:34:57 -1000 Subject: [PATCH 08/41] Allow CDATA text We needed to send embedded XML as CDATA in the request. Without this modification, the embedded XML was escaped, now it is transmitted unmodified. --- src/zeep/xsd/types/simple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zeep/xsd/types/simple.py b/src/zeep/xsd/types/simple.py index a492969c..943673d7 100644 --- a/src/zeep/xsd/types/simple.py +++ b/src/zeep/xsd/types/simple.py @@ -93,7 +93,7 @@ def render( if value is Nil: node.set(xsi_ns("nil"), "true") return - node.text = self.xmlvalue(value) + node.text = value if isinstance(value, etree.CDATA) else self.xmlvalue(value) def signature(self, schema=None, standalone=True): return self.get_prefixed_name(schema) From b53b17713ba2a2b0cd0a9587f345459bf53e6478 Mon Sep 17 00:00:00 2001 From: Michael Heyvaert Date: Sat, 6 Aug 2022 00:22:45 +0200 Subject: [PATCH 09/41] allow to pass a preparsed Document in the zeep Client --- src/zeep/client.py | 7 +++++-- tests/test_client.py | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/zeep/client.py b/src/zeep/client.py index 6c42741f..56f9a61c 100644 --- a/src/zeep/client.py +++ b/src/zeep/client.py @@ -38,7 +38,7 @@ def __getitem__(self, key): class Client: """The zeep Client. - :param wsdl: + :param wsdl: Url/local WSDL location or preparsed WSDL Document :param wsse: :param transport: Custom transport class. :param service_name: The service name for the service binding. Defaults to @@ -70,7 +70,10 @@ def __init__( self.transport = ( transport if transport is not None else self._default_transport() ) - self.wsdl = Document(wsdl, self.transport, settings=self.settings) + if isinstance(wsdl, Document): + self.wsdl = wsdl + else: + self.wsdl = Document(wsdl, self.transport, settings=self.settings) self.wsse = wsse self.plugins = plugins if plugins is not None else [] diff --git a/tests/test_client.py b/tests/test_client.py index c73170fc..3b26578b 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -5,6 +5,8 @@ from tests.utils import load_xml from zeep import client, xsd +from zeep.wsdl import Document +from zeep.transports import Transport from zeep.exceptions import Error @@ -14,6 +16,13 @@ def test_bind(): assert service +def test_bind_existing_document(): + wsdl = Document("tests/wsdl_files/soap.wsdl", transport=Transport()) + client_obj = client.Client(wsdl) + service = client_obj.bind() + assert service + + def test_unknown_transport(): client_obj = client.Client("tests/wsdl_files/soap_transport_err.wsdl") service = client_obj.bind() From 48c860f978cfff138578b0d9d03daab913711f9d Mon Sep 17 00:00:00 2001 From: Romuald Brunet Date: Tue, 2 Aug 2022 15:54:52 +0200 Subject: [PATCH 10/41] Fix httpx DeprecationWarning for post data In the httpx module, `data=x` has been deprecated in favor of `content=x` in version 0.18.0 (April 2021) As a side effect, this fixes the test suite since pytest-httpx removed the `data=` mock in version 0.18.0 (January 2022) --- setup.py | 2 +- src/zeep/transports.py | 2 +- tests/test_async_transport.py | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 4cf9073b..b82dcafb 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ "sphinx>=1.4.0", ] -async_require = ["httpx"] +async_require = ["httpx>=0.15.0"] xmlsec_require = [ "xmlsec>=0.6.1", diff --git a/src/zeep/transports.py b/src/zeep/transports.py index 0841e2f1..ffde356b 100644 --- a/src/zeep/transports.py +++ b/src/zeep/transports.py @@ -218,7 +218,7 @@ async def post(self, address, message, headers): self.logger.debug("HTTP Post to %s:\n%s", address, message) response = await self.client.post( address, - data=message, + content=message, headers=headers, ) self.logger.debug( diff --git a/tests/test_async_transport.py b/tests/test_async_transport.py index f5e8d1b0..08f2b0f4 100644 --- a/tests/test_async_transport.py +++ b/tests/test_async_transport.py @@ -19,7 +19,7 @@ def test_load(httpx_mock): cache = stub(get=lambda url: None, add=lambda url, content: None) transport = AsyncTransport(cache=cache) - httpx_mock.add_response(url="http://tests.python-zeep.org/test.xml", data="x") + httpx_mock.add_response(url="http://tests.python-zeep.org/test.xml", content="x") result = transport.load("http://tests.python-zeep.org/test.xml") assert result == b"x" @@ -30,7 +30,7 @@ def test_load_cache(httpx_mock): cache = InMemoryCache() transport = AsyncTransport(cache=cache) - httpx_mock.add_response(url="http://tests.python-zeep.org/test.xml", data="x") + httpx_mock.add_response(url="http://tests.python-zeep.org/test.xml", content="x") result = transport.load("http://tests.python-zeep.org/test.xml") assert result == b"x" @@ -45,7 +45,7 @@ async def test_post(httpx_mock: HTTPXMock): envelope = etree.Element("Envelope") - httpx_mock.add_response(url="http://tests.python-zeep.org/test.xml", data="x") + httpx_mock.add_response(url="http://tests.python-zeep.org/test.xml", content="x") result = await transport.post_xml( "http://tests.python-zeep.org/test.xml", envelope=envelope, headers={} ) @@ -67,7 +67,7 @@ async def test_http_error(httpx_mock: HTTPXMock): transport = AsyncTransport() httpx_mock.add_response( - url="http://tests.python-zeep.org/test.xml", data="x", status_code=500 + url="http://tests.python-zeep.org/test.xml", content="x", status_code=500 ) with pytest.raises(exceptions.TransportError) as exc: transport.load("http://tests.python-zeep.org/test.xml") From f06b447d29f6416c1120a088b3e57f1632de6f73 Mon Sep 17 00:00:00 2001 From: gopackgo90 Date: Fri, 11 Mar 2022 09:51:49 -0600 Subject: [PATCH 11/41] Remove universal wheel, python 2 is unsupported --- setup.cfg | 3 --- 1 file changed, 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 85a238a8..61d90815 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,2 @@ -[wheel] -universal = 1 - [flake8] max-line-length = 99 From b50cb54adbff36bb29a872fd50ca2195cc002ec3 Mon Sep 17 00:00:00 2001 From: Andrii Oriekhov Date: Tue, 1 Mar 2022 20:54:35 +0200 Subject: [PATCH 12/41] add GitHub URL for PyPi --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index b82dcafb..96b428e8 100755 --- a/setup.py +++ b/setup.py @@ -55,6 +55,9 @@ author="Michael van Tellingen", author_email="michaelvantellingen@gmail.com", url="https://docs.python-zeep.org", + project_urls={ + "Source": "https://github.com/mvantellingen/python-zeep", + }, python_requires=">=3.6", install_requires=install_requires, tests_require=tests_require, From 9c5a01613594d37f64eed8ba32052f8ba30ceb83 Mon Sep 17 00:00:00 2001 From: David Jack Wange Olrik Date: Thu, 23 Dec 2021 15:09:19 +0100 Subject: [PATCH 13/41] Fix empty SOAPAction header SOAPAction header should never be "None". When `self.operation.soapaction` is `None` it was stringifyed into `"None"` when it should be `""`. --- src/zeep/wsdl/messages/soap.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/zeep/wsdl/messages/soap.py b/src/zeep/wsdl/messages/soap.py index 553bfa2c..6685a6fa 100644 --- a/src/zeep/wsdl/messages/soap.py +++ b/src/zeep/wsdl/messages/soap.py @@ -84,7 +84,11 @@ def serialize(self, *args, **kwargs): # 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 # now. - headers = {"SOAPAction": '"%s"' % self.operation.soapaction} + headers = { + "SOAPAction": '"%s"' % self.operation.soapaction + if self.operation.soapaction + else '""' + } return SerializedMessage(path=None, headers=headers, content=envelope) def deserialize(self, envelope): From c87acd15418d452ace50dcaa18148fc73ce4f8ce Mon Sep 17 00:00:00 2001 From: Cristian Salamea Date: Sat, 14 Nov 2020 16:28:36 -0500 Subject: [PATCH 14/41] [ADD] support context manager on Client --- src/zeep/client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/zeep/client.py b/src/zeep/client.py index 56f9a61c..46b0c9da 100644 --- a/src/zeep/client.py +++ b/src/zeep/client.py @@ -214,6 +214,12 @@ def _get_service(self, name: typing.Optional[str]) -> str: service = next(iter(self.wsdl.services.values()), None) return service + def __enter__(self): + return self + + def __exit__(self, exc_type=None, exc_value=None, traceback=None): + self.transport.close() + class AsyncClient(Client): _default_transport = AsyncTransport From 08687518e638e082bf519de71b75e99e500efa17 Mon Sep 17 00:00:00 2001 From: Cristian Salamea Date: Sat, 14 Nov 2020 16:37:07 -0500 Subject: [PATCH 15/41] [ADD] test context manager client --- tests/test_client.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 3b26578b..a221e63b 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -52,6 +52,11 @@ def test_service_proxy_non_existing(): assert client_obj.service.NonExisting +def test_context_manager(): + with client.Client("tests/wsdl_files/soap.wsdl") as client: + assert client + + def test_service_proxy_dir_operations(): client_obj = client.Client("tests/wsdl_files/soap.wsdl") operations = [op for op in dir(client_obj.service) if not op.startswith("_")] From 2f5c1269186eb148988ce4bbe5132366ae5b7f9f Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 30 Sep 2022 15:58:31 +0100 Subject: [PATCH 16/41] Update mypy.ini --- mypy.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/mypy.ini b/mypy.ini index c58eae98..fdb1e742 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,5 +1,6 @@ [mypy] ignore_missing_imports = True +implicit_reexport = False python_version = 3.6 warn_unused_configs = True mypy_path = src From cc986db24c1a541348adbbe46c7d70dd8192ed24 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 30 Sep 2022 17:03:32 +0100 Subject: [PATCH 17/41] Fix type errors. --- examples/trafficvance_apikey.py | 2 +- mypy.ini | 2 +- src/zeep/__init__.py | 10 +++++----- src/zeep/client.py | 2 +- src/zeep/loader.py | 2 +- src/zeep/wsdl/__init__.py | 2 +- src/zeep/wsdl/attachments.py | 5 +++-- src/zeep/wsdl/bindings/__init__.py | 4 ++-- src/zeep/wsdl/definitions.py | 4 +++- src/zeep/wsdl/wsdl.py | 4 ++-- src/zeep/wsse/__init__.py | 6 +++--- src/zeep/xsd/__init__.py | 2 +- src/zeep/xsd/elements/indicators.py | 5 +++-- src/zeep/xsd/types/any.py | 8 +++++--- src/zeep/xsd/types/complex.py | 20 +++++++++++++------- tests/test_transports.py | 4 ++-- tests/test_wsse_signature.py | 20 ++++++++++++-------- 17 files changed, 59 insertions(+), 43 deletions(-) diff --git a/examples/trafficvance_apikey.py b/examples/trafficvance_apikey.py index 4f3e242d..c68894f3 100644 --- a/examples/trafficvance_apikey.py +++ b/examples/trafficvance_apikey.py @@ -3,7 +3,7 @@ API_KEY_TEST = 'YOUR_OWN_API_KEY' WSDL_TEST = 'https://apitest.trafficvance.com/?v3=system.wsdl' -client = Client(WSDL) +client = Client(WSDL_TEST) header = xsd.Element( '{WSDL_TEST}AuthenticateRequest', xsd.ComplexType([ diff --git a/mypy.ini b/mypy.ini index fdb1e742..acacfe51 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,9 +1,9 @@ [mypy] +files = src/, benchmark/, examples/, tests/ ignore_missing_imports = True implicit_reexport = False python_version = 3.6 warn_unused_configs = True mypy_path = src warn_unreachable = True -follow_imports = True follow_imports_for_stubs = True diff --git a/src/zeep/__init__.py b/src/zeep/__init__.py index eee2f6fb..40966416 100644 --- a/src/zeep/__init__.py +++ b/src/zeep/__init__.py @@ -1,7 +1,7 @@ -from zeep.client import AsyncClient, CachingClient, Client # noqa -from zeep.plugins import Plugin # noqa -from zeep.settings import Settings # noqa -from zeep.transports import Transport # noqa -from zeep.xsd.valueobjects import AnyObject # noqa +from zeep.client import AsyncClient as AsyncClient, CachingClient as CachingClient, Client as Client # noqa +from zeep.plugins import Plugin as Plugin # noqa +from zeep.settings import Settings as Settings # noqa +from zeep.transports import Transport as Transport # noqa +from zeep.xsd.valueobjects import AnyObject as AnyObject # noqa __version__ = "4.1.0" diff --git a/src/zeep/client.py b/src/zeep/client.py index 46b0c9da..ff2d8b50 100644 --- a/src/zeep/client.py +++ b/src/zeep/client.py @@ -51,7 +51,7 @@ class Client: """ - _default_transport = Transport + _default_transport = typing.Union[Transport, AsyncTransport] def __init__( self, diff --git a/src/zeep/loader.py b/src/zeep/loader.py index 9bf979ac..30a6ab4a 100644 --- a/src/zeep/loader.py +++ b/src/zeep/loader.py @@ -68,7 +68,7 @@ def parse_xml(content: str, transport, base_url=None, settings=None): ) -def load_external(url: typing.IO, transport, base_url=None, settings=None): +def load_external(url: typing.Union[typing.IO, str], transport, base_url=None, settings=None): """Load an external XML document. :param url: diff --git a/src/zeep/wsdl/__init__.py b/src/zeep/wsdl/__init__.py index f24188ef..eb2a8a2a 100644 --- a/src/zeep/wsdl/__init__.py +++ b/src/zeep/wsdl/__init__.py @@ -13,4 +13,4 @@ """ -from zeep.wsdl.wsdl import Document # noqa +from zeep.wsdl.wsdl import Document as Document # noqa diff --git a/src/zeep/wsdl/attachments.py b/src/zeep/wsdl/attachments.py index 075bee59..3e91df56 100644 --- a/src/zeep/wsdl/attachments.py +++ b/src/zeep/wsdl/attachments.py @@ -5,10 +5,11 @@ """ import base64 +import sys -try: +if sys.version_info >= (3, 8): from functools import cached_property -except ImportError: +else: from cached_property import cached_property from requests.structures import CaseInsensitiveDict diff --git a/src/zeep/wsdl/bindings/__init__.py b/src/zeep/wsdl/bindings/__init__.py index 38a6102b..c8ea74cd 100644 --- a/src/zeep/wsdl/bindings/__init__.py +++ b/src/zeep/wsdl/bindings/__init__.py @@ -1,2 +1,2 @@ -from .http import HttpGetBinding, HttpPostBinding # noqa -from .soap import Soap11Binding, Soap12Binding # noqa +from .http import HttpGetBinding as HttpGetBinding, HttpPostBinding as HttpPostBinding # noqa +from .soap import Soap11Binding as Soap11Binding, Soap12Binding as Soap12Binding # noqa diff --git a/src/zeep/wsdl/definitions.py b/src/zeep/wsdl/definitions.py index 3a4fe603..5ab8cd1b 100644 --- a/src/zeep/wsdl/definitions.py +++ b/src/zeep/wsdl/definitions.py @@ -25,6 +25,8 @@ if typing.TYPE_CHECKING: from zeep.wsdl.wsdl import Definition +else: + Definition = None MessagePart = namedtuple("MessagePart", ["element", "type"]) @@ -134,7 +136,7 @@ def __init__(self, wsdl, name, port_name): self.wsdl = wsdl self._operations = {} - def resolve(self, definitions: "Definition") -> None: + def resolve(self, definitions: Definition) -> None: self.port_type = definitions.get("port_types", self.port_name.text) for name, operation in list(self._operations.items()): diff --git a/src/zeep/wsdl/wsdl.py b/src/zeep/wsdl/wsdl.py index bb87664e..f842fa43 100644 --- a/src/zeep/wsdl/wsdl.py +++ b/src/zeep/wsdl/wsdl.py @@ -181,8 +181,8 @@ def __init__(self, wsdl, doc, location): self.types = wsdl.types self.port_types = {} self.messages = {} - self.bindings = {} # type: typing.Dict[str, typing.Type[Binding]] - self.services = OrderedDict() # type: typing.Dict[str, Service] + self.bindings: typing.Dict[str, Binding] = {} + self.services: typing.Dict[str, Service] = OrderedDict() self.imports = {} self._resolved_imports = False diff --git a/src/zeep/wsse/__init__.py b/src/zeep/wsse/__init__.py index eac48a1b..47f35cfa 100644 --- a/src/zeep/wsse/__init__.py +++ b/src/zeep/wsse/__init__.py @@ -1,3 +1,3 @@ -from .compose import Compose # noqa -from .signature import BinarySignature, MemorySignature, Signature # noqa -from .username import UsernameToken # noqa +from .compose import Compose as Compose # noqa +from .signature import BinarySignature as BinarySignature, MemorySignature as MemorySignature, Signature as Signature # noqa +from .username import UsernameToken as UsernameToken # noqa diff --git a/src/zeep/xsd/__init__.py b/src/zeep/xsd/__init__.py index dfe63583..140339c8 100644 --- a/src/zeep/xsd/__init__.py +++ b/src/zeep/xsd/__init__.py @@ -5,7 +5,7 @@ """ from zeep.xsd.const import Nil, SkipValue # noqa from zeep.xsd.elements import * # noqa -from zeep.xsd.schema import Schema # noqa +from zeep.xsd.schema import Schema as Schema # noqa from zeep.xsd.types import * # noqa from zeep.xsd.types.builtins import * # noqa from zeep.xsd.valueobjects import * # noqa diff --git a/src/zeep/xsd/elements/indicators.py b/src/zeep/xsd/elements/indicators.py index e9ef2c4d..f56814e6 100644 --- a/src/zeep/xsd/elements/indicators.py +++ b/src/zeep/xsd/elements/indicators.py @@ -13,12 +13,13 @@ """ import copy import operator +import sys import typing from collections import OrderedDict, defaultdict, deque -try: +if sys.version_info >= (3, 8): from functools import cached_property as threaded_cached_property -except ImportError: +else: from cached_property import threaded_cached_property from lxml import etree diff --git a/src/zeep/xsd/types/any.py b/src/zeep/xsd/types/any.py index 17f244e1..4b792fca 100644 --- a/src/zeep/xsd/types/any.py +++ b/src/zeep/xsd/types/any.py @@ -1,9 +1,10 @@ import logging +import sys import typing -try: +if sys.version_info >= (3, 8): from functools import cached_property as threaded_cached_property -except ImportError: +else: from cached_property import threaded_cached_property from lxml import etree @@ -11,6 +12,7 @@ from zeep.utils import qname_attr from zeep.xsd.const import xsd_ns, xsi_ns from zeep.xsd.context import XmlParserContext +from zeep.xsd.elements.base import Base from zeep.xsd.types.base import Type from zeep.xsd.valueobjects import AnyObject, CompoundValue @@ -25,7 +27,7 @@ class AnyType(Type): _default_qname = xsd_ns("anyType") - _element = None + _element: typing.Optional[Base] = None def __call__(self, value=None): return value or "" diff --git a/src/zeep/xsd/types/complex.py b/src/zeep/xsd/types/complex.py index b2ed9bf0..5c1167a1 100644 --- a/src/zeep/xsd/types/complex.py +++ b/src/zeep/xsd/types/complex.py @@ -1,12 +1,14 @@ import copy import logging +import sys import typing from collections import OrderedDict, deque from itertools import chain +from typing import Optional -try: +if sys.version_info >= (3, 8): from functools import cached_property as threaded_cached_property -except ImportError: +else: from cached_property import threaded_cached_property from lxml import etree @@ -32,10 +34,14 @@ if typing.TYPE_CHECKING: from zeep.xsd.schema import Schema from zeep.xsd.types.base import Type +else: + Schema = Type = None logger = logging.getLogger(__name__) __all__ = ["ComplexType"] +# Recursive alias +_ObjectList = typing.List[typing.Union[CompoundValue, None, _ObjectList]] class ComplexType(AnyType): @@ -166,10 +172,10 @@ def _array_type(self): def parse_xmlelement( self, xmlelement: etree._Element, - schema: "Schema" = None, + schema: Optional[Schema] = None, allow_none: bool = True, context: XmlParserContext = None, - schema_type: "Type" = None, + schema_type: Optional[Type] = None, ) -> typing.Optional[typing.Union[str, CompoundValue, typing.List[etree._Element]]]: """Consume matching xmlelements and call parse() on each @@ -217,7 +223,7 @@ def parse_xmlelement( # Check if all children are consumed (parsed) if elements: - if schema.settings.strict: + if schema and schema.settings.strict: raise XMLParseError("Unexpected element %r" % elements[0].tag) else: init_kwargs["_raw_elements"] = elements @@ -333,8 +339,8 @@ def parse_kwargs( return {} def _create_object( - self, value: typing.Union[list, dict, CompoundValue], name: str - ) -> typing.Optional[CompoundValue]: + self, value: typing.Union[list, dict, CompoundValue, None], name: str + ) -> typing.Union[CompoundValue, None, _ObjectList]: """Return the value as a CompoundValue object :type value: str diff --git a/tests/test_transports.py b/tests/test_transports.py index ead41243..2fc87013 100644 --- a/tests/test_transports.py +++ b/tests/test_transports.py @@ -32,7 +32,7 @@ def test_load(): @pytest.mark.skipif(os.name != "nt", reason="test valid for windows platform only") -def test_load_file(): +def test_load_file_windows(): cache = stub(get=lambda url: None, add=lambda url, content: None) transport = transports.Transport(cache=cache) with patch("io.open", mock_open(read_data=b"x")) as m_open: @@ -42,7 +42,7 @@ def test_load_file(): @pytest.mark.skipif(os.name == "nt", reason="test valid for unix platform only") -def test_load_file(): +def test_load_file_unix(): cache = stub(get=lambda url: None, add=lambda url, content: None) transport = transports.Transport(cache=cache) with patch("io.open", mock_open(read_data=b"x")) as m_open: diff --git a/tests/test_wsse_signature.py b/tests/test_wsse_signature.py index ae3c353f..208039c7 100644 --- a/tests/test_wsse_signature.py +++ b/tests/test_wsse_signature.py @@ -9,7 +9,11 @@ from zeep import ns, wsse from zeep.exceptions import SignatureVerificationFailed from zeep.wsse import signature -from zeep.wsse.signature import xmlsec as xmlsec_installed + +try: + import xmlsec +except ImportError: + xmlsec = None KEY_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "cert_valid.pem") KEY_FILE_PW = os.path.join( @@ -30,7 +34,7 @@ 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" + xmlsec is None, reason="xmlsec library not installed" ) @@ -77,8 +81,8 @@ def test_sign_timestamp_if_present( KEY_FILE, KEY_FILE, None, - signature_method=getattr(xmlsec_installed.Transform, signature_method), - digest_method=getattr(xmlsec_installed.Transform, digest_method), + signature_method=getattr(xmlsec.Transform, signature_method), + digest_method=getattr(xmlsec.Transform, digest_method), ) signature.verify_envelope(envelope, KEY_FILE) digests = envelope.xpath("//ds:DigestMethod", namespaces={"ds": ns.DS}) @@ -120,8 +124,8 @@ def test_sign( envelope, KEY_FILE, KEY_FILE, - signature_method=getattr(xmlsec_installed.Transform, signature_method), - digest_method=getattr(xmlsec_installed.Transform, digest_method), + signature_method=getattr(xmlsec.Transform, signature_method), + digest_method=getattr(xmlsec.Transform, digest_method), ) signature.verify_envelope(envelope, KEY_FILE) @@ -240,8 +244,8 @@ def test_signature_binary( KEY_FILE_PW, KEY_FILE_PW, "geheim", - signature_method=getattr(xmlsec_installed.Transform, signature_method), - digest_method=getattr(xmlsec_installed.Transform, digest_method), + signature_method=getattr(xmlsec.Transform, signature_method), + digest_method=getattr(xmlsec.Transform, digest_method), ) envelope, headers = plugin.apply(envelope, {}) plugin.verify(envelope) From bcf82d8e8a74b7b83d5862bcaef0844b41c4a87a Mon Sep 17 00:00:00 2001 From: Cristian Libotean Date: Fri, 5 Aug 2022 11:01:08 +0300 Subject: [PATCH 18/41] Allow Ws Addressing plugin to use a different URL address than the binding address. Some SOAP services require you to connect to a gateway server but specify your actual url in the addressing part. With this change you can override the binding address if you want to, but by default it will use the same address. --- src/zeep/wsa.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/zeep/wsa.py b/src/zeep/wsa.py index 3778bc31..7f49b79d 100644 --- a/src/zeep/wsa.py +++ b/src/zeep/wsa.py @@ -13,6 +13,9 @@ class WsAddressingPlugin(Plugin): nsmap = {"wsa": ns.WSA} + def __init__(self, address_url: str = None): + self.address_url = address_url + def egress(self, envelope, http_headers, operation, binding_options): """Apply the ws-addressing headers to the given envelope.""" @@ -24,7 +27,7 @@ def egress(self, envelope, http_headers, operation, binding_options): headers = [ WSA.Action(wsa_action), WSA.MessageID("urn:uuid:" + str(uuid.uuid4())), - WSA.To(binding_options["address"]), + WSA.To(self.address_url or binding_options["address"]), ] header.extend(headers) From c4c6368996305b1a19aa42d8d4db5db3d3b1af42 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 07:45:32 +0100 Subject: [PATCH 19/41] Remove explicit unicode strings like `u""` No longer required --- src/zeep/cache.py | 2 +- src/zeep/wsdl/bindings/soap.py | 2 +- src/zeep/wsdl/definitions.py | 10 +++++----- tests/test_helpers.py | 2 +- tests/test_loader.py | 8 ++++---- tests/test_soap_multiref.py | 4 ++-- tests/test_wsdl.py | 2 +- tests/test_xsd_types.py | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/zeep/cache.py b/src/zeep/cache.py index e484cdc9..4b7b90e7 100644 --- a/src/zeep/cache.py +++ b/src/zeep/cache.py @@ -60,7 +60,7 @@ def _version_string(self): assert ( getattr(self, "_version", None) is not None ), "A version must be provided in order to use the VersionedCacheBase backend." - prefix = u"$ZEEP:%s$" % self._version + prefix = "$ZEEP:%s$" % self._version return bytes(prefix.encode("ascii")) diff --git a/src/zeep/wsdl/bindings/soap.py b/src/zeep/wsdl/bindings/soap.py index 81b70b09..3a5e5433 100644 --- a/src/zeep/wsdl/bindings/soap.py +++ b/src/zeep/wsdl/bindings/soap.py @@ -179,7 +179,7 @@ def process_reply(self, client, operation, response): elif response.status_code != 200 and not response.content: raise TransportError( - u"Server returned HTTP status %d (no content available)" + "Server returned HTTP status %d (no content available)" % response.status_code, status_code=response.status_code, ) diff --git a/src/zeep/wsdl/definitions.py b/src/zeep/wsdl/definitions.py index 5ab8cd1b..deb33ea9 100644 --- a/src/zeep/wsdl/definitions.py +++ b/src/zeep/wsdl/definitions.py @@ -212,11 +212,11 @@ def __repr__(self): def __str__(self): if not self.input: - return u"%s(missing input message)" % (self.name) + return "%s(missing input message)" % (self.name) - retval = u"%s(%s)" % (self.name, self.input.signature()) + retval = "%s(%s)" % (self.name, self.input.signature()) if self.output: - retval += u" -> %s" % (self.output.signature(as_output=True)) + retval += " -> %s" % (self.output.signature(as_output=True)) return retval def create(self, *args, **kwargs): @@ -275,7 +275,7 @@ def __repr__(self): ) def __str__(self): - return u"Port: %s (%s)" % (self.name, self.binding) + return "Port: %s (%s)" % (self.name, self.binding) def resolve(self, definitions): if self._resolve_context is None: @@ -309,7 +309,7 @@ def __init__(self, name): self._is_resolved = False def __str__(self): - return u"Service: %s" % self.name + return "Service: %s" % self.name def __repr__(self): return "<%s(name=%r, ports=%r)>" % ( diff --git a/tests/test_helpers.py b/tests/test_helpers.py index d83f5238..5c22f83e 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -167,7 +167,7 @@ def test_serialize_any_array(): def test_create_xml_soap_map(): data = OrderedDict( [ - ("text", u"String"), + ("text", "String"), ("bytes", b"Bytes"), ("boolean", True), ("integer", 100), diff --git a/tests/test_loader.py b/tests/test_loader.py index c50d8d0e..16548320 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -11,23 +11,23 @@ def test_huge_text(): # libxml2>=2.7.3 has XML_MAX_TEXT_LENGTH 10000000 without XML_PARSE_HUGE settings = Settings(xml_huge_tree=True) tree = parse_xml( - u""" + """ %s """ - % (u"\u00e5" * 10000001), + % ("\u00e5" * 10000001), DummyTransport(), settings=settings, ) - assert tree[0][0].text == u"\u00e5" * 10000001 + assert tree[0][0].text == "\u00e5" * 10000001 def test_allow_entities_and_dtd(): - xml = u""" + xml = """ ]> diff --git a/tests/test_soap_multiref.py b/tests/test_soap_multiref.py index ddbf8412..375ddcc1 100644 --- a/tests/test_soap_multiref.py +++ b/tests/test_soap_multiref.py @@ -10,7 +10,7 @@ @pytest.mark.requests def test_parse_multiref_soap_response(): wsdl_file = io.StringIO( - u""" + """ ]> Date: Thu, 3 Nov 2022 08:06:19 +0100 Subject: [PATCH 20/41] Fix failing test case (unbound variable client) --- tests/test_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index a221e63b..64bf350a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -53,8 +53,8 @@ def test_service_proxy_non_existing(): def test_context_manager(): - with client.Client("tests/wsdl_files/soap.wsdl") as client: - assert client + with client.Client("tests/wsdl_files/soap.wsdl") as c: + assert c def test_service_proxy_dir_operations(): From d734a63c696ed18d0396d4b36b6adc206aa72490 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:09:36 +0100 Subject: [PATCH 21/41] Remove support for Python 3.6, add 3.11 --- .github/workflows/python-test.yml | 5 +---- README.rst | 2 +- docs/index.rst | 6 +++--- mypy.ini | 2 +- setup.py | 4 ++-- tox.ini | 12 ++++++------ 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 6ee31cbc..428e60b5 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -24,10 +24,7 @@ jobs: max-parallel: 4 matrix: platform: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] - # TODO: Remove Windows exclusion when binary wheel available for lxml - exclude: - - { platform: windows-latest, python-version: "3.10" } + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] steps: - name: Install system dependencies diff --git a/README.rst b/README.rst index 6a05eca4..da27ca3b 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Zeep: Python SOAP client A fast and modern Python SOAP client Highlights: - * Compatible with Python 3.6, 3.7, 3.8, 3.9, 3.10 and PyPy3 + * Compatible with Python 3.7, 3.8, 3.9, 3.10, 3.11 and PyPy3 * Build on top of lxml and requests * Support for Soap 1.1, Soap 1.2 and HTTP bindings * Support for WS-Addressing headers diff --git a/docs/index.rst b/docs/index.rst index b32949c9..a2a81279 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,7 +5,7 @@ Zeep: Python SOAP client A fast and modern Python SOAP client Highlights: - * Compatible with Python 3.6, 3.7, 3.8 and PyPy + * Compatible with Python 3.7, 3.8, 3.9, 3.10, 3.11 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 @@ -70,8 +70,8 @@ If you have installed pip then run:: pip install zeep -Note that the latest version to support Python 2.7, 3.3, 3.4 and 3.5 is Zeep 3.4, -install via `pip install zeep==3.4.0` +Note that the latest version to support Python 2.7, 3.3, 3.4 and 3.5 is Zeep 3.4, +install via `pip install zeep==2.4.0` This assumes that there are wheel files available for the latest lxml release. If that is not the case (https://pypi.python.org/pypi/lxml/) then first diff --git a/mypy.ini b/mypy.ini index acacfe51..12877919 100644 --- a/mypy.ini +++ b/mypy.ini @@ -2,7 +2,7 @@ files = src/, benchmark/, examples/, tests/ ignore_missing_imports = True implicit_reexport = False -python_version = 3.6 +python_version = 3.7 warn_unused_configs = True mypy_path = src warn_unreachable = True diff --git a/setup.py b/setup.py index 96b428e8..7984ecc8 100755 --- a/setup.py +++ b/setup.py @@ -58,7 +58,7 @@ project_urls={ "Source": "https://github.com/mvantellingen/python-zeep", }, - python_requires=">=3.6", + python_requires=">=3.7", install_requires=install_requires, tests_require=tests_require, extras_require={ @@ -77,11 +77,11 @@ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ], diff --git a/tox.ini b/tox.ini index f6d1331e..861f3489 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,13 @@ [tox] -envlist = py{36,37,38,39,310}-{mac,linux,windows},pypy +envlist = py{37,38,39,310,311}-{mac,linux,windows},pypy [gh-actions] python = - 3.6: py36 3.7: py37 3.8: py38 3.9: py39 3.10: py310 + 3.11: py311 [testenv] @@ -18,11 +18,11 @@ platform = extras = test {mac,linux}: xmlsec - py{36,37,38,39,310}: async + py{37,38,39,310,311}: async deps = - py{36,37,38,39,310}: aioresponses==0.5.0 - py{36,37,38,39,310}: aiohttp==3.7.4 - py{36,37,38,39,310}: pytest-asyncio==0.11.0 + py{37,38,39,310,311}: aioresponses==0.5.0 + py{37,38,39,310,311}: aiohttp==3.7.4 + py{37,38,39,310,311}: pytest-asyncio==0.11.0 commands = coverage run --parallel -m pytest {posargs} From ef99ecf9a61e968abbcf5970ebcab9686b794236 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:09:48 +0100 Subject: [PATCH 22/41] Add env/ to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b0aa1724..7c94d732 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +env/ *.egg-info *.pyc __pycache__ From 4388dddbc9eba203ac4a9dc40c8692fac4ecfdda Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:10:12 +0100 Subject: [PATCH 23/41] Fix invalid type definition --- src/zeep/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zeep/client.py b/src/zeep/client.py index ff2d8b50..450101f2 100644 --- a/src/zeep/client.py +++ b/src/zeep/client.py @@ -51,7 +51,7 @@ class Client: """ - _default_transport = typing.Union[Transport, AsyncTransport] + _default_transport: typing.Union[Transport, AsyncTransport] = Transport def __init__( self, From 570c62364479f7de015e01c07e227880f32b401a Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:10:29 +0100 Subject: [PATCH 24/41] Fix the __exit__ clause Not the best fix, but it works --- src/zeep/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zeep/client.py b/src/zeep/client.py index 450101f2..fac7ecd7 100644 --- a/src/zeep/client.py +++ b/src/zeep/client.py @@ -218,7 +218,8 @@ def __enter__(self): return self def __exit__(self, exc_type=None, exc_value=None, traceback=None): - self.transport.close() + if hasattr(self.transport, "close"): + self.transport.close() class AsyncClient(Client): From a31583a544a8e74279a0b357617895bef49e9c61 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:10:42 +0100 Subject: [PATCH 25/41] Formatting --- src/zeep/__init__.py | 19 ++++++++++++++----- src/zeep/loader.py | 4 +++- src/zeep/wsdl/__init__.py | 4 +++- src/zeep/wsdl/bindings/__init__.py | 6 ++++-- src/zeep/wsse/__init__.py | 14 +++++++++++--- src/zeep/xsd/__init__.py | 4 ++-- src/zeep/xsd/types/complex.py | 4 +++- src/zeep/xsd/utils.py | 2 +- tests/test_client.py | 4 ++-- tests/test_wsse_signature.py | 4 +--- 10 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/zeep/__init__.py b/src/zeep/__init__.py index 40966416..9e8e52db 100644 --- a/src/zeep/__init__.py +++ b/src/zeep/__init__.py @@ -1,7 +1,16 @@ -from zeep.client import AsyncClient as AsyncClient, CachingClient as CachingClient, Client as Client # noqa -from zeep.plugins import Plugin as Plugin # noqa -from zeep.settings import Settings as Settings # noqa -from zeep.transports import Transport as Transport # noqa -from zeep.xsd.valueobjects import AnyObject as AnyObject # noqa +from zeep.client import AsyncClient, CachingClient, Client +from zeep.plugins import Plugin +from zeep.settings import Settings +from zeep.transports import Transport +from zeep.xsd.valueobjects import AnyObject __version__ = "4.1.0" +__all__ = [ + "AsyncClient", + "CachingClient", + "Client", + "Plugin", + "Settings", + "Transport", + "AnyObject", +] diff --git a/src/zeep/loader.py b/src/zeep/loader.py index 30a6ab4a..7814d6ab 100644 --- a/src/zeep/loader.py +++ b/src/zeep/loader.py @@ -68,7 +68,9 @@ def parse_xml(content: str, transport, base_url=None, settings=None): ) -def load_external(url: typing.Union[typing.IO, str], transport, base_url=None, settings=None): +def load_external( + url: typing.Union[typing.IO, str], transport, base_url=None, settings=None +): """Load an external XML document. :param url: diff --git a/src/zeep/wsdl/__init__.py b/src/zeep/wsdl/__init__.py index eb2a8a2a..8b7d052c 100644 --- a/src/zeep/wsdl/__init__.py +++ b/src/zeep/wsdl/__init__.py @@ -13,4 +13,6 @@ """ -from zeep.wsdl.wsdl import Document as Document # noqa +from zeep.wsdl.wsdl import Document + +__all__ = ["Document"] diff --git a/src/zeep/wsdl/bindings/__init__.py b/src/zeep/wsdl/bindings/__init__.py index c8ea74cd..20867aae 100644 --- a/src/zeep/wsdl/bindings/__init__.py +++ b/src/zeep/wsdl/bindings/__init__.py @@ -1,2 +1,4 @@ -from .http import HttpGetBinding as HttpGetBinding, HttpPostBinding as HttpPostBinding # noqa -from .soap import Soap11Binding as Soap11Binding, Soap12Binding as Soap12Binding # noqa +from .http import HttpGetBinding, HttpPostBinding +from .soap import Soap11Binding, Soap12Binding + +__all__ = ["HttpGetBinding", "HttpPostBinding", "Soap11Binding", "Soap12Binding"] diff --git a/src/zeep/wsse/__init__.py b/src/zeep/wsse/__init__.py index 47f35cfa..5df2c78d 100644 --- a/src/zeep/wsse/__init__.py +++ b/src/zeep/wsse/__init__.py @@ -1,3 +1,11 @@ -from .compose import Compose as Compose # noqa -from .signature import BinarySignature as BinarySignature, MemorySignature as MemorySignature, Signature as Signature # noqa -from .username import UsernameToken as UsernameToken # noqa +from .compose import Compose +from .signature import BinarySignature, MemorySignature, Signature +from .username import UsernameToken + +__all__ = [ + "Compose", + "BinarySignature", + "MemorySignature", + "Signature", + "UsernameToken", +] diff --git a/src/zeep/xsd/__init__.py b/src/zeep/xsd/__init__.py index 140339c8..45a29397 100644 --- a/src/zeep/xsd/__init__.py +++ b/src/zeep/xsd/__init__.py @@ -3,9 +3,9 @@ -------- """ -from zeep.xsd.const import Nil, SkipValue # noqa +from zeep.xsd.const import Nil, SkipValue from zeep.xsd.elements import * # noqa -from zeep.xsd.schema import Schema as Schema # noqa +from zeep.xsd.schema import Schema as Schema from zeep.xsd.types import * # noqa from zeep.xsd.types.builtins import * # noqa from zeep.xsd.valueobjects import * # noqa diff --git a/src/zeep/xsd/types/complex.py b/src/zeep/xsd/types/complex.py index 5c1167a1..9208e1a7 100644 --- a/src/zeep/xsd/types/complex.py +++ b/src/zeep/xsd/types/complex.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import copy import logging import sys @@ -41,7 +43,7 @@ __all__ = ["ComplexType"] # Recursive alias -_ObjectList = typing.List[typing.Union[CompoundValue, None, _ObjectList]] +_ObjectList = typing.List[typing.Union[CompoundValue, None, "_ObjectList"]] class ComplexType(AnyType): diff --git a/src/zeep/xsd/utils.py b/src/zeep/xsd/utils.py index 369343b9..7fe3ca22 100644 --- a/src/zeep/xsd/utils.py +++ b/src/zeep/xsd/utils.py @@ -27,7 +27,7 @@ def create_name(self, name): def max_occurs_iter(max_occurs, items=None): assert max_occurs is not None - generator = range(0, max_occurs if max_occurs != "unbounded" else 2 ** 31 - 1) + generator = range(0, max_occurs if max_occurs != "unbounded" else 2**31 - 1) if items is not None: for i, sub_kwargs in zip(generator, items): diff --git a/tests/test_client.py b/tests/test_client.py index 64bf350a..af13d9b9 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -5,9 +5,9 @@ from tests.utils import load_xml from zeep import client, xsd -from zeep.wsdl import Document -from zeep.transports import Transport from zeep.exceptions import Error +from zeep.transports import Transport +from zeep.wsdl import Document def test_bind(): diff --git a/tests/test_wsse_signature.py b/tests/test_wsse_signature.py index 208039c7..487b8354 100644 --- a/tests/test_wsse_signature.py +++ b/tests/test_wsse_signature.py @@ -33,9 +33,7 @@ skip_if_no_xmlsec = pytest.mark.skipif( sys.platform == "win32", reason="does not run on windows" -) and pytest.mark.skipif( - xmlsec is None, reason="xmlsec library not installed" -) +) and pytest.mark.skipif(xmlsec is None, reason="xmlsec library not installed") @skip_if_no_xmlsec From 33e692f1cc07fee39a695c6cf8fe466ef04437eb Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:10:47 +0100 Subject: [PATCH 26/41] Update changelog --- CHANGES | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGES b/CHANGES index 37d54d59..85c4065f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +4.2.0 (2022-111-03) +------------------- + - Drop support for Python 3.6 + - Allow embedding CDATA elements in simple types (#1339) + - Allow to pass in a pre parsed Document (#1330) + - Fix httpx DeprecationWarning for post data (#1326) + - Add BinaryMemorySignature (#1300) + - Fix IndexError when empty body response (#1287) + - Add support for context manager on Client (#1166) + - Allow Ws Addressing plugin to use a different URL (#1328) + + 4.1.0 (2021-08-15) ------------------ - Remove last dependency on `six` (#1250) From 50e927948d5855f6f67a51771107d066f702e91e Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:15:46 +0100 Subject: [PATCH 27/41] Update README.rst --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index da27ca3b..d8a52b7f 100644 --- a/README.rst +++ b/README.rst @@ -23,6 +23,10 @@ http://docs.python-zeep.org/ Status ------ + +**I consider this library to be stable. Since no new developments happen around the SOAP specification it won't be updated that much. Good PR's which fix bugs are always welcome however.** + + .. image:: https://readthedocs.org/projects/python-zeep/badge/?version=latest :target: https://readthedocs.org/projects/python-zeep/ From df0ce40d3cff6a6958588177fcf8f815af6d14e4 Mon Sep 17 00:00:00 2001 From: "albert.zecheru" Date: Fri, 3 Apr 2020 19:51:15 +0200 Subject: [PATCH 28/41] Added return of value for accepted string type for xsd:base64Binary. --- src/zeep/xsd/types/builtins.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zeep/xsd/types/builtins.py b/src/zeep/xsd/types/builtins.py index d57068ee..6307493f 100644 --- a/src/zeep/xsd/types/builtins.py +++ b/src/zeep/xsd/types/builtins.py @@ -372,6 +372,8 @@ class Base64Binary(BuiltinType): @check_no_collection def xmlvalue(self, value): + if isinstance(value, six.string_types): + return value return base64.b64encode(value) def pythonvalue(self, value): From 5a0627669bf066d4cd8a853d0113e050579832a2 Mon Sep 17 00:00:00 2001 From: "albert.zecheru" Date: Fri, 3 Apr 2020 20:04:16 +0200 Subject: [PATCH 29/41] Added assert for accepted string type for xsd:base64Binary. --- tests/test_xsd_builtins.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_xsd_builtins.py b/tests/test_xsd_builtins.py index 9d76dea5..635cdaa9 100644 --- a/tests/test_xsd_builtins.py +++ b/tests/test_xsd_builtins.py @@ -380,6 +380,10 @@ class TestBase64Binary: def test_xmlvalue(self): instance = builtins.Base64Binary() assert instance.xmlvalue(b"hoi") == b"aG9p" + assert ( + instance.xmlvalue("aG9p") + == "aG9p" + ) def test_pythonvalue(self): instance = builtins.Base64Binary() From ea2e1667148b3bbf73f482ec496ccd960a5df32f Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:26:11 +0100 Subject: [PATCH 30/41] remove six reference --- src/zeep/xsd/types/builtins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zeep/xsd/types/builtins.py b/src/zeep/xsd/types/builtins.py index 6307493f..18b9a66f 100644 --- a/src/zeep/xsd/types/builtins.py +++ b/src/zeep/xsd/types/builtins.py @@ -372,7 +372,7 @@ class Base64Binary(BuiltinType): @check_no_collection def xmlvalue(self, value): - if isinstance(value, six.string_types): + if isinstance(value, str): return value return base64.b64encode(value) From 703c975f672129f703489eeb7f5ef693fa75e588 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:26:30 +0100 Subject: [PATCH 31/41] Update --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 85c4065f..291850b9 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,7 @@ - Fix IndexError when empty body response (#1287) - Add support for context manager on Client (#1166) - Allow Ws Addressing plugin to use a different URL (#1328) + - Accept strings for xsd base64Binary (#1072) 4.1.0 (2021-08-15) From ec71c4986a2b6867063f4e086162164baa5b4caa Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 08:27:45 +0100 Subject: [PATCH 32/41] =?UTF-8?q?Bump=20version:=204.1.0=20=E2=86=92=204.2?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- docs/conf.py | 2 +- docs/index.rst | 2 +- setup.py | 2 +- src/zeep/__init__.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c107a201..bb87933d 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 4.1.0 +current_version = 4.2.0 commit = true tag = true tag_name = {new_version} diff --git a/docs/conf.py b/docs/conf.py index f006c1af..e3eac58f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -62,7 +62,7 @@ # built documents. # # The short X.Y version. -version = '4.1.0' +version = '4.2.0' release = version # The language for content autogenerated by Sphinx. Refer to documentation diff --git a/docs/index.rst b/docs/index.rst index a2a81279..80047f2f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -106,7 +106,7 @@ See ``python -mzeep --help`` for more information about this command. .. note:: Zeep follows `semver`_ for versioning, however bugs can always occur. So as always pin the version of zeep you tested with - (e.g. ``zeep==4.1.0``'). + (e.g. ``zeep==4.2.0``'). .. _semver: http://semver.org/ diff --git a/setup.py b/setup.py index 7984ecc8..07136d74 100755 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ setup( name="zeep", - version="4.1.0", + version="4.2.0", description="A modern/fast Python SOAP client based on lxml / requests", long_description=long_description, author="Michael van Tellingen", diff --git a/src/zeep/__init__.py b/src/zeep/__init__.py index 9e8e52db..4083a2c9 100644 --- a/src/zeep/__init__.py +++ b/src/zeep/__init__.py @@ -4,7 +4,7 @@ from zeep.transports import Transport from zeep.xsd.valueobjects import AnyObject -__version__ = "4.1.0" +__version__ = "4.2.0" __all__ = [ "AsyncClient", "CachingClient", From 790151c4f3f7fd3fafbd5a8b547a56fef2a6305b Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 09:09:53 +0100 Subject: [PATCH 33/41] Fix testcase for windows / python 3.11 --- .github/workflows/python-test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 428e60b5..becd264d 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -25,6 +25,10 @@ jobs: matrix: platform: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + # TODO: Remove Windows exclusion when binary wheel available for lxml + exclude: + - { platform: windows-latest, python-version: "3.11" } + steps: - name: Install system dependencies From 84513a7ac0d61c7621d82cd03ffaa0572574091c Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 3 Nov 2022 09:10:10 +0100 Subject: [PATCH 34/41] fix formatting --- tests/test_xsd_builtins.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_xsd_builtins.py b/tests/test_xsd_builtins.py index 635cdaa9..1b001b1c 100644 --- a/tests/test_xsd_builtins.py +++ b/tests/test_xsd_builtins.py @@ -380,10 +380,7 @@ class TestBase64Binary: def test_xmlvalue(self): instance = builtins.Base64Binary() assert instance.xmlvalue(b"hoi") == b"aG9p" - assert ( - instance.xmlvalue("aG9p") - == "aG9p" - ) + assert instance.xmlvalue("aG9p") == "aG9p" def test_pythonvalue(self): instance = builtins.Base64Binary() From 09019c8807f4b34160e9287a7725e783e2cf677c Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Sat, 5 Nov 2022 20:24:37 +0100 Subject: [PATCH 35/41] Remove reference to modern/fast It's 6 years old already, how long can it stay modern ;-) --- README.rst | 10 ++++++---- docs/_templates/sidebar-intro.html | 2 +- docs/index.rst | 2 +- setup.py | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index d8a52b7f..875fb8e5 100644 --- a/README.rst +++ b/README.rst @@ -2,11 +2,11 @@ Zeep: Python SOAP client ======================== -A fast and modern Python SOAP client +A Python SOAP client Highlights: * Compatible with Python 3.7, 3.8, 3.9, 3.10, 3.11 and PyPy3 - * Build on top of lxml and requests + * Build on top of lxml, requests and httpx * Support for Soap 1.1, Soap 1.2 and HTTP bindings * Support for WS-Addressing headers * Support for WSSE (UserNameToken / x.509 signing) @@ -48,9 +48,11 @@ Installation pip install zeep -Note that the latest version to support Python 2.7, 3.3, 3.4 and 3.5 is Zeep 3.4, install via `pip install zeep==3.4.0` +Note that the latest version to support Python 2.7, 3.3, 3.4 and 3.5 is Zeep +3.4, install via `pip install zeep==3.4.0` -Zeep uses the lxml library for parsing xml. See https://lxml.de/installation.html for the installation requirements. +Zeep uses the lxml library for parsing xml. See +https://lxml.de/installation.html for the installation requirements. Usage ----- diff --git a/docs/_templates/sidebar-intro.html b/docs/_templates/sidebar-intro.html index af3fb9ea..db7b6ef8 100644 --- a/docs/_templates/sidebar-intro.html +++ b/docs/_templates/sidebar-intro.html @@ -3,7 +3,7 @@ -

Zeep is a modern SOAP client for Python

+

Zeep is a SOAP client for Python

diff --git a/docs/index.rst b/docs/index.rst index 80047f2f..f8c9393e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ Zeep: Python SOAP client ======================== -A fast and modern Python SOAP client +A Python SOAP client Highlights: * Compatible with Python 3.7, 3.8, 3.9, 3.10, 3.11 and PyPy diff --git a/setup.py b/setup.py index 07136d74..0ac49561 100755 --- a/setup.py +++ b/setup.py @@ -50,7 +50,7 @@ setup( name="zeep", version="4.2.0", - description="A modern/fast Python SOAP client based on lxml / requests", + description="A Python SOAP client", long_description=long_description, author="Michael van Tellingen", author_email="michaelvantellingen@gmail.com", From 7d22412558c0b29ceb1561bbc632082bd1214ba6 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Thu, 10 Nov 2022 09:18:44 +0100 Subject: [PATCH 36/41] Fix error when closing session in transport destructor Fixes #1347 --- CHANGES | 6 +++++- src/zeep/transports.py | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 291850b9..8a6053b3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,8 @@ -4.2.0 (2022-111-03) +4.2.1 (2022-11-10) +------------------- + - Fix error regarding closing session in async transport (#1347) + +4.2.0 (2022-11-03) ------------------- - Drop support for Python 3.6 - Allow embedding CDATA elements in simple types (#1339) diff --git a/src/zeep/transports.py b/src/zeep/transports.py index ffde356b..8e6970d2 100644 --- a/src/zeep/transports.py +++ b/src/zeep/transports.py @@ -37,7 +37,7 @@ def __init__(self, cache=None, timeout=300, operation_timeout=None, session=None self.operation_timeout = operation_timeout self.logger = logging.getLogger(__name__) - self.__close_session = not session + self._close_session = not session self.session = session or requests.Session() self.session.mount("file://", FileAdapter()) self.session.headers["User-Agent"] = "Zeep/%s (www.python-zeep.org)" % ( @@ -156,7 +156,7 @@ def settings(self, timeout=None): self.operation_timeout = old_timeout def __del__(self): - if self.__close_session: + if self._close_session: self.session.close() @@ -181,6 +181,7 @@ def __init__( if httpx is None: raise RuntimeError("The AsyncTransport is based on the httpx module") + self._close_session = False self.cache = cache self.wsdl_client = wsdl_client or httpx.Client( verify=verify_ssl, From 4e5ebad9eb355281cf3ae73cf83f666dc4b8bb00 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Sun, 20 Nov 2022 21:31:55 +0100 Subject: [PATCH 37/41] =?UTF-8?q?Bump=20version:=204.2.0=20=E2=86=92=204.2?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- docs/conf.py | 2 +- docs/index.rst | 2 +- setup.py | 2 +- src/zeep/__init__.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index bb87933d..34d91208 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 4.2.0 +current_version = 4.2.1 commit = true tag = true tag_name = {new_version} diff --git a/docs/conf.py b/docs/conf.py index e3eac58f..f146b9f8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -62,7 +62,7 @@ # built documents. # # The short X.Y version. -version = '4.2.0' +version = '4.2.1' release = version # The language for content autogenerated by Sphinx. Refer to documentation diff --git a/docs/index.rst b/docs/index.rst index f8c9393e..fe2382e6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -106,7 +106,7 @@ See ``python -mzeep --help`` for more information about this command. .. note:: Zeep follows `semver`_ for versioning, however bugs can always occur. So as always pin the version of zeep you tested with - (e.g. ``zeep==4.2.0``'). + (e.g. ``zeep==4.2.1``'). .. _semver: http://semver.org/ diff --git a/setup.py b/setup.py index 0ac49561..9b81ae59 100755 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ setup( name="zeep", - version="4.2.0", + version="4.2.1", description="A Python SOAP client", long_description=long_description, author="Michael van Tellingen", diff --git a/src/zeep/__init__.py b/src/zeep/__init__.py index 4083a2c9..f5b88ab8 100644 --- a/src/zeep/__init__.py +++ b/src/zeep/__init__.py @@ -4,7 +4,7 @@ from zeep.transports import Transport from zeep.xsd.valueobjects import AnyObject -__version__ = "4.2.0" +__version__ = "4.2.1" __all__ = [ "AsyncClient", "CachingClient", From 55478012253f59db1c71c9f99bf3696ba274db93 Mon Sep 17 00:00:00 2001 From: Michael van Tellingen Date: Fri, 3 Mar 2023 15:30:25 +0100 Subject: [PATCH 38/41] Create .github/FUNDING.yml --- .github/FUNDING.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..0d1007cf --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: [mvantellingen] From d0d737adbcd68213b940a5cc4f1da6cd43dfca81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20=C5=A0ulcs?= Date: Mon, 6 Mar 2023 12:34:31 +0200 Subject: [PATCH 39/41] Get rid of deprecated cgi module. Uses email module as suggested in docs: https://docs.python.org/3/library/cgi.html#cgi.parse_header Fixes #1352 --- src/zeep/utils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/zeep/utils.py b/src/zeep/utils.py index 2118253e..e08cdcd0 100644 --- a/src/zeep/utils.py +++ b/src/zeep/utils.py @@ -1,4 +1,4 @@ -import cgi +from email.message import Message import inspect import typing @@ -90,5 +90,8 @@ def detect_soap_env(envelope): 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.lower() + msg = Message() + msg['content-type'] = value + + return msg.get_content_type() + From 377d9313b1b4807a31a5ee42227f1dc7e7e0471e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Holstebroe?= Date: Sun, 20 Nov 2022 21:36:57 +0100 Subject: [PATCH 40/41] Fix to deserializer if result type does not have a length An exception will be thrown if a bool is returned from a SOAP service call. `deserialize` soap.py will ask for the length of the result body, but it may not be allowed to take len on some result body types. Added check if length is valid and returns the body directly if it is not. I haven't tested with any other types, such as integers. --- src/zeep/wsdl/messages/soap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zeep/wsdl/messages/soap.py b/src/zeep/wsdl/messages/soap.py index 6685a6fa..30e04e1b 100644 --- a/src/zeep/wsdl/messages/soap.py +++ b/src/zeep/wsdl/messages/soap.py @@ -116,6 +116,8 @@ def deserialize(self, envelope): return result result = result.body + if not hasattr(result, '__len__'): # Return body directly if len is allowed (could indicated valid primitive type). + return result if result is None or len(result) == 0: return None elif len(result) > 1: From e310879dce5e1e3300a975f1f68c2094ac9dc648 Mon Sep 17 00:00:00 2001 From: u243606 Date: Thu, 20 Apr 2023 16:11:07 +0530 Subject: [PATCH 41/41] Patch(visitor): copy min occurs and max occurs of parent element to child element --- src/zeep/xsd/visitor.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/zeep/xsd/visitor.py b/src/zeep/xsd/visitor.py index c7b1fb93..d471f6f5 100644 --- a/src/zeep/xsd/visitor.py +++ b/src/zeep/xsd/visitor.py @@ -68,7 +68,7 @@ def register_element(self, qname: etree.QName, instance: xsd_elements.Element): self.document.register_element(qname, instance) def register_attribute( - self, name: etree.QName, instance: xsd_elements.Attribute + self, name: etree.QName, instance: xsd_elements.Attribute ) -> None: self.document.register_attribute(name, instance) @@ -79,7 +79,7 @@ def register_group(self, qname: etree.QName, instance: xsd_elements.Group): self.document.register_group(qname, instance) def register_attribute_group( - self, qname: etree.QName, instance: xsd_elements.AttributeGroup + self, qname: etree.QName, instance: xsd_elements.AttributeGroup ) -> None: self.document.register_attribute_group(qname, instance) @@ -302,7 +302,7 @@ def visit_include(self, node, parent): # If included schema doesn't have default ns, then it should be set to parent's targetNs. # See Chameleon Inclusion https://www.w3.org/TR/xmlschema11-1/#chameleon-xslt if not schema_node.nsmap.get(None) and ( - node.nsmap.get(None) or parent.attrib.get("targetNamespace") + node.nsmap.get(None) or parent.attrib.get("targetNamespace") ): nsmap = {None: node.nsmap.get(None) or parent.attrib["targetNamespace"]} nsmap.update(schema_node.nsmap) @@ -436,7 +436,7 @@ def visit_element(self, node, parent): return element def visit_attribute( - self, node: etree._Element, parent: etree._Element + self, node: etree._Element, parent: etree._Element ) -> typing.Union[xsd_elements.Attribute, xsd_elements.RefAttribute]: """Declares an attribute. @@ -925,7 +925,11 @@ def visit_sequence(self, node, parent): raise self._create_error( "Unexpected element %s in xsd:sequence" % child.tag, child ) - + if node.attrib: + if "minOccurs" in node.attrib: + child.set("minOccurs", node.attrib["minOccurs"]) + if "maxOccurs" in node.attrib: + child.set("maxOccurs", node.attrib["maxOccurs"]) item = self.process(child, node) assert item is not None result.append(item) @@ -1217,7 +1221,7 @@ def _create_qname(self, name): # that fact and handle it by auto-importing the schema if it is # referenced. if name.namespace in AUTO_IMPORT_NAMESPACES and not self.document.is_imported( - name.namespace + name.namespace ): logger.debug("Auto importing missing known schema: %s", name.namespace) import_node = etree.Element( @@ -1226,10 +1230,10 @@ def _create_qname(self, name): 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 + 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