@@ -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 |