| @@ -1,6 +1,14 @@ | |||
| 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) | |||
| -------------------- | |||
| @@ -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 $ | |||
| CVS=0 | |||
| CVS = 0 | |||
| from setuptools import setup, find_packages | |||
| import os | |||
| from setuptools import setup, find_packages | |||
| def read(*rnames): | |||
| return "\n"+ open( | |||
| return "\n" + open( | |||
| os.path.join('.', *rnames) | |||
| ).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( | |||
| 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", | |||
| 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, | |||
| packages=find_packages('src'), | |||
| package_dir = {'': 'src'}, | |||
| package_dir={'': 'src'}, | |||
| include_package_data=True, | |||
| install_requires=[ | |||
| 'wstools', | |||
| 'defusedxml', | |||
| ] | |||
| ) | |||
| @@ -55,7 +55,7 @@ import socket, http.client | |||
| from http.client import HTTPConnection | |||
| import http.cookies | |||
| # SOAPpy modules | |||
| # SOAPpy-py3 modules | |||
| from .Errors import * | |||
| from .Config import Config | |||
| from .Parser import parseSOAPRPC | |||
| @@ -71,7 +71,7 @@ import collections | |||
| def SOAPUserAgent(): | |||
| return "SOAPpy " + __version__ + " (pywebsvcs.sf.net)" | |||
| return "SOAPpy-py3 " + __version__ + " (pywebsvcs.sf.net)" | |||
| class HTTP: | |||
| @@ -137,7 +137,7 @@ class HTTP: | |||
| #only add this keyword if non-default for compatibility | |||
| #with other connection classes | |||
| 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, | |||
| ### then we are going to have problems with self.sock | |||
| @@ -329,7 +329,7 @@ class HTTPTransport: | |||
| debugHeader(s) | |||
| print("POST %s %s" % (real_path, r._http_vsn_str)) | |||
| 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-length:", len(data)) | |||
| print('SOAPAction: "%s"' % soapaction) | |||
| @@ -56,7 +56,7 @@ import socketserver | |||
| from SOAPpy.Types import * | |||
| import http.server | |||
| # SOAPpy modules | |||
| # SOAPpy-py3 modules | |||
| from .Parser import parseSOAPRPC | |||
| from .Config import SOAPConfig | |||
| 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 $' | |||
| from .version import __version__ | |||
| @@ -298,7 +298,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| if null: | |||
| 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") | |||
| data = None | |||
| @@ -943,7 +943,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| raise OverflowError("%s too large: %s" % (t[1], s)) | |||
| elif d == 0: | |||
| if type(self.zerofloatre) == StringType: | |||
| self.zerofloatre = re.compile(self.zerofloatre) | |||
| self.zerofloatre = re.compile(str(self.zerofloatre)) | |||
| if self.zerofloatre.search(s): | |||
| raise UnderflowError("invalid %s: %s" % (t[1], s)) | |||
| @@ -22,17 +22,17 @@ from warnings import 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 | |||
| 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(...) | |||
| use | |||
| from SOAPpy import SOAPProxy | |||
| from SOAPpy-py3 import SOAPProxy | |||
| ... | |||
| SOAPProxy(...) | |||
| @@ -39,7 +39,7 @@ from .version import __version__ | |||
| import cgi | |||
| from wstools.XMLname import toXMLname, fromXMLname | |||
| # SOAPpy modules | |||
| # SOAPpy-py3 modules | |||
| from .Config import Config | |||
| from .NS import NS | |||
| from SOAPpy.Types import * | |||
| @@ -53,7 +53,7 @@ from SOAPpy.Types import * | |||
| import http.server | |||
| import _thread | |||
| # SOAPpy modules | |||
| # SOAPpy-py3 modules | |||
| from .Parser import parseSOAPRPC | |||
| from .Config import Config | |||
| from SOAPpy.Types import faultType, voidType, simplify | |||
| @@ -194,7 +194,7 @@ class SOAPRequestHandler(http.server.BaseHTTPRequestHandler): | |||
| ignore_ext = True | |||
| def version_string(self): | |||
| return '<a href="http://pywebsvcs.sf.net">' + \ | |||
| 'SOAPpy ' + __version__ + '</a> (Python ' + \ | |||
| 'SOAPpy-py3 ' + __version__ + '</a> (Python ' + \ | |||
| sys.version.split()[0] + ')' | |||
| 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 $' | |||
| from .version import __version__ | |||
| @@ -47,7 +59,7 @@ import re | |||
| import time | |||
| from SOAPpy.Types import * | |||
| # SOAPpy modules | |||
| # SOAPpy-py3 modules | |||
| from .Errors import * | |||
| from .NS import NS | |||
| from .Utilities import encodeHexString, cleanDate | |||
| @@ -1110,7 +1122,7 @@ class longType(anyType): | |||
| return data | |||
| class int(anyType): | |||
| class intType(anyType): | |||
| _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) | |||
| def _checkValueSpace(self, data): | |||
| @@ -1611,7 +1623,7 @@ class faultType(structType, Error): | |||
| class SOAPException(Exception): | |||
| 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.string = string | |||
| self.detail = detail | |||
| @@ -1650,12 +1662,12 @@ class MethodFailed(Exception): | |||
| 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): | |||
| """ | |||
| 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, | |||
| and all public subobjects. (Private subobjects have names that | |||
| @@ -1709,7 +1721,7 @@ def simplify(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 | |||
| 'container' object to simple python types. | |||
| @@ -41,7 +41,7 @@ import string | |||
| import sys | |||
| from SOAPpy.Types import * | |||
| # SOAPpy modules | |||
| # SOAPpy-py3 modules | |||
| from .Errors import * | |||
| ################################################################################ | |||
| @@ -1,5 +1,5 @@ | |||
| try: | |||
| import pkg_resources | |||
| __version__ = pkg_resources.get_distribution("SOAPpy").version | |||
| __version__ = pkg_resources.get_distribution("SOAPpy-py3").version | |||
| except: | |||
| __version__="xxx" | |||
| @@ -3750,7 +3750,7 @@ if __name__ == '__main__': | |||
| NOTE: The 'testArray' test will fail because 'referenced' elements are | |||
| 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. | |||
| @@ -6,7 +6,7 @@ ident = '$Id: alanbushTest.py,v 1.5 2003/05/21 14:52:37 warnes Exp $' | |||
| import os, re,sys | |||
| # add local SOAPpy code to search path | |||
| # add local SOAPpy-py3 code to search path | |||
| sys.path.insert(1, "..") | |||
| from SOAPpy import * | |||
| @@ -16,7 +16,7 @@ except: | |||
| PROXY="http://www.soapware.org/xmlStorageSystem" | |||
| EMAIL="SOAPpy@actzero.com" | |||
| EMAIL="SOAPpy-py3@actzero.com" | |||
| NAME="test_user" | |||
| PASSWORD="mypasswd" | |||
| SERIAL=1123214 | |||
| @@ -7,7 +7,7 @@ import sys | |||
| sys.path.insert(1, "..") | |||
| import SOAPpy | |||
| #SOAPpy.Config.debug=1 | |||
| #SOAPpy-py3.Config.debug=1 | |||
| # global to shut down server | |||
| quit = 0 | |||
| @@ -107,7 +107,7 @@ class ClientTestCase(unittest.TestCase): | |||
| # gc.set_debug(gc.DEBUG_SAVEALL) | |||
| # 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' | |||
| # server.echo(s) | |||
| # gc.collect() | |||
| @@ -1 +0,0 @@ | |||
| *.pyc | |||
| @@ -1 +0,0 @@ | |||
| *.pyc | |||