From b55a6ad300c4fc04770f4c9489233c19fcccfccf Mon Sep 17 00:00:00 2001 From: Curtis Date: Tue, 1 Sep 2015 15:47:04 +1000 Subject: [PATCH 1/5] Add cached_property to simplify code --- rinse/client.py | 15 +++------------ rinse/util.py | 12 ++++++++++++ rinse/wsdl.py | 24 +++++++++++------------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/rinse/client.py b/rinse/client.py index d327173..a3b468f 100644 --- a/rinse/client.py +++ b/rinse/client.py @@ -2,7 +2,7 @@ from __future__ import print_function import requests from rinse import ENVELOPE_XSD -from rinse.util import SCHEMA +from rinse.util import SCHEMA, cached_property from rinse.response import RinseResponse @@ -10,8 +10,6 @@ class SoapClient(object): """Rinse SOAP client.""" - __session = None - def __init__(self, url, debug=False, **kwargs): """Set base attributes.""" self.url = url @@ -20,17 +18,10 @@ def __init__(self, url, debug=False, **kwargs): self.operations = {} self.soap_schema = SCHEMA[ENVELOPE_XSD] - @property + @cached_property def _session(self): """Cached instance of requests.Session.""" - if self.__session is None: - self.__session = requests.Session() - return self.__session - - @_session.setter - def _session(self, session): - """Allow injecting your own instance of requests.Session.""" - self.__session = session + return requests.Session() def __call__(self, msg, action="", build_response=RinseResponse, debug=False): diff --git a/rinse/util.py b/rinse/util.py index f9b08c2..120c736 100644 --- a/rinse/util.py +++ b/rinse/util.py @@ -169,3 +169,15 @@ def recursive_dict(element): map(recursive_dict, element) ) or element.text ) + + +class cached_property(object): + def __init__(self, func): + self.func = func + self.__doc__ = getattr(func, '__doc__') + + def __get__(self, instance, owner): + if instance is None: + return self + result = instance.__dict__[self.func.__name__] = self.func(instance) + return result diff --git a/rinse/wsdl.py b/rinse/wsdl.py index 12e831b..64386ed 100644 --- a/rinse/wsdl.py +++ b/rinse/wsdl.py @@ -1,6 +1,8 @@ """Rinse SOAP library: module providing WSDL functions.""" from lxml import etree -from rinse.util import safe_parse_path, safe_parse_url, element_as_tree +from rinse.util import ( + safe_parse_path, safe_parse_url, element_as_tree, cached_property, +) from rinse.xsd import XSDValidator, NS_XSD NS_WSDL = 'http://schemas.xmlsoap.org/wsdl/' @@ -31,22 +33,18 @@ def __init__(self, wsdl_root): """WSDL init.""" self.root = wsdl_root - @property + @cached_property def schema(self): """Return schema element (used for XSD validation).""" - if self._schema is None: - schema_el = self.root.xpath( - '/wsdl:definitions/wsdl:types/xsd:schema', namespaces=NS_MAP, - )[0] - self._schema = element_as_tree(schema_el) - return self._schema - - @property + schema_el = self.root.xpath( + '/wsdl:definitions/wsdl:types/xsd:schema', namespaces=NS_MAP, + )[0] + return element_as_tree(schema_el) + + @cached_property def xsd_validator(self): """Extract XML Schema Definition (XSD) element tree.""" - if self._xsd_validator is None: - self._xsd_validator = XSDValidator(self.schema) - return self._xsd_validator + return XSDValidator(self.schema) def is_valid(self, soapmsg): """Return True if SOAP message body validates against WSDL schema.""" From 47a400146d0e87bc630b464cc5fe7bf917073e4e Mon Sep 17 00:00:00 2001 From: Tyson Clugg Date: Thu, 10 Sep 2015 16:20:43 +1000 Subject: [PATCH 2/5] Fix build chain/Makefile to ensure we include all relevant files and upload to PyPi consistently. --- MANIFEST.in | 14 ++++----- Makefile | 69 ++++++++++++++++++++++--------------------- setup.cfg | 2 ++ setup.py | 5 ++-- test-requirements.txt | 2 ++ tox.ini | 43 +++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 setup.cfg create mode 100644 test-requirements.txt create mode 100644 tox.ini diff --git a/MANIFEST.in b/MANIFEST.in index 3f3d256..66ebd92 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,10 +1,10 @@ include LICENSE -include Makefile include *.rst -include docs/*.rst -include docs/conf.py -include docs/make.bat -include docs/Makefile -include docs/_static/* -include docs/_templates/* +include *.sh +include *.txt +include Makefile +recursive-include docs *.bat +recursive-include docs *.py +recursive-include docs *.rst +recursive-include docs Makefile recursive-include rinse *.xsd diff --git a/Makefile b/Makefile index c509055..543eed0 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,42 @@ -SOURCES := \ - rinse/__init__.py \ - rinse/client.py \ - rinse/message.py \ - rinse/response.py \ - rinse/util.py \ - rinse/wsa.py \ - rinse/wsdl.py \ - rinse/wsse.py \ - rinse/xsd.py - -DOCS := \ - README.rst \ - docs/index.rst \ - docs/rinse.rst \ - docs/rinse.client.rst \ - docs/rinse.message.rst \ - docs/rinse.response.rst \ - docs/rinse.util.rst \ - docs/rinse.wsa.rst \ - docs/rinse.wsdl.rst \ - docs/rinse.wsse.rst \ - docs/rinse.xsd.rst - -.PHONY: all test clean clean-docs - -all: docs +NAME := $(shell python setup.py --name) +VERSION := $(shell python setup.py --version) + +SDIST := dist/${NAME}-${VERSION}.tar.gz +WHEEL := dist/${NAME}-${VERSION}-py2.py3-none-any.whl + +.PHONY: all test clean clean-docs upload-docs upload-pypi dist docs + +all: docs dist test: - python setup.py test + tox -clean: clean-docs +clean: clean-docs clean-sdist clean-wheel clean-docs: - rm -rf docs/_build/ + $(MAKE) -C docs/ clean + +clean-sdist: + rm -f "${SDIST}" + +clean-wheel: + rm -f "${WHEEL}" + +docs: + $(MAKE) -C docs/ clean html + +${SDIST}: + python setup.py sdist + +${WHEEL}: + python setup.py bdist_wheel + +dist: test ${SDIST} ${WHEEL} + +upload: upload-pypi upload-docs -docs: docs/_build/ +upload-pypi: ${SDIST} ${WHEEL} + twine upload "${WHEEL}" "${SDIST}" -docs/_build/: ${DOCS} ${SOURCES} docs/conf.py setup.py - rm -rf docs/_build/ - cd docs && $(MAKE) html doctest +upload-docs: docs/_build/ + python setup.py upload_sphinx --upload-dir="$=2.1.1 or refuse to run the tests. +minversion=2.1.1 + +# return success even if some of the specified environments are missing +skip_missing_interpreters=True + +# "envlist" is a comma separated list of environments, each environment name +# contains factors separated by hyphens. For example, "py27-unittest" has 2 +# factors: "py27" and "unittest". Other settings such as "setenv" accept the +# factor names as a prefixes (eg: "unittest: ...") so that prefixed settings +# only apply if the environment being run contains that factor. + +envlist = + py27-test, + py32-test, + py33-test, + py34-test, + py35-test, + +[testenv] +recreate=True +usedevelop=False +passenv= + BUILD_NUMBER + BUILD_URL + XDG_CACHE_HOME + +# continue running commands even if previous commands have failed +ignore_errors = True + +commands = + coverage run --source={toxinidir}/rinse {toxinidir}/setup.py test + coverage report + +deps = + -r{toxinidir}/test-requirements.txt + coverage From 913f449568ba4191ed05bebe9dc689bf181a2baf Mon Sep 17 00:00:00 2001 From: Tyson Clugg Date: Thu, 10 Sep 2015 16:35:29 +1000 Subject: [PATCH 3/5] Update trove classifiers. --- setup.py | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/setup.py b/setup.py index b38180e..a62d1ec 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,38 @@ #!/usr/bin/env python from setuptools import setup, find_packages +CLASSIFIERS = [ + # Beta status until 1.0 is released + "Development Status :: 4 - Beta", + + # Who and what the project is for + "Intended Audience :: Developers", + "Topic :: Communications", + "Topic :: Internet", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + "Topic :: Software Development :: Libraries", + "Topic :: Text Processing :: Markup :: XML", + + # License classifiers + "License :: OSI Approved :: MIT License", + "License :: DFSG approved", + "License :: OSI Approved", + + # Generally, we support the following. + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Framework :: Django", + + # Specifically, we support the following releases. + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Framework :: Django :: 1.7", + "Framework :: Django :: 1.8", +] + setup( name='rinse', version='0.3.0', @@ -20,15 +52,5 @@ 'requests', ], tests_require=['mock', 'six'], - classifiers=[ - "Development Status :: 4 - Beta", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", - "License :: OSI Approved :: MIT License", - "Topic :: Communications", - "Topic :: Internet :: WWW/HTTP", - "Topic :: Software Development :: Libraries", - "Topic :: Text Processing :: Markup :: XML", - ], + classifiers=CLASSIFIERS, ) From 49b57f1b32d4402c98c490c9a8445ac718fb4205 Mon Sep 17 00:00:00 2001 From: Tyson Clugg Date: Thu, 10 Sep 2015 16:35:44 +1000 Subject: [PATCH 4/5] Drop Python 3.2 from tox tests. --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5d37e49..8b934b9 100644 --- a/tox.ini +++ b/tox.ini @@ -18,7 +18,6 @@ skip_missing_interpreters=True envlist = py27-test, - py32-test, py33-test, py34-test, py35-test, From a2be85e119904e6fc06cb3b217948816f056860f Mon Sep 17 00:00:00 2001 From: Tyson Clugg Date: Thu, 10 Sep 2015 16:42:57 +1000 Subject: [PATCH 5/5] Update CHANGELOG.rst, bump version number. --- CHANGELOG.rst | 10 +++++++++- setup.py | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 66bdc45..49c88ec 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ Changelog ========= +0.4.0 +----- +* Use ``@cached_property`` to simplify property code. +* Fix ``AttributeError`` when debugging. +* Include missing XSD files in wheel distributions. +* Ensure XSD files exist in distributed files via tox test suite + options. + 0.3.0 ----- * Add 'SOAPAction' header to requests. @@ -51,4 +59,4 @@ Changelog 0.0.1 ----- -* Generate SOAP requests and parse SOAP 1.1 responses. \ No newline at end of file +* Generate SOAP requests and parse SOAP 1.1 responses. diff --git a/setup.py b/setup.py index a62d1ec..fb3d9ce 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ setup( name='rinse', - version='0.3.0', + version='0.4.0', description='SOAP client built with lxml and requests.', long_description=open('README.rst').read(), author='Tyson Clugg',