| @@ -1,6 +1,14 @@ | |||||
| CHANGELOG | CHANGELOG | ||||
| ===================== | ===================== | ||||
| 0.52.23 (unreleased) | |||||
| -------------------- | |||||
| - Port to Python 3.5 | |||||
| - Added TwistedSOAPPublisher and Proxy | |||||
| These are located in twisted.web.soap, but thats only for Python 2. | |||||
| 0.12.23 (unreleased) | 0.12.23 (unreleased) | ||||
| -------------------- | -------------------- | ||||
| @@ -1 +0,0 @@ | |||||
| *.pyc | |||||
| @@ -1 +0,0 @@ | |||||
| *.pyc | |||||
| @@ -2,33 +2,36 @@ | |||||
| # | # | ||||
| # $Id: setup.py,v 1.11 2005/02/15 16:32:22 warnes Exp $ | # $Id: setup.py,v 1.11 2005/02/15 16:32:22 warnes Exp $ | ||||
| CVS=0 | |||||
| CVS = 0 | |||||
| from setuptools import setup, find_packages | |||||
| import os | import os | ||||
| from setuptools import setup, find_packages | |||||
| def read(*rnames): | def read(*rnames): | ||||
| return "\n"+ open( | |||||
| return "\n" + open( | |||||
| os.path.join('.', *rnames) | os.path.join('.', *rnames) | ||||
| ).read() | ).read() | ||||
| url="https://github.com/kiorky/SOAPpy.git" | |||||
| long_description="SOAPpy provides tools for building SOAP clients and servers. For more information see " + url\ | |||||
| +'\n'+read('README.txt')\ | |||||
| +'\n'+read('CHANGES.txt') | |||||
| url = "https://github.com/Synerty/SOAPpy-py3" | |||||
| long_description = "SOAPpy-py3 provides tools for building SOAP clients and servers. For more information see " + url \ | |||||
| + '\n' + read('README.txt') \ | |||||
| + '\n' + read('CHANGES.txt') | |||||
| setup( | setup( | ||||
| name="SOAPpy", | |||||
| version='0.12.23.dev0', | |||||
| name="SOAPpy-py3", | |||||
| version='0.52.23', # Add 0.40.0 for the SOAPpy-py3 port | |||||
| description="SOAP Services for Python", | description="SOAP Services for Python", | ||||
| maintainer="Gregory Warnes, kiorky", | |||||
| maintainer_email="Gregory.R.Warnes@Pfizer.com, kiorky@cryptelium.net", | |||||
| url = url, | |||||
| maintainer="Synerty", | |||||
| maintainer_email="contact@synerty.com", | |||||
| url=url, | |||||
| long_description=long_description, | long_description=long_description, | ||||
| packages=find_packages('src'), | packages=find_packages('src'), | ||||
| package_dir = {'': 'src'}, | |||||
| package_dir={'': 'src'}, | |||||
| include_package_data=True, | include_package_data=True, | ||||
| install_requires=[ | install_requires=[ | ||||
| 'wstools', | 'wstools', | ||||
| 'defusedxml', | 'defusedxml', | ||||
| ] | ] | ||||
| ) | ) | ||||
| @@ -55,7 +55,7 @@ import socket, http.client | |||||
| from http.client import HTTPConnection | from http.client import HTTPConnection | ||||
| import http.cookies | import http.cookies | ||||
| # SOAPpy modules | |||||
| # SOAPpy-py3 modules | |||||
| from .Errors import * | from .Errors import * | ||||
| from .Config import Config | from .Config import Config | ||||
| from .Parser import parseSOAPRPC | from .Parser import parseSOAPRPC | ||||
| @@ -71,7 +71,7 @@ import collections | |||||
| def SOAPUserAgent(): | def SOAPUserAgent(): | ||||
| return "SOAPpy " + __version__ + " (pywebsvcs.sf.net)" | |||||
| return "SOAPpy-py3 " + __version__ + " (pywebsvcs.sf.net)" | |||||
| class HTTP: | class HTTP: | ||||
| @@ -137,7 +137,7 @@ class HTTP: | |||||
| #only add this keyword if non-default for compatibility | #only add this keyword if non-default for compatibility | ||||
| #with other connection classes | #with other connection classes | ||||
| response = self._conn.getresponse(buffering) | response = self._conn.getresponse(buffering) | ||||
| except BadStatusLine as e: | |||||
| except http.BadStatusLine as e: | |||||
| ### hmm. if getresponse() ever closes the socket on a bad request, | ### hmm. if getresponse() ever closes the socket on a bad request, | ||||
| ### then we are going to have problems with self.sock | ### then we are going to have problems with self.sock | ||||
| @@ -329,7 +329,7 @@ class HTTPTransport: | |||||
| debugHeader(s) | debugHeader(s) | ||||
| print("POST %s %s" % (real_path, r._http_vsn_str)) | print("POST %s %s" % (real_path, r._http_vsn_str)) | ||||
| print("Host:", addr.host) | print("Host:", addr.host) | ||||
| print("User-agent: SOAPpy " + __version__ + " (http://pywebsvcs.sf.net)") | |||||
| print("User-agent: SOAPpy-py3 " + __version__ + " (http://pywebsvcs.sf.net)") | |||||
| print("Content-type:", t) | print("Content-type:", t) | ||||
| print("Content-length:", len(data)) | print("Content-length:", len(data)) | ||||
| print('SOAPAction: "%s"' % soapaction) | print('SOAPAction: "%s"' % soapaction) | ||||
| @@ -56,7 +56,7 @@ import socketserver | |||||
| from SOAPpy.Types import * | from SOAPpy.Types import * | ||||
| import http.server | import http.server | ||||
| # SOAPpy modules | |||||
| # SOAPpy-py3 modules | |||||
| from .Parser import parseSOAPRPC | from .Parser import parseSOAPRPC | ||||
| from .Config import SOAPConfig | from .Config import SOAPConfig | ||||
| from .Types import faultType, voidType, simplify | from .Types import faultType, voidType, simplify | ||||
| @@ -40,7 +40,7 @@ | |||||
| ################################################################################ | ################################################################################ | ||||
| """ | """ | ||||
| from SOAPpy.Errors import Error | |||||
| ident = '$Id: NS.py 1468 2008-05-24 01:55:33Z warnes $' | ident = '$Id: NS.py 1468 2008-05-24 01:55:33Z warnes $' | ||||
| from .version import __version__ | from .version import __version__ | ||||
| @@ -298,7 +298,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||||
| if null: | if null: | ||||
| if len(cur) or \ | if len(cur) or \ | ||||
| (self._data != None and string.join(self._data, "").strip() != ''): | |||||
| (self._data != None and ''.join(self._data).strip() != ''): | |||||
| raise Error("nils can't have data") | raise Error("nils can't have data") | ||||
| data = None | data = None | ||||
| @@ -943,7 +943,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||||
| raise OverflowError("%s too large: %s" % (t[1], s)) | raise OverflowError("%s too large: %s" % (t[1], s)) | ||||
| elif d == 0: | elif d == 0: | ||||
| if type(self.zerofloatre) == StringType: | if type(self.zerofloatre) == StringType: | ||||
| self.zerofloatre = re.compile(self.zerofloatre) | |||||
| self.zerofloatre = re.compile(str(self.zerofloatre)) | |||||
| if self.zerofloatre.search(s): | if self.zerofloatre.search(s): | ||||
| raise UnderflowError("invalid %s: %s" % (t[1], s)) | raise UnderflowError("invalid %s: %s" % (t[1], s)) | ||||
| @@ -22,17 +22,17 @@ from warnings import warn | |||||
| warn(""" | warn(""" | ||||
| The sub-module SOAPpy.SOAP is deprecated and is only | |||||
| The sub-module SOAPpy-py3.SOAP is deprecated and is only | |||||
| provided for short-term backward compatibility. Objects are now | provided for short-term backward compatibility. Objects are now | ||||
| available directly within the SOAPpy module. Thus, instead of | |||||
| available directly within the SOAPpy-py3 module. Thus, instead of | |||||
| from SOAPpy import SOAP | |||||
| from SOAPpy-py3 import SOAP | |||||
| ... | ... | ||||
| SOAP.SOAPProxy(...) | SOAP.SOAPProxy(...) | ||||
| use | use | ||||
| from SOAPpy import SOAPProxy | |||||
| from SOAPpy-py3 import SOAPProxy | |||||
| ... | ... | ||||
| SOAPProxy(...) | SOAPProxy(...) | ||||
| @@ -39,7 +39,7 @@ from .version import __version__ | |||||
| import cgi | import cgi | ||||
| from wstools.XMLname import toXMLname, fromXMLname | from wstools.XMLname import toXMLname, fromXMLname | ||||
| # SOAPpy modules | |||||
| # SOAPpy-py3 modules | |||||
| from .Config import Config | from .Config import Config | ||||
| from .NS import NS | from .NS import NS | ||||
| from SOAPpy.Types import * | from SOAPpy.Types import * | ||||
| @@ -53,7 +53,7 @@ from SOAPpy.Types import * | |||||
| import http.server | import http.server | ||||
| import _thread | import _thread | ||||
| # SOAPpy modules | |||||
| # SOAPpy-py3 modules | |||||
| from .Parser import parseSOAPRPC | from .Parser import parseSOAPRPC | ||||
| from .Config import Config | from .Config import Config | ||||
| from SOAPpy.Types import faultType, voidType, simplify | from SOAPpy.Types import faultType, voidType, simplify | ||||
| @@ -194,7 +194,7 @@ class SOAPRequestHandler(http.server.BaseHTTPRequestHandler): | |||||
| ignore_ext = True | ignore_ext = True | ||||
| def version_string(self): | def version_string(self): | ||||
| return '<a href="http://pywebsvcs.sf.net">' + \ | return '<a href="http://pywebsvcs.sf.net">' + \ | ||||
| 'SOAPpy ' + __version__ + '</a> (Python ' + \ | |||||
| 'SOAPpy-py3 ' + __version__ + '</a> (Python ' + \ | |||||
| sys.version.split()[0] + ')' | sys.version.split()[0] + ')' | ||||
| def date_time_string(self): | def date_time_string(self): | ||||
| @@ -0,0 +1,41 @@ | |||||
| # twisted imports | |||||
| from twisted.web import client | |||||
| import SOAPpy | |||||
| class TwistedSOAPProxy: | |||||
| """A Proxy for making remote SOAP calls. | |||||
| Pass the URL of the remote SOAP server to the constructor. | |||||
| Use proxy.callRemote('foobar', 1, 2) to call remote method | |||||
| 'foobar' with args 1 and 2, proxy.callRemote('foobar', x=1) | |||||
| will call foobar with named argument 'x'. | |||||
| """ | |||||
| # at some point this should have encoding etc. kwargs | |||||
| def __init__(self, url, namespace=None, header=None): | |||||
| self.url = url | |||||
| self.namespace = namespace | |||||
| self.header = header | |||||
| def _cbGotResult(self, result): | |||||
| result = SOAPpy.parseSOAPRPC(result) | |||||
| if hasattr(result, 'Result'): | |||||
| return result.Result | |||||
| elif len(result) == 1: | |||||
| ## SOAPpy 0.11.6 wraps the return results in a containing structure. | |||||
| ## This check added to make Proxy behaviour emulate SOAPProxy, which | |||||
| ## flattens the structure by default. | |||||
| ## This behaviour is OK because even singleton lists are wrapped in | |||||
| ## another singleton structType, which is almost always useless. | |||||
| return result[0] | |||||
| else: | |||||
| return result | |||||
| def callRemote(self, method: str, *args, **kwargs): | |||||
| payload = SOAPpy.buildSOAP(args=args, kw=kwargs, method=method, | |||||
| header=self.header, namespace=self.namespace) | |||||
| return client.getPage(self.url.encode, postdata=payload, method=b"POST", | |||||
| headers={b'content-type': b'text/xml', | |||||
| b'SOAPAction': method.encode()} | |||||
| ).addCallback(self._cbGotResult) | |||||
| @@ -0,0 +1,98 @@ | |||||
| # twisted imports | |||||
| import logging | |||||
| from twisted.internet import defer | |||||
| from twisted.web import server, resource | |||||
| import SOAPpy | |||||
| class TwistedSOAPPublisher(resource.Resource): | |||||
| """Publish SOAP methods. | |||||
| By default, publish methods beginning with 'soap_'. If the method | |||||
| has an attribute 'useKeywords', it well get the arguments passed | |||||
| as keyword args. | |||||
| """ | |||||
| isLeaf = 1 | |||||
| # override to change the encoding used for responses | |||||
| encoding = "UTF-8" | |||||
| def lookupFunction(self, functionName): | |||||
| """Lookup published SOAP function. | |||||
| Override in subclasses. Default behaviour - publish methods | |||||
| starting with soap_. | |||||
| @return: callable or None if not found. | |||||
| """ | |||||
| return getattr(self, "soap_%s" % functionName, None) | |||||
| def render(self, request): | |||||
| """Handle a SOAP command.""" | |||||
| data = request.content.read() | |||||
| # Convert it to str from bytes | |||||
| data = data.decode() | |||||
| p, header, body, attrs = SOAPpy.parseSOAPRPC(data, 1, 1, 1) | |||||
| methodName, args, kwargs = p._name, p._aslist, p._asdict | |||||
| # deal with changes in SOAPpy 0.11 | |||||
| if callable(args): | |||||
| args = args() | |||||
| if callable(kwargs): | |||||
| kwargs = kwargs() | |||||
| function = self.lookupFunction(methodName) | |||||
| if not function: | |||||
| self._methodNotFound(request, methodName) | |||||
| return server.NOT_DONE_YET | |||||
| else: | |||||
| if hasattr(function, "useKeywords"): | |||||
| keywords = {} | |||||
| for k, v in kwargs.items(): | |||||
| keywords[str(k)] = v | |||||
| d = defer.maybeDeferred(function, **keywords) | |||||
| else: | |||||
| d = defer.maybeDeferred(function, *args) | |||||
| d.addCallback(self._gotResult, request, methodName) | |||||
| d.addErrback(self._gotError, request, methodName) | |||||
| return server.NOT_DONE_YET | |||||
| def _methodNotFound(self, request, methodName): | |||||
| response = SOAPpy.buildSOAP(SOAPpy.faultType("%s:Client" % | |||||
| SOAPpy.NS.ENV_T, | |||||
| "Method %s not found" % methodName), | |||||
| encoding=self.encoding) | |||||
| self._sendResponse(request, response, status=500) | |||||
| def _gotResult(self, result, request, methodName): | |||||
| if not isinstance(result, SOAPpy.voidType): | |||||
| result = {"Result": result} | |||||
| response = SOAPpy.buildSOAP(kw={'%sResponse' % methodName: result}, | |||||
| encoding=self.encoding) | |||||
| self._sendResponse(request, response) | |||||
| def _gotError(self, failure, request, methodName): | |||||
| e = failure.value | |||||
| if isinstance(e, SOAPpy.faultType): | |||||
| fault = e | |||||
| else: | |||||
| fault = SOAPpy.faultType("%s:Server" % SOAPpy.NS.ENV_T, | |||||
| "Method %s failed." % methodName) | |||||
| response = SOAPpy.buildSOAP(fault, encoding=self.encoding) | |||||
| self._sendResponse(request, response, status=500) | |||||
| def _sendResponse(self, request, response, status=200): | |||||
| request.setResponseCode(status) | |||||
| if self.encoding is not None: | |||||
| mimeType = 'text/xml; charset="%s"' % self.encoding | |||||
| else: | |||||
| mimeType = "text/xml" | |||||
| request.setHeader(b"Content-type", mimeType.encode()) | |||||
| request.setHeader(b"Content-length", str(len(response)).encode()) | |||||
| request.write(response) | |||||
| request.finish() | |||||
| @@ -34,6 +34,18 @@ | |||||
| """ | """ | ||||
| ## PYTHON3 - These types are no longer present in the builtin "types" module | |||||
| StringType = str | |||||
| UnicodeType = str | |||||
| ListType = list | |||||
| DictType = dict | |||||
| IntType = int | |||||
| LongType = int | |||||
| FloatType = float | |||||
| BooleanType = bool | |||||
| TupleType = tuple | |||||
| InstanceType = object | |||||
| ident = '$Id: Types.py 1496 2010-03-04 23:46:17Z pooryorick $' | ident = '$Id: Types.py 1496 2010-03-04 23:46:17Z pooryorick $' | ||||
| from .version import __version__ | from .version import __version__ | ||||
| @@ -47,7 +59,7 @@ import re | |||||
| import time | import time | ||||
| from SOAPpy.Types import * | from SOAPpy.Types import * | ||||
| # SOAPpy modules | |||||
| # SOAPpy-py3 modules | |||||
| from .Errors import * | from .Errors import * | ||||
| from .NS import NS | from .NS import NS | ||||
| from .Utilities import encodeHexString, cleanDate | from .Utilities import encodeHexString, cleanDate | ||||
| @@ -1110,7 +1122,7 @@ class longType(anyType): | |||||
| return data | return data | ||||
| class int(anyType): | |||||
| class intType(anyType): | |||||
| _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) | _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) | ||||
| def _checkValueSpace(self, data): | def _checkValueSpace(self, data): | ||||
| @@ -1611,7 +1623,7 @@ class faultType(structType, Error): | |||||
| class SOAPException(Exception): | class SOAPException(Exception): | ||||
| def __init__(self, code="", string="", detail=None): | def __init__(self, code="", string="", detail=None): | ||||
| self.value = ("SOAPpy SOAP Exception", code, string, detail) | |||||
| self.value = ("SOAPpy-py3 SOAP Exception", code, string, detail) | |||||
| self.code = code | self.code = code | ||||
| self.string = string | self.string = string | ||||
| self.detail = detail | self.detail = detail | ||||
| @@ -1650,12 +1662,12 @@ class MethodFailed(Exception): | |||||
| return repr(self.value) | return repr(self.value) | ||||
| ####### | ####### | ||||
| # Convert complex SOAPpy objects to native python equivalents | |||||
| # Convert complex SOAPpy-py3 objects to native python equivalents | |||||
| ####### | ####### | ||||
| def simplify(object, level=0): | def simplify(object, level=0): | ||||
| """ | """ | ||||
| Convert the SOAPpy objects and their contents to simple python types. | |||||
| Convert the SOAPpy-py3 objects and their contents to simple python types. | |||||
| This function recursively converts the passed 'container' object, | This function recursively converts the passed 'container' object, | ||||
| and all public subobjects. (Private subobjects have names that | and all public subobjects. (Private subobjects have names that | ||||
| @@ -1709,7 +1721,7 @@ def simplify(object, level=0): | |||||
| def simplify_contents(object, level=0): | def simplify_contents(object, level=0): | ||||
| """ | """ | ||||
| Convert the contents of SOAPpy objects to simple python types. | |||||
| Convert the contents of SOAPpy-py3 objects to simple python types. | |||||
| This function recursively converts the sub-objects contained in a | This function recursively converts the sub-objects contained in a | ||||
| 'container' object to simple python types. | 'container' object to simple python types. | ||||
| @@ -41,7 +41,7 @@ import string | |||||
| import sys | import sys | ||||
| from SOAPpy.Types import * | from SOAPpy.Types import * | ||||
| # SOAPpy modules | |||||
| # SOAPpy-py3 modules | |||||
| from .Errors import * | from .Errors import * | ||||
| ################################################################################ | ################################################################################ | ||||
| @@ -1,5 +1,5 @@ | |||||
| try: | try: | ||||
| import pkg_resources | import pkg_resources | ||||
| __version__ = pkg_resources.get_distribution("SOAPpy").version | |||||
| __version__ = pkg_resources.get_distribution("SOAPpy-py3").version | |||||
| except: | except: | ||||
| __version__="xxx" | __version__="xxx" | ||||
| @@ -3750,7 +3750,7 @@ if __name__ == '__main__': | |||||
| NOTE: The 'testArray' test will fail because 'referenced' elements are | NOTE: The 'testArray' test will fail because 'referenced' elements are | ||||
| included in the return object. This is a known shortcoming of | included in the return object. This is a known shortcoming of | ||||
| the current version of SOAPpy. | |||||
| the current version of SOAPpy-py3. | |||||
| All other tests should succeed. | All other tests should succeed. | ||||
| @@ -6,7 +6,7 @@ ident = '$Id: alanbushTest.py,v 1.5 2003/05/21 14:52:37 warnes Exp $' | |||||
| import os, re,sys | import os, re,sys | ||||
| # add local SOAPpy code to search path | |||||
| # add local SOAPpy-py3 code to search path | |||||
| sys.path.insert(1, "..") | sys.path.insert(1, "..") | ||||
| from SOAPpy import * | from SOAPpy import * | ||||
| @@ -16,7 +16,7 @@ except: | |||||
| PROXY="http://www.soapware.org/xmlStorageSystem" | PROXY="http://www.soapware.org/xmlStorageSystem" | ||||
| EMAIL="SOAPpy@actzero.com" | |||||
| EMAIL="SOAPpy-py3@actzero.com" | |||||
| NAME="test_user" | NAME="test_user" | ||||
| PASSWORD="mypasswd" | PASSWORD="mypasswd" | ||||
| SERIAL=1123214 | SERIAL=1123214 | ||||
| @@ -7,7 +7,7 @@ import sys | |||||
| sys.path.insert(1, "..") | sys.path.insert(1, "..") | ||||
| import SOAPpy | import SOAPpy | ||||
| #SOAPpy.Config.debug=1 | |||||
| #SOAPpy-py3.Config.debug=1 | |||||
| # global to shut down server | # global to shut down server | ||||
| quit = 0 | quit = 0 | ||||
| @@ -107,7 +107,7 @@ class ClientTestCase(unittest.TestCase): | |||||
| # gc.set_debug(gc.DEBUG_SAVEALL) | # gc.set_debug(gc.DEBUG_SAVEALL) | ||||
| # for i in range(400): | # for i in range(400): | ||||
| # server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') | |||||
| # server = SOAPpy-py3.Client.SOAPProxy('127.0.0.1:8000') | |||||
| # s = 'Hello World' | # s = 'Hello World' | ||||
| # server.echo(s) | # server.echo(s) | ||||
| # gc.collect() | # gc.collect() | ||||
| @@ -1 +0,0 @@ | |||||
| *.pyc | |||||
| @@ -1 +0,0 @@ | |||||
| *.pyc | |||||