@@ -0,0 +1,5 @@ | |||||
[report] | |||||
omit = | |||||
*/python?.?/* | |||||
*/site-packages/nose/* | |||||
@@ -0,0 +1,2 @@ | |||||
repo_token: 5AkyFNIcadJWZQU8iA6f9GPtJs2xP8V6C | |||||
@@ -1,6 +1,12 @@ | |||||
language: python | language: python | ||||
python: | |||||
- "2.6" | |||||
- "2.7" | |||||
script: ./tox | |||||
env: | |||||
- TOX_ENV=py26 | |||||
- TOX_ENV=py27 | |||||
- TOX_ENV=py33 | |||||
- TOX_ENV=py34 | |||||
- TOX_ENV=flake8 | |||||
install: | |||||
- pip install tox | |||||
script: | |||||
- tox -e $TOX_ENV | |||||
@@ -1,3 +1,5 @@ | |||||
[](https://travis-ci.org/kartoch/wstools)[](https://coveralls.io/r/kartoch/wstools?branch=master) | |||||
General | General | ||||
======== | ======== | ||||
- Homepage: https://github.com/pycontribs/wstools | - Homepage: https://github.com/pycontribs/wstools |
@@ -1,8 +1,7 @@ | |||||
#!/usr/bin/env python | #!/usr/bin/env python | ||||
import os | import os | ||||
import re | |||||
from setuptools import setup, find_packages | |||||
from setuptools import setup | |||||
url = "https://github.com/pycontribs/wstools.git" | url = "https://github.com/pycontribs/wstools.git" | ||||
@@ -12,23 +11,24 @@ def read(*rnames): | |||||
os.path.join('.', *rnames) | os.path.join('.', *rnames) | ||||
).read() | ).read() | ||||
long_description = """WSDL parsing services package for Web Services for Python. see """ + url \ | |||||
+ read('README.txt')\ | |||||
+ read('CHANGES.txt')\ | |||||
long_description = \ | |||||
"WSDL parsing services package for Web Services for Python. see" + url | |||||
from src.wstools.version import __version__ | |||||
from wstools.version import __version__ | |||||
install_requires = [ | |||||
'docutils' | |||||
] | |||||
setup( | setup( | ||||
name="wstools", | name="wstools", | ||||
version=__version__, | version=__version__, | ||||
description="wstools", | description="wstools", | ||||
maintainer="Gregory Warnes, kiorky, sorin", | maintainer="Gregory Warnes, kiorky, sorin", | ||||
maintainer_email="Gregory.R.Warnes@Pfizer.com, kiorky@cryptelium.net, sorin.sbarnea+os@gmail.com", | |||||
maintainer_email="Gregory.R.Warnes@Pfizer.com, " | |||||
+ " kiorky@cryptelium.net, " + "sorin.sbarnea+os@gmail.com", | |||||
url=url, | url=url, | ||||
long_description=long_description, | long_description=long_description, | ||||
packages=find_packages('src'), | |||||
package_dir={'': 'src'}, | |||||
include_package_data=True, | |||||
install_requires=['docutils'], | |||||
tests_require=['virtualenv>=1.8.4', 'pytest'], | |||||
packages=['wstools'], | |||||
install_requires=install_requires, | |||||
) | ) |
@@ -1,298 +0,0 @@ | |||||
# Copyright (c) 2003, The Regents of the University of California, | |||||
# through Lawrence Berkeley National Laboratory (subject to receipt of | |||||
# any required approvals from the U.S. Dept. of Energy). All rights | |||||
# reserved. | |||||
# | |||||
"""Logging""" | |||||
ident = "$Id$" | |||||
import os | |||||
import sys | |||||
WARN = 1 | |||||
DEBUG = 2 | |||||
class ILogger: | |||||
'''Logger interface, by default this class | |||||
will be used and logging calls are no-ops. | |||||
''' | |||||
level = 0 | |||||
def __init__(self, msg): | |||||
return | |||||
def warning(self, *args, **kw): | |||||
return | |||||
def debug(self, *args, **kw): | |||||
return | |||||
def error(self, *args, **kw): | |||||
return | |||||
def setLevel(cls, level): | |||||
cls.level = level | |||||
setLevel = classmethod(setLevel) | |||||
debugOn = lambda self: self.level >= DEBUG | |||||
warnOn = lambda self: self.level >= WARN | |||||
class BasicLogger(ILogger): | |||||
last = '' | |||||
def __init__(self, msg, out=sys.stdout): | |||||
self.msg, self.out = msg, out | |||||
def warning(self, msg, *args, **kw): | |||||
if self.warnOn() is False: | |||||
return | |||||
if BasicLogger.last != self.msg: | |||||
BasicLogger.last = self.msg | |||||
print >>self, "---- ", self.msg, " ----" | |||||
print >>self, " %s " % self.WARN, | |||||
print >>self, msg % args | |||||
WARN = '[WARN]' | |||||
def debug(self, msg, *args, **kw): | |||||
if self.debugOn() is False: | |||||
return | |||||
if BasicLogger.last != self.msg: | |||||
BasicLogger.last = self.msg | |||||
print >>self, "---- ", self.msg, " ----" | |||||
print >>self, " %s " % self.DEBUG, | |||||
print >>self, msg % args | |||||
DEBUG = '[DEBUG]' | |||||
def error(self, msg, *args, **kw): | |||||
if BasicLogger.last != self.msg: | |||||
BasicLogger.last = self.msg | |||||
print >>self, "---- ", self.msg, " ----" | |||||
print >>self, " %s " % self.ERROR, | |||||
print >>self, msg % args | |||||
ERROR = '[ERROR]' | |||||
def write(self, *args): | |||||
'''Write convenience function; writes strings. | |||||
''' | |||||
for s in args: | |||||
self.out.write(s) | |||||
event = ''.join(*args) | |||||
_LoggerClass = BasicLogger | |||||
class GridLogger(ILogger): | |||||
def debug(self, msg, *args, **kw): | |||||
kw['component'] = self.msg | |||||
gridLog(event=msg % args, level='DEBUG', **kw) | |||||
def warning(self, msg, *args, **kw): | |||||
kw['component'] = self.msg | |||||
gridLog(event=msg % args, level='WARNING', **kw) | |||||
def error(self, msg, *args, **kw): | |||||
kw['component'] = self.msg | |||||
gridLog(event=msg % args, level='ERROR', **kw) | |||||
# | |||||
# Registry of send functions for gridLog | |||||
# | |||||
GLRegistry = {} | |||||
class GLRecord(dict): | |||||
"""Grid Logging Best Practices Record, Distributed Logging Utilities | |||||
The following names are reserved: | |||||
event -- log event name | |||||
Below is EBNF for the event name part of a log message. | |||||
name = <nodot> ( "." <name> )? | |||||
nodot = {RFC3896-chars except "."} | |||||
Suffixes: | |||||
start: Immediately before the first action in a task. | |||||
end: Immediately after the last action in a task (that succeeded). | |||||
error: an error condition that does not correspond to an end event. | |||||
ts -- timestamp | |||||
level -- logging level (see levels below) | |||||
status -- integer status code | |||||
gid -- global grid identifier | |||||
gid, cgid -- parent/child identifiers | |||||
prog -- program name | |||||
More info: http://www.cedps.net/wiki/index.php/LoggingBestPractices#Python | |||||
reserved -- list of reserved names, | |||||
omitname -- list of reserved names, output only values ('ts', 'event',) | |||||
levels -- dict of levels and description | |||||
""" | |||||
reserved = ('ts', 'event', 'level', 'status', 'gid', 'prog') | |||||
omitname = () | |||||
levels = dict(FATAL='Component cannot continue, or system is unusable.', | |||||
ALERT='Action must be taken immediately.', | |||||
CRITICAL='Critical conditions (on the system).', | |||||
ERROR='Errors in the component; not errors from elsewhere.', | |||||
WARNING='Problems that are recovered from, usually.', | |||||
NOTICE='Normal but significant condition.', | |||||
INFO='Informational messages that would be useful to a deployer or administrator.', | |||||
DEBUG='Lower level information concerning program logic decisions, internal state, etc.', | |||||
TRACE='Finest granularity, similar to "stepping through" the component or system.',) | |||||
def __init__(self, date=None, **kw): | |||||
kw['ts'] = date or self.GLDate() | |||||
kw['gid'] = kw.get('gid') or os.getpid() | |||||
dict.__init__(self, kw) | |||||
def __str__(self): | |||||
""" | |||||
""" | |||||
from cStringIO import StringIO | |||||
s = StringIO() | |||||
n = " " | |||||
reserved = self.reserved | |||||
omitname = self.omitname | |||||
levels = self.levels | |||||
for k in (list(filter(lambda i: i in self, reserved)) + | |||||
list(filter(lambda i: i not in reserved, self.keys())) | |||||
): | |||||
v = self[k] | |||||
if k in omitname: | |||||
s.write("%s " % self.format[type(v)](v)) | |||||
continue | |||||
if k == reserved[2] and v not in levels: | |||||
pass | |||||
s.write("%s=%s " % (k, self.format[type(v)](v))) | |||||
s.write("\n") | |||||
return s.getvalue() | |||||
class GLDate(str): | |||||
"""Grid logging Date Format | |||||
all timestamps should all be in the same time zone (UTC). | |||||
Grid timestamp value format that is a highly readable variant of the ISO8601 time standard [1]: | |||||
YYYY-MM-DDTHH:MM:SS.SSSSSSZ | |||||
""" | |||||
def __new__(self, args=None): | |||||
"""args -- datetime (year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]]) | |||||
""" | |||||
import datetime | |||||
args = args or datetime.datetime.utcnow() | |||||
l = (args.year, args.month, args.day, args.hour, args.minute, args.second, | |||||
args.microsecond, args.tzinfo or 'Z') | |||||
return str.__new__(self, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%s" % l) | |||||
format = {int: str, float: lambda x: "%lf" % x, long: str, str: lambda x: x, | |||||
unicode: str, GLDate: str, } | |||||
def gridLog(**kw): | |||||
"""Send GLRecord, Distributed Logging Utilities | |||||
If the scheme is passed as a keyword parameter | |||||
the value is expected to be a callable function | |||||
that takes 2 parameters: url, outputStr | |||||
GRIDLOG_ON -- turn grid logging on | |||||
GRIDLOG_DEST -- provide URL destination | |||||
""" | |||||
import os | |||||
if not bool(int(os.environ.get('GRIDLOG_ON', 0))): | |||||
return | |||||
url = os.environ.get('GRIDLOG_DEST') | |||||
if url is None: | |||||
return | |||||
## NOTE: urlparse problem w/customized schemes | |||||
try: | |||||
scheme = url[:url.find('://')] | |||||
send = GLRegistry[scheme] | |||||
send(url, str(GLRecord(**kw)), ) | |||||
except Exception, ex: | |||||
print >>sys.stderr, "*** gridLog failed -- %s" % (str(kw)) | |||||
def sendUDP(url, outputStr): | |||||
from socket import socket, AF_INET, SOCK_DGRAM | |||||
idx1 = url.find('://') + 3 | |||||
idx2 = url.find('/', idx1) | |||||
if idx2 < idx1: | |||||
idx2 = len(url) | |||||
netloc = url[idx1:idx2] | |||||
host, port = (netloc.split(':') + [80])[0:2] | |||||
socket(AF_INET, SOCK_DGRAM).sendto(outputStr, (host, int(port)), ) | |||||
def writeToFile(url, outputStr): | |||||
print >> open(url.split('://')[1], 'a+'), outputStr | |||||
GLRegistry["gridlog-udp"] = sendUDP | |||||
GLRegistry["file"] = writeToFile | |||||
def setBasicLogger(): | |||||
'''Use Basic Logger. | |||||
''' | |||||
setLoggerClass(BasicLogger) | |||||
BasicLogger.setLevel(0) | |||||
def setGridLogger(): | |||||
'''Use GridLogger for all logging events. | |||||
''' | |||||
setLoggerClass(GridLogger) | |||||
def setBasicLoggerWARN(): | |||||
'''Use Basic Logger. | |||||
''' | |||||
setLoggerClass(BasicLogger) | |||||
BasicLogger.setLevel(WARN) | |||||
def setBasicLoggerDEBUG(): | |||||
'''Use Basic Logger. | |||||
''' | |||||
setLoggerClass(BasicLogger) | |||||
BasicLogger.setLevel(DEBUG) | |||||
def setLoggerClass(loggingClass): | |||||
'''Set Logging Class. | |||||
''' | |||||
def setLoggerClass(loggingClass): | |||||
'''Set Logging Class. | |||||
''' | |||||
assert issubclass(loggingClass, ILogger), 'loggingClass must subclass ILogger' | |||||
global _LoggerClass | |||||
_LoggerClass = loggingClass | |||||
def setLevel(level=0): | |||||
'''Set Global Logging Level. | |||||
''' | |||||
ILogger.level = level | |||||
def getLevel(): | |||||
return ILogger.level | |||||
def getLogger(msg): | |||||
'''Return instance of Logging class. | |||||
''' | |||||
return _LoggerClass(msg) |
@@ -1 +0,0 @@ | |||||
#! /usr/bin/env python |
@@ -1,25 +0,0 @@ | |||||
############################################################################ | |||||
# Joshua R. Boverhof, David W. Robertson, LBNL | |||||
# See LBNLCopyright for copyright notice! | |||||
########################################################################### | |||||
import unittest | |||||
import test_wsdl | |||||
""" | |||||
import utils | |||||
TODO: find where the hell is the missing utils package what is supposed to contain the MatchTestLoader() | |||||
import utils | |||||
def makeTestSuite(): | |||||
suite = unittest.TestSuite() | |||||
suite.addTest(test_wsdl.makeTestSuite("services_by_file")) | |||||
return suite | |||||
def main(): | |||||
loader = utils.MatchTestLoader(True, None, "makeTestSuite") | |||||
unittest.main(defaultTest="makeTestSuite", testLoader=loader) | |||||
""" | |||||
if __name__ == "__main__": | |||||
main() |
@@ -1,42 +0,0 @@ | |||||
#!/usr/bin/env python | |||||
############################################################################ | |||||
# Joshua R. Boverhof, David W. Robertson, LBNL | |||||
# See LBNLCopyright for copyright notice! | |||||
########################################################################### | |||||
import unittest | |||||
import tarfile | |||||
import os | |||||
import ConfigParser | |||||
import test_wsdl | |||||
SECTION = 'files' | |||||
CONFIG_FILE = 'config.txt' | |||||
def extractFiles(section, option): | |||||
config = ConfigParser.ConfigParser() | |||||
config.read(CONFIG_FILE) | |||||
archives = config.get(section, option) | |||||
archives = eval(archives) | |||||
for file in archives: | |||||
tar = tarfile.open(file) | |||||
if not os.access(tar.membernames[0], os.R_OK): | |||||
for i in tar.getnames(): | |||||
tar.extract(i) | |||||
def makeTestSuite(): | |||||
suite = unittest.TestSuite() | |||||
suite.addTest(test_wsdl.makeTestSuite("services_by_file")) | |||||
return suite | |||||
def main(): | |||||
extractFiles(SECTION, 'archives') | |||||
unittest.main(defaultTest="makeTestSuite") | |||||
if __name__ == "__main__": | |||||
main() |
@@ -1,33 +0,0 @@ | |||||
#!/usr/bin/env python | |||||
""" | |||||
The main purpose of this file is to run tox only with the current existing python interpretors. | |||||
""" | |||||
import os | |||||
import sys | |||||
import logging | |||||
if __name__ == "__main__": | |||||
log = logging.getLogger() | |||||
# now we'll detect which python interpretors we have on this machine and run the tests for all of them | |||||
#'python2.5':'py25', | |||||
known_pys = { 'python2.6':'py26', 'python2.7':'py27' } # ,'python3':'py3', 'python3.2':'py32', 'python4':'py4'} | |||||
#known_pys = { 'python2.7':'py27' } # ,'python3':'py3', 'python3.2':'py32', 'python4':'py4'} | |||||
detected_pys = set() | |||||
for known_py in known_pys: | |||||
if os.system("which %s >/dev/null" % known_py) == 0: | |||||
detected_pys.add(known_pys[known_py]) | |||||
#detected_pys.add('docs') | |||||
#os.system("python setup.py test") | |||||
cmds = ["autopep8 --ignore=E501 -i *.py tendo/*.py demo/*.py", | |||||
#"pep8", | |||||
"./tox -e %s" % ",".join(detected_pys)] | |||||
for cmd in cmds: | |||||
if os.system(cmd) != 0: | |||||
print("ERROR: Command `%s` failed, testing stopped here." % cmd) | |||||
sys.exit(6) | |||||
@@ -3,41 +3,15 @@ | |||||
# See Copyright for copyright notice! | # See Copyright for copyright notice! | ||||
########################################################################### | ########################################################################### | ||||
########################################################################### | |||||
# Config file for the unit test framework. | |||||
# Sections below. | |||||
########################################################################### | |||||
########################################################################## | |||||
# SECTION [files] - archives of wsdl/xsd files. | |||||
# | |||||
########################################################################## | |||||
[files] | |||||
archives = ('xmethods.tar.gz', 'schema.tar.gz') | |||||
########################################################################## | ########################################################################## | ||||
# SECTION [services_by_file] - all services locally available for | # SECTION [services_by_file] - all services locally available for | ||||
# testing. | # testing. | ||||
########################################################################## | ########################################################################## | ||||
[services_by_file] | [services_by_file] | ||||
ogsi = schema/ogsi/ogsi_service.wsdl | |||||
airport = xmethods/airport.wsdl | |||||
distance = xmethods/Distance.wsdl | |||||
freedb = xmethods/freedb.wsdl | |||||
globalweather = xmethods/globalweather.wsdl | |||||
IHaddock = xmethods/IHaddock.wsdl | |||||
ip2geo = xmethods/ip2geo.wsdl | |||||
magic = xmethods/magic.wsdl | |||||
query = xmethods/query.wsdl | |||||
RateInfo = xmethods/RateInfo.wsdl | |||||
SHA1Encrypt = xmethods/SHA1Encrypt.wsdl | |||||
siteInsepct = xmethods/siteInspect.wsdl | |||||
TemperatureService = xmethods/TemperatureService.wsdl | |||||
usweather = xmethods/usweather.wsdl | |||||
zip2geo = xmethods/zip2geo.wsdl | |||||
SolveSystem = xmethods/SolveSystem.wsdl.xml | |||||
ip2geo = data/ip2geo.wsdl | |||||
zip2geo = data/zip2geo.wsdl | |||||
soapi-dlw = data/soapi-1.63.0-dlw.wsdl | |||||
soapi-re = data/soapi-1.63.0-re.wsdl | |||||
########################################################################## | ########################################################################## | ||||
# SECTION [services_by_http] - | # SECTION [services_by_http] - |
@@ -0,0 +1,144 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<wsdl:definitions xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://ws.cdyne.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://ws.cdyne.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> | |||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Our system uses a multiple sources for resolution. Including a host database, trace route information, and other systems. Resolves IP addresses to Organization, Country, City, and State/Province, Latitude, Longitude. In most US cities it will also provide some extra information such as Area Code, and more.</wsdl:documentation> | |||||
<wsdl:types> | |||||
<s:schema elementFormDefault="qualified" targetNamespace="http://ws.cdyne.com/"> | |||||
<s:element name="ResolveIP"> | |||||
<s:complexType> | |||||
<s:sequence> | |||||
<s:element minOccurs="0" maxOccurs="1" name="ipAddress" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="licenseKey" type="s:string" /> | |||||
</s:sequence> | |||||
</s:complexType> | |||||
</s:element> | |||||
<s:element name="ResolveIPResponse"> | |||||
<s:complexType> | |||||
<s:sequence> | |||||
<s:element minOccurs="0" maxOccurs="1" name="ResolveIPResult" type="tns:IPInformation" /> | |||||
</s:sequence> | |||||
</s:complexType> | |||||
</s:element> | |||||
<s:complexType name="IPInformation"> | |||||
<s:sequence> | |||||
<s:element minOccurs="0" maxOccurs="1" name="City" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="StateProvince" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="Country" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="Organization" type="s:string" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="Latitude" type="s:double" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="Longitude" type="s:double" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="AreaCode" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="TimeZone" type="s:string" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="HasDaylightSavings" type="s:boolean" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="Certainty" type="s:short" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="RegionName" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="CountryCode" type="s:string" /> | |||||
</s:sequence> | |||||
</s:complexType> | |||||
<s:element name="IPInformation" nillable="true" type="tns:IPInformation" /> | |||||
</s:schema> | |||||
</wsdl:types> | |||||
<wsdl:message name="ResolveIPSoapIn"> | |||||
<wsdl:part name="parameters" element="tns:ResolveIP" /> | |||||
</wsdl:message> | |||||
<wsdl:message name="ResolveIPSoapOut"> | |||||
<wsdl:part name="parameters" element="tns:ResolveIPResponse" /> | |||||
</wsdl:message> | |||||
<wsdl:message name="ResolveIPHttpGetIn"> | |||||
<wsdl:part name="ipAddress" type="s:string" /> | |||||
<wsdl:part name="licenseKey" type="s:string" /> | |||||
</wsdl:message> | |||||
<wsdl:message name="ResolveIPHttpGetOut"> | |||||
<wsdl:part name="Body" element="tns:IPInformation" /> | |||||
</wsdl:message> | |||||
<wsdl:message name="ResolveIPHttpPostIn"> | |||||
<wsdl:part name="ipAddress" type="s:string" /> | |||||
<wsdl:part name="licenseKey" type="s:string" /> | |||||
</wsdl:message> | |||||
<wsdl:message name="ResolveIPHttpPostOut"> | |||||
<wsdl:part name="Body" element="tns:IPInformation" /> | |||||
</wsdl:message> | |||||
<wsdl:portType name="IP2GeoSoap"> | |||||
<wsdl:operation name="ResolveIP"> | |||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Use a License Key of 0 for Testing</wsdl:documentation> | |||||
<wsdl:input message="tns:ResolveIPSoapIn" /> | |||||
<wsdl:output message="tns:ResolveIPSoapOut" /> | |||||
</wsdl:operation> | |||||
</wsdl:portType> | |||||
<wsdl:portType name="IP2GeoHttpGet"> | |||||
<wsdl:operation name="ResolveIP"> | |||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Use a License Key of 0 for Testing</wsdl:documentation> | |||||
<wsdl:input message="tns:ResolveIPHttpGetIn" /> | |||||
<wsdl:output message="tns:ResolveIPHttpGetOut" /> | |||||
</wsdl:operation> | |||||
</wsdl:portType> | |||||
<wsdl:portType name="IP2GeoHttpPost"> | |||||
<wsdl:operation name="ResolveIP"> | |||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Use a License Key of 0 for Testing</wsdl:documentation> | |||||
<wsdl:input message="tns:ResolveIPHttpPostIn" /> | |||||
<wsdl:output message="tns:ResolveIPHttpPostOut" /> | |||||
</wsdl:operation> | |||||
</wsdl:portType> | |||||
<wsdl:binding name="IP2GeoSoap" type="tns:IP2GeoSoap"> | |||||
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> | |||||
<wsdl:operation name="ResolveIP"> | |||||
<soap:operation soapAction="http://ws.cdyne.com/ResolveIP" style="document" /> | |||||
<wsdl:input> | |||||
<soap:body use="literal" /> | |||||
</wsdl:input> | |||||
<wsdl:output> | |||||
<soap:body use="literal" /> | |||||
</wsdl:output> | |||||
</wsdl:operation> | |||||
</wsdl:binding> | |||||
<wsdl:binding name="IP2GeoSoap12" type="tns:IP2GeoSoap"> | |||||
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" /> | |||||
<wsdl:operation name="ResolveIP"> | |||||
<soap12:operation soapAction="http://ws.cdyne.com/ResolveIP" style="document" /> | |||||
<wsdl:input> | |||||
<soap12:body use="literal" /> | |||||
</wsdl:input> | |||||
<wsdl:output> | |||||
<soap12:body use="literal" /> | |||||
</wsdl:output> | |||||
</wsdl:operation> | |||||
</wsdl:binding> | |||||
<wsdl:binding name="IP2GeoHttpGet" type="tns:IP2GeoHttpGet"> | |||||
<http:binding verb="GET" /> | |||||
<wsdl:operation name="ResolveIP"> | |||||
<http:operation location="/ResolveIP" /> | |||||
<wsdl:input> | |||||
<http:urlEncoded /> | |||||
</wsdl:input> | |||||
<wsdl:output> | |||||
<mime:mimeXml part="Body" /> | |||||
</wsdl:output> | |||||
</wsdl:operation> | |||||
</wsdl:binding> | |||||
<wsdl:binding name="IP2GeoHttpPost" type="tns:IP2GeoHttpPost"> | |||||
<http:binding verb="POST" /> | |||||
<wsdl:operation name="ResolveIP"> | |||||
<http:operation location="/ResolveIP" /> | |||||
<wsdl:input> | |||||
<mime:content type="application/x-www-form-urlencoded" /> | |||||
</wsdl:input> | |||||
<wsdl:output> | |||||
<mime:mimeXml part="Body" /> | |||||
</wsdl:output> | |||||
</wsdl:operation> | |||||
</wsdl:binding> | |||||
<wsdl:service name="IP2Geo"> | |||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Our system uses a multiple sources for resolution. Including a host database, trace route information, and other systems. Resolves IP addresses to Organization, Country, City, and State/Province, Latitude, Longitude. In most US cities it will also provide some extra information such as Area Code, and more.</wsdl:documentation> | |||||
<wsdl:port name="IP2GeoSoap" binding="tns:IP2GeoSoap"> | |||||
<soap:address location="http://ws.cdyne.com/ip2geo/ip2geo.asmx" /> | |||||
</wsdl:port> | |||||
<wsdl:port name="IP2GeoSoap12" binding="tns:IP2GeoSoap12"> | |||||
<soap12:address location="http://ws.cdyne.com/ip2geo/ip2geo.asmx" /> | |||||
</wsdl:port> | |||||
<wsdl:port name="IP2GeoHttpGet" binding="tns:IP2GeoHttpGet"> | |||||
<http:address location="http://ws.cdyne.com/ip2geo/ip2geo.asmx" /> | |||||
</wsdl:port> | |||||
<wsdl:port name="IP2GeoHttpPost" binding="tns:IP2GeoHttpPost"> | |||||
<http:address location="http://ws.cdyne.com/ip2geo/ip2geo.asmx" /> | |||||
</wsdl:port> | |||||
</wsdl:service> | |||||
</wsdl:definitions> |
@@ -0,0 +1,99 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:s0="http://ws.cdyne.com" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://ws.cdyne.com" xmlns="http://schemas.xmlsoap.org/wsdl/"> | |||||
<types> | |||||
<s:schema elementFormDefault="qualified" targetNamespace="http://ws.cdyne.com"> | |||||
<s:element name="GetLatLong"> | |||||
<s:complexType> | |||||
<s:sequence> | |||||
<s:element minOccurs="0" maxOccurs="1" name="zipcode" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="LicenseKey" type="s:string" /> | |||||
</s:sequence> | |||||
</s:complexType> | |||||
</s:element> | |||||
<s:element name="GetLatLongResponse"> | |||||
<s:complexType> | |||||
<s:sequence> | |||||
<s:element minOccurs="1" maxOccurs="1" name="GetLatLongResult" type="s0:LatLongReturn" /> | |||||
</s:sequence> | |||||
</s:complexType> | |||||
</s:element> | |||||
<s:complexType name="LatLongReturn"> | |||||
<s:sequence> | |||||
<s:element minOccurs="1" maxOccurs="1" name="ServiceError" type="s:boolean" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="AddressError" type="s:boolean" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="City" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="StateAbbrev" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="ZipCode" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="County" type="s:string" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="FromLongitude" type="s:decimal" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="FromLatitude" type="s:decimal" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="ToLongitude" type="s:decimal" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="ToLatitude" type="s:decimal" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="AvgLongitude" type="s:decimal" /> | |||||
<s:element minOccurs="1" maxOccurs="1" name="AvgLatitude" type="s:decimal" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="CMSA" type="s:string" /> | |||||
<s:element minOccurs="0" maxOccurs="1" name="PMSA" type="s:string" /> | |||||
</s:sequence> | |||||
</s:complexType> | |||||
<s:element name="LatLongReturn" type="s0:LatLongReturn" /> | |||||
</s:schema> | |||||
</types> | |||||
<message name="GetLatLongSoapIn"> | |||||
<part name="parameters" element="s0:GetLatLong" /> | |||||
</message> | |||||
<message name="GetLatLongSoapOut"> | |||||
<part name="parameters" element="s0:GetLatLongResponse" /> | |||||
</message> | |||||
<message name="GetLatLongHttpGetIn"> | |||||
<part name="zipcode" type="s:string" /> | |||||
<part name="LicenseKey" type="s:string" /> | |||||
</message> | |||||
<message name="GetLatLongHttpGetOut"> | |||||
<part name="Body" element="s0:LatLongReturn" /> | |||||
</message> | |||||
<message name="GetLatLongHttpPostIn"> | |||||
<part name="zipcode" type="s:string" /> | |||||
<part name="LicenseKey" type="s:string" /> | |||||
</message> | |||||
<message name="GetLatLongHttpPostOut"> | |||||
<part name="Body" element="s0:LatLongReturn" /> | |||||
</message> | |||||
<portType name="Zip2GeoSoap"> | |||||
<operation name="GetLatLong"> | |||||
<documentation>This method will convert a zip code to Longitude and Latitude. You will get better accuracy with the plus 4 added to the zipcode. Use a license key of 0 for testing.</documentation> | |||||
<input message="s0:GetLatLongSoapIn" /> | |||||
<output message="s0:GetLatLongSoapOut" /> | |||||
</operation> | |||||
</portType> | |||||
<portType name="Zip2GeoHttpGet"> | |||||
<operation name="GetLatLong"> | |||||
<documentation>This method will convert a zip code to Longitude and Latitude. You will get better accuracy with the plus 4 added to the zipcode. Use a license key of 0 for testing.</documentation> | |||||
<input message="s0:GetLatLongHttpGetIn" /> | |||||
<output message="s0:GetLatLongHttpGetOut" /> | |||||
</operation> | |||||
</portType> | |||||
<portType name="Zip2GeoHttpPost"> | |||||
<operation name="GetLatLong"> | |||||
<documentation>This method will convert a zip code to Longitude and Latitude. You will get better accuracy with the plus 4 added to the zipcode. Use a license key of 0 for testing.</documentation> | |||||
<input message="s0:GetLatLongHttpPostIn" /> | |||||
<output message="s0:GetLatLongHttpPostOut" /> | |||||
</operation> | |||||
</portType> | |||||
<binding name="Zip2GeoSoap" type="s0:Zip2GeoSoap"> | |||||
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> | |||||
<operation name="GetLatLong"> | |||||
<soap:operation soapAction="http://ws.cdyne.com/GetLatLong" style="document" /> | |||||
<input> | |||||
<soap:body use="literal" /> | |||||
</input> | |||||
<output> | |||||
<soap:body use="literal" /> | |||||
</output> | |||||
</operation> | |||||
</binding> | |||||
<service name="Zip2Geo"> | |||||
<port name="Zip2GeoSoap" binding="s0:Zip2GeoSoap"> | |||||
<soap:address location="http://ws.cdyne.com/ziptogeo/zip2geo.asmx" /> | |||||
</port> | |||||
</service> | |||||
</definitions> |
@@ -13,8 +13,7 @@ from wstools.Utility import DOM | |||||
from wstools.WSDLTools import WSDLReader | from wstools.WSDLTools import WSDLReader | ||||
from wstools.TimeoutSocket import TimeoutError | from wstools.TimeoutSocket import TimeoutError | ||||
from wstools import tests | |||||
cwd = os.path.dirname(tests.__file__) | |||||
cwd = 'tests' | |||||
# that's for tox/pytest | # that's for tox/pytest | ||||
nameGenerator = None | nameGenerator = None | ||||
@@ -31,7 +30,6 @@ def makeTestSuite(section='services_by_file'): | |||||
return suite | return suite | ||||
@unittest.skip("skipping due broken assets") | |||||
class WSDLToolsTestCase(unittest.TestCase): | class WSDLToolsTestCase(unittest.TestCase): | ||||
def __init__(self, methodName='runTest'): | def __init__(self, methodName='runTest'): | ||||
@@ -71,7 +69,7 @@ class WSDLToolsTestCase(unittest.TestCase): | |||||
if self.path[:7] == 'http://': | if self.path[:7] == 'http://': | ||||
self.wsdl = WSDLReader().loadFromURL(self.path) | self.wsdl = WSDLReader().loadFromURL(self.path) | ||||
else: | else: | ||||
self.wsdl = WSDLReader().loadFromFile(self.path) | |||||
self.wsdl = WSDLReader().loadFromFile('tests/' + self.path) | |||||
except TimeoutError: | except TimeoutError: | ||||
print "connection timed out" | print "connection timed out" | ||||
@@ -166,11 +164,3 @@ def setUpOptions(section): | |||||
def getOption(cp, section): | def getOption(cp, section): | ||||
for name, value in cp.items(section): | for name, value in cp.items(section): | ||||
yield value | yield value | ||||
def main(): | |||||
unittest.main(defaultTest="makeTestSuite") | |||||
if __name__ == "__main__": | |||||
main() |
@@ -14,8 +14,9 @@ def makeTestSuite(): | |||||
return suite | return suite | ||||
def main(): | |||||
unittest.main(defaultTest="makeTestSuite") | |||||
def test_runner(): | |||||
runner = unittest.TextTestRunner() | |||||
runner.run(makeTestSuite()) | |||||
if __name__ == "__main__": | if __name__ == "__main__": | ||||
main() | |||||
test_runner() |
@@ -1,46 +0,0 @@ | |||||
#!/bin/bash | |||||
set -e | |||||
if which virtualenv >/dev/null; then | |||||
echo | |||||
else | |||||
sudo easy_install "virtualenv>=1.8.4" | |||||
if [ $? -ne 0 ]; then | |||||
echo "failed to install virtualenv, you'll have to fix this yourself" | |||||
exit 1 | |||||
fi | |||||
fi | |||||
if [ -z "$VIRTUAL_ENV" ] | |||||
then | |||||
virtualenv .tox/tox | |||||
cd .tox/tox | |||||
source bin/activate | |||||
#exit 1 | |||||
fi | |||||
if [ -z "$VIRTUAL_ENV" ] | |||||
then | |||||
echo This script should only be run inside a virtual_env. | |||||
exit 1 | |||||
fi | |||||
easy_install "tox>=1.3" | |||||
#pip install tox --upgrade -v | |||||
# pytest pytest-cov | |||||
python setup.py check --restructuredtext --strict | |||||
autopep8 -i -r src/*.py | |||||
# commented some errors temporarly, TODO: remove them and fix the code | |||||
pep8 --max-line-length=180 --ignore=E502,E128,E123,E127,E125 src | |||||
tox -v $@ | |||||
if [ $? -ne 0 ]; then | |||||
echo "Error: tox returned error code $?" | |||||
else | |||||
echo "Done." | |||||
fi |
@@ -1,43 +1,27 @@ | |||||
[tox] | [tox] | ||||
minversion=1.3 | |||||
envlist = py26,py27 | |||||
#,py27 | |||||
#,py27,py32 | |||||
#,py27,py32 | |||||
addopts = --ignore=setup.py --ignore=.tox --ignore=setuptools --ignore=third | |||||
[pytest] | |||||
rsyncdirs = scripts | |||||
rsyncignore = .hg third | |||||
addopts = -v -v | |||||
[testenv:docs] | |||||
downloadcache={toxworkdir}/downloadcache | |||||
basepython=python | |||||
changedir=doc | |||||
deps=sphinx | |||||
commands= | |||||
sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html | |||||
[tools] | |||||
downloadcache={toxworkdir}/downloadcache | |||||
testing= | |||||
deps= | |||||
minversion = 1.3 | |||||
envlist = py26,py27,py33,py34,flake8 | |||||
[testenv] | [testenv] | ||||
downloadcache={toxworkdir}/downloadcache | |||||
distribute=True | |||||
sitepackages=False | |||||
deps= | deps= | ||||
pytest | |||||
nose | |||||
coveralls | |||||
coverage | |||||
commands= | commands= | ||||
py.test src | |||||
#nosetests | |||||
nosetests --with-coverage --cover-package=wstools | |||||
bash -c "coveralls || true" | |||||
whitelist_externals=bash | |||||
[testenv:py26] | [testenv:py26] | ||||
downloadcache={toxworkdir}/downloadcache | |||||
deps= | |||||
unittest2 | |||||
commands= | |||||
py.test src | |||||
[testenv:py27] | |||||
[testenv:py33] | |||||
[testenv:py34] | |||||
[testenv:flake8] | |||||
basepython=python2.7 | |||||
deps=flake8 | |||||
commands=flake8 wstools/ | |||||
@@ -1,17 +1,17 @@ | |||||
#TODO add the license | |||||
#I had to rewrite this class because the python MIME email.mime (version 2.5) | |||||
#are buggy, they use \n instead \r\n for new line which is not compliant | |||||
#to standard! | |||||
# TODO add the license | |||||
# I had to rewrite this class because the python MIME email.mime (version 2.5) | |||||
# are buggy, they use \n instead \r\n for new line which is not compliant | |||||
# to standard! | |||||
# http://bugs.python.org/issue5525 | # http://bugs.python.org/issue5525 | ||||
#TODO do not load all the message in memory stream it from the disk | |||||
# TODO do not load all the message in memory stream it from the disk | |||||
import re | import re | ||||
import random | import random | ||||
import sys | import sys | ||||
#new line | |||||
# new line | |||||
NL = '\r\n' | NL = '\r\n' | ||||
_width = len(repr(sys.maxint - 1)) | _width = len(repr(sys.maxint - 1)) | ||||
@@ -27,32 +27,33 @@ class MIMEMessage: | |||||
self._boundary = "" | self._boundary = "" | ||||
def makeBoundary(self): | def makeBoundary(self): | ||||
#create the boundary | |||||
# create the boundary | |||||
msgparts = [] | msgparts = [] | ||||
msgparts.append(self._xmlMessage) | msgparts.append(self._xmlMessage) | ||||
for i in self._files: | for i in self._files: | ||||
msgparts.append(i.read()) | msgparts.append(i.read()) | ||||
#this sucks, all in memory | |||||
# this sucks, all in memory | |||||
alltext = NL.join(msgparts) | alltext = NL.join(msgparts) | ||||
self._boundary = _make_boundary(alltext) | self._boundary = _make_boundary(alltext) | ||||
#maybe I can save some memory | |||||
# maybe I can save some memory | |||||
del alltext | del alltext | ||||
del msgparts | del msgparts | ||||
self._startCID = "<" + (_fmt % random.randrange(sys.maxint)) + (_fmt % random.randrange(sys.maxint)) + ">" | |||||
self._startCID = "<" + (_fmt % random.randrange(sys.maxint)) \ | |||||
+ (_fmt % random.randrange(sys.maxint)) + ">" | |||||
def toString(self): | def toString(self): | ||||
'''it return a string with the MIME message''' | '''it return a string with the MIME message''' | ||||
if len(self._boundary) == 0: | if len(self._boundary) == 0: | ||||
#the makeBoundary hasn't been called yet | |||||
# the makeBoundary hasn't been called yet | |||||
self.makeBoundary() | self.makeBoundary() | ||||
#ok we have everything let's start to spit the message out | |||||
#first the XML | |||||
# ok we have everything let's start to spit the message out | |||||
# first the XML | |||||
returnstr = NL + "--" + self._boundary + NL | returnstr = NL + "--" + self._boundary + NL | ||||
returnstr += "Content-Type: text/xml; charset=\"us-ascii\"" + NL | returnstr += "Content-Type: text/xml; charset=\"us-ascii\"" + NL | ||||
returnstr += "Content-Transfer-Encoding: 7bit" + NL | returnstr += "Content-Transfer-Encoding: 7bit" + NL | ||||
returnstr += "Content-Id: " + self._startCID + NL + NL | returnstr += "Content-Id: " + self._startCID + NL + NL | ||||
returnstr += self._xmlMessage + NL | returnstr += self._xmlMessage + NL | ||||
#then the files | |||||
# then the files | |||||
for file in self._files: | for file in self._files: | ||||
returnstr += "--" + self._boundary + NL | returnstr += "--" + self._boundary + NL | ||||
returnstr += "Content-Type: application/octet-stream" + NL | returnstr += "Content-Type: application/octet-stream" + NL | ||||
@@ -60,7 +61,7 @@ class MIMEMessage: | |||||
returnstr += "Content-Id: <" + str(id(file)) + ">" + NL + NL | returnstr += "Content-Id: <" + str(id(file)) + ">" + NL + NL | ||||
file.seek(0) | file.seek(0) | ||||
returnstr += file.read() + NL | returnstr += file.read() + NL | ||||
#closing boundary | |||||
# closing boundary | |||||
returnstr += "--" + self._boundary + "--" + NL | returnstr += "--" + self._boundary + "--" + NL | ||||
return returnstr | return returnstr | ||||
@@ -91,7 +92,7 @@ class MIMEMessage: | |||||
def _make_boundary(text=None): | def _make_boundary(text=None): | ||||
#some code taken from python stdlib | |||||
# some code taken from python stdlib | |||||
# Craft a random boundary. If text is given, ensure that the chosen | # Craft a random boundary. If text is given, ensure that the chosen | ||||
# boundary doesn't appear in the text. | # boundary doesn't appear in the text. | ||||
token = random.randrange(sys.maxint) | token = random.randrange(sys.maxint) |
@@ -46,7 +46,8 @@ except: | |||||
class DSIG: | class DSIG: | ||||
BASE = "http://www.w3.org/2000/09/xmldsig#" | BASE = "http://www.w3.org/2000/09/xmldsig#" | ||||
C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | ||||
C14N_COMM = "http://www.w3.org/TR/2000/CR-xml-c14n-20010315#WithComments" | |||||
C14N_COMM = \ | |||||
"http://www.w3.org/TR/2000/CR-xml-c14n-20010315#WithComments" | |||||
C14N_EXCL = "http://www.w3.org/2001/10/xml-exc-c14n#" | C14N_EXCL = "http://www.w3.org/2001/10/xml-exc-c14n#" | ||||
DIGEST_MD2 = "http://www.w3.org/2000/09/xmldsig#md2" | DIGEST_MD2 = "http://www.w3.org/2000/09/xmldsig#md2" | ||||
DIGEST_MD5 = "http://www.w3.org/2000/09/xmldsig#md5" | DIGEST_MD5 = "http://www.w3.org/2000/09/xmldsig#md5" | ||||
@@ -79,41 +80,55 @@ except: | |||||
class WSRF_V1_2: | class WSRF_V1_2: | ||||
'''OASIS WSRF Specifications Version 1.2 | |||||
''' | |||||
OASIS WSRF Specifications Version 1.2 | |||||
''' | ''' | ||||
class LIFETIME: | |||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd" | |||||
XSD_DRAFT4 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceLifetime-1.2-draft-04.xsd" | |||||
WSDL_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.wsdl" | |||||
WSDL_DRAFT4 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceLifetime-1.2-draft-04.wsdl" | |||||
class LIFETIME: | |||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/" | |||||
"wsrf-WS-ResourceLifetime-1.2-draft-01.xsd" | |||||
XSD_DRAFT4 = "http://docs.oasis-open.org/wsrf/2004/11/" | |||||
"wsrf-WS-ResourceLifetime-1.2-draft-04.xsd" | |||||
WSDL_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/" | |||||
"wsrf-WS-ResourceLifetime-1.2-draft-01.wsdl" | |||||
WSDL_DRAFT4 = "http://docs.oasis-open.org/wsrf/2004/11/" | |||||
"wsrf-WS-ResourceLifetime-1.2-draft-04.wsdl" | |||||
LATEST = WSDL_DRAFT4 | LATEST = WSDL_DRAFT4 | ||||
WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT4) | WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT4) | ||||
XSD_LIST = (XSD_DRAFT1, XSD_DRAFT4) | XSD_LIST = (XSD_DRAFT1, XSD_DRAFT4) | ||||
class PROPERTIES: | class PROPERTIES: | ||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.xsd" | |||||
XSD_DRAFT5 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceProperties-1.2-draft-05.xsd" | |||||
WSDL_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl" | |||||
WSDL_DRAFT5 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceProperties-1.2-draft-05.wsdl" | |||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/" | |||||
"wsrf-WS-ResourceProperties-1.2-draft-01.xsd" | |||||
XSD_DRAFT5 = "http://docs.oasis-open.org/wsrf/2004/11/" | |||||
"wsrf-WS-ResourceProperties-1.2-draft-05.xsd" | |||||
WSDL_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/" | |||||
"wsrf-WS-ResourceProperties-1.2-draft-01.wsdl" | |||||
WSDL_DRAFT5 = "http://docs.oasis-open.org/wsrf/2004/11/" | |||||
"wsrf-WS-ResourceProperties-1.2-draft-05.wsdl" | |||||
LATEST = WSDL_DRAFT5 | LATEST = WSDL_DRAFT5 | ||||
WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT5) | WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT5) | ||||
XSD_LIST = (XSD_DRAFT1, XSD_DRAFT5) | XSD_LIST = (XSD_DRAFT1, XSD_DRAFT5) | ||||
class BASENOTIFICATION: | class BASENOTIFICATION: | ||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsn/2004/06/wsn-WS-BaseNotification-1.2-draft-01.xsd" | |||||
WSDL_DRAFT1 = "http://docs.oasis-open.org/wsn/2004/06/wsn-WS-BaseNotification-1.2-draft-01.wsdl" | |||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsn/2004/06/" | |||||
"wsn-WS-BaseNotification-1.2-draft-01.xsd" | |||||
WSDL_DRAFT1 = "http://docs.oasis-open.org/wsn/2004/06/" | |||||
"wsn-WS-BaseNotification-1.2-draft-01.wsdl" | |||||
LATEST = WSDL_DRAFT1 | LATEST = WSDL_DRAFT1 | ||||
WSDL_LIST = (WSDL_DRAFT1,) | WSDL_LIST = (WSDL_DRAFT1,) | ||||
XSD_LIST = (XSD_DRAFT1,) | XSD_LIST = (XSD_DRAFT1,) | ||||
class BASEFAULTS: | class BASEFAULTS: | ||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-BaseFaults-1.2-draft-01.xsd" | |||||
XSD_DRAFT3 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-BaseFaults-1.2-draft-03.xsd" | |||||
#LATEST = DRAFT3 | |||||
#WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT3) | |||||
XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/" | |||||
"wsrf-WS-BaseFaults-1.2-draft-01.xsd" | |||||
XSD_DRAFT3 = "http://docs.oasis-open.org/wsrf/2004/11/" | |||||
"wsrf-WS-BaseFaults-1.2-draft-03.xsd" | |||||
# LATEST = DRAFT3 | |||||
# WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT3) | |||||
XSD_LIST = (XSD_DRAFT1, XSD_DRAFT3) | XSD_LIST = (XSD_DRAFT1, XSD_DRAFT3) | ||||
WSRF = WSRF_V1_2 | WSRF = WSRF_V1_2 | ||||
@@ -123,16 +138,24 @@ WSRFLIST = (WSRF_V1_2,) | |||||
class OASIS: | class OASIS: | ||||
'''URLs for Oasis specifications | '''URLs for Oasis specifications | ||||
''' | ''' | ||||
WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" | |||||
UTILITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" | |||||
WSSE = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-wssecurity-secext-1.0.xsd" | |||||
UTILITY = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-wssecurity-utility-1.0.xsd" | |||||
class X509TOKEN: | class X509TOKEN: | ||||
Base64Binary = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" | |||||
STRTransform = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0" | |||||
PKCS7 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#PKCS7" | |||||
X509 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509" | |||||
X509PKIPathv1 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1" | |||||
X509v3SubjectKeyIdentifier = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3SubjectKeyIdentifier" | |||||
Base64Binary = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-soap-message-security-1.0#Base64Binary" | |||||
STRTransform = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-soap-message-security-1.0" | |||||
PKCS7 = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-x509-token-profile-1.0#PKCS7" | |||||
X509 = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-x509-token-profile-1.0#X509" | |||||
X509PKIPathv1 = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1" | |||||
X509v3SubjectKeyIdentifier = "http://docs.oasis-open.org/wss/2004/01/" | |||||
"oasis-200401-wss-x509-token-profile-1.0#X509v3SubjectKeyIdentifier" | |||||
LIFETIME = WSRF_V1_2.LIFETIME.XSD_DRAFT1 | LIFETIME = WSRF_V1_2.LIFETIME.XSD_DRAFT1 | ||||
PROPERTIES = WSRF_V1_2.PROPERTIES.XSD_DRAFT1 | PROPERTIES = WSRF_V1_2.PROPERTIES.XSD_DRAFT1 | ||||
@@ -141,8 +164,9 @@ class OASIS: | |||||
class APACHE: | class APACHE: | ||||
'''This name space is defined by AXIS and it is used for the TC in TCapache.py, | |||||
Map and file attachment (DataHandler) | |||||
''' | |||||
This name space is defined by AXIS and it is used for the TC in | |||||
TCapache.py, Map and file attachment (DataHandler) | |||||
''' | ''' | ||||
AXIS_NS = "http://xml.apache.org/xml-soap" | AXIS_NS = "http://xml.apache.org/xml-soap" | ||||
@@ -163,8 +187,10 @@ class WSU: | |||||
class WSR: | class WSR: | ||||
PROPERTIES = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties" | |||||
LIFETIME = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime" | |||||
PROPERTIES = \ | |||||
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties" | |||||
LIFETIME = \ | |||||
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime" | |||||
class WSA200508: | class WSA200508: | ||||
@@ -196,7 +222,9 @@ WSA_LIST = (WSA200508, WSA200408, WSA200403, WSA200303) | |||||
class _WSAW(str): | class _WSAW(str): | ||||
""" Define ADDRESS attribute to be compatible with WSA* layout """ | |||||
""" | |||||
Define ADDRESS attribute to be compatible with WSA* layout | |||||
""" | |||||
ADDRESS = property(lambda s: s) | ADDRESS = property(lambda s: s) | ||||
WSAW200605 = _WSAW("http://www.w3.org/2006/05/addressing/wsdl") | WSAW200605 = _WSAW("http://www.w3.org/2006/05/addressing/wsdl") |
@@ -15,7 +15,6 @@ | |||||
ident = "$Id$" | ident = "$Id$" | ||||
import string | |||||
import socket | import socket | ||||
import select | import select | ||||
import errno | import errno | ||||
@@ -24,7 +23,10 @@ WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022) | |||||
class TimeoutSocket: | class TimeoutSocket: | ||||
"""A socket imposter that supports timeout limits.""" | |||||
""" | |||||
A socket imposter that supports timeout limits. | |||||
""" | |||||
def __init__(self, timeout=20, sock=None): | def __init__(self, timeout=20, sock=None): | ||||
self.timeout = float(timeout) | self.timeout = float(timeout) | ||||
@@ -57,9 +59,8 @@ class TimeoutSocket: | |||||
code = 0 | code = 0 | ||||
else: | else: | ||||
code, why = why | code, why = why | ||||
if code not in ( | |||||
errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK | |||||
): | |||||
if code not in \ | |||||
(errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): | |||||
raise | raise | ||||
r, w, e = select.select([], [sock], [], timeout) | r, w, e = select.select([], [sock], [], timeout) | ||||
if w: | if w: |
@@ -3,7 +3,8 @@ A more or less complete user-defined wrapper around tuple objects. | |||||
Adapted version of the standard library's UserList. | Adapted version of the standard library's UserList. | ||||
Taken from Stefan Schwarzer's ftputil library, available at | Taken from Stefan Schwarzer's ftputil library, available at | ||||
<http://www.ndh.net/home/sschwarzer/python/python_software.html>, and used under this license: | |||||
<http://www.ndh.net/home/sschwarzer/python/python_software.html>, | |||||
and used under this license: | |||||
@@ -43,11 +44,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
# $Id$ | # $Id$ | ||||
#XXX tuple instances (in Python 2.2) contain also: | |||||
# XXX tuple instances (in Python 2.2) contain also: | |||||
# __class__, __delattr__, __getattribute__, __hash__, __new__, | # __class__, __delattr__, __getattribute__, __hash__, __new__, | ||||
# __reduce__, __setattr__, __str__ | # __reduce__, __setattr__, __str__ | ||||
# What about these? | # What about these? | ||||
class UserTuple: | class UserTuple: | ||||
def __init__(self, inittuple=None): | def __init__(self, inittuple=None): | ||||
self.data = () | self.data = () | ||||
if inittuple is not None: | if inittuple is not None: |
@@ -17,17 +17,33 @@ ident = "$Id$" | |||||
import sys | import sys | ||||
import types | import types | ||||
import httplib | |||||
import urllib | |||||
import socket | import socket | ||||
import weakref | import weakref | ||||
from os.path import isfile | from os.path import isfile | ||||
from string import join, strip, split | from string import join, strip, split | ||||
from UserDict import UserDict | from UserDict import UserDict | ||||
from cStringIO import StringIO | |||||
from TimeoutSocket import TimeoutSocket, TimeoutError | |||||
from urlparse import urlparse | |||||
from httplib import HTTPConnection, HTTPSConnection | |||||
import urllib | |||||
from .TimeoutSocket import TimeoutSocket, TimeoutError | |||||
try: | |||||
from io import StringIO | |||||
except ImportError: | |||||
from cStringIO import StringIO | |||||
try: | |||||
from urlparse import urlparse | |||||
except ImportError: | |||||
from urllib.parse import urlparse | |||||
try: | |||||
from httplib import HTTPConnection, HTTPSConnection | |||||
except ImportError: | |||||
from http.client import HTTPConnection, HTTPSConnection | |||||
from exceptions import Exception | from exceptions import Exception | ||||
try: | try: | ||||
from ZSI import _get_idstr | from ZSI import _get_idstr | ||||
@@ -91,28 +107,35 @@ if sys.version_info[0:2] < (2, 4, 0, 'final', 0)[0:2]: | |||||
class NamespaceError(Exception): | class NamespaceError(Exception): | ||||
"""Used to indicate a Namespace Error.""" | """Used to indicate a Namespace Error.""" | ||||
class RecursionError(Exception): | class RecursionError(Exception): | ||||
"""Used to indicate a HTTP redirect recursion.""" | """Used to indicate a HTTP redirect recursion.""" | ||||
class ParseError(Exception): | class ParseError(Exception): | ||||
"""Used to indicate a XML parsing error.""" | """Used to indicate a XML parsing error.""" | ||||
class DOMException(Exception): | class DOMException(Exception): | ||||
"""Used to indicate a problem processing DOM.""" | """Used to indicate a problem processing DOM.""" | ||||
class Base: | class Base: | ||||
"""Base class for instance level Logging""" | """Base class for instance level Logging""" | ||||
def __init__(self, module=__name__): | |||||
self.logger = logging.getLogger('%s-%s(%s)' % (module, self.__class__, _get_idstr(self))) | |||||
def __init__(self, logger=None): | |||||
self.logger = logger or logging.getLogger(__name__) | |||||
class HTTPResponse: | class HTTPResponse: | ||||
"""Captures the information in an HTTP response message.""" | """Captures the information in an HTTP response message.""" | ||||
def __init__(self, response): | def __init__(self, response): | ||||
@@ -124,7 +147,9 @@ class HTTPResponse: | |||||
class TimeoutHTTP(HTTPConnection): | class TimeoutHTTP(HTTPConnection): | ||||
"""A custom http connection object that supports socket timeout.""" | """A custom http connection object that supports socket timeout.""" | ||||
def __init__(self, host, port=None, timeout=20): | def __init__(self, host, port=None, timeout=20): | ||||
HTTPConnection.__init__(self, host, port) | HTTPConnection.__init__(self, host, port) | ||||
self.timeout = timeout | self.timeout = timeout | ||||
@@ -135,12 +160,14 @@ class TimeoutHTTP(HTTPConnection): | |||||
class TimeoutHTTPS(HTTPSConnection): | class TimeoutHTTPS(HTTPSConnection): | ||||
"""A custom https object that supports socket timeout. Note that this | """A custom https object that supports socket timeout. Note that this | ||||
is not really complete. The builtin SSL support in the Python socket | is not really complete. The builtin SSL support in the Python socket | ||||
module requires a real socket (type) to be passed in to be hooked to | module requires a real socket (type) to be passed in to be hooked to | ||||
SSL. That means our fake socket won't work and our timeout hacks are | SSL. That means our fake socket won't work and our timeout hacks are | ||||
bypassed for send and recv calls. Since our hack _is_ in place at | bypassed for send and recv calls. Since our hack _is_ in place at | ||||
connect() time, it should at least provide some timeout protection.""" | connect() time, it should at least provide some timeout protection.""" | ||||
def __init__(self, host, port=None, timeout=20, **kwargs): | def __init__(self, host, port=None, timeout=20, **kwargs): | ||||
HTTPSConnection.__init__(self, str(host), port, **kwargs) | HTTPSConnection.__init__(self, str(host), port, **kwargs) | ||||
self.timeout = timeout | self.timeout = timeout | ||||
@@ -224,15 +251,16 @@ def urlopen(url, timeout=20, redirects=None): | |||||
class DOM: | class DOM: | ||||
"""The DOM singleton defines a number of XML related constants and | """The DOM singleton defines a number of XML related constants and | ||||
provides a number of utility methods for DOM related tasks. It | provides a number of utility methods for DOM related tasks. It | ||||
also provides some basic abstractions so that the rest of the | also provides some basic abstractions so that the rest of the | ||||
package need not care about actual DOM implementation in use.""" | package need not care about actual DOM implementation in use.""" | ||||
looseNamespaces = False # if can't find a referenced namespace, try the default one | |||||
# if can't find a referenced namespace, try the default one | |||||
looseNamespaces = False | |||||
# Namespace stuff related to the SOAP specification. | # Namespace stuff related to the SOAP specification. | ||||
NS_SOAP_ENV_1_1 = 'http://schemas.xmlsoap.org/soap/envelope/' | NS_SOAP_ENV_1_1 = 'http://schemas.xmlsoap.org/soap/envelope/' | ||||
NS_SOAP_ENC_1_1 = 'http://schemas.xmlsoap.org/soap/encoding/' | NS_SOAP_ENC_1_1 = 'http://schemas.xmlsoap.org/soap/encoding/' | ||||
@@ -419,7 +447,7 @@ class DOM: | |||||
if node.nodeType != node.ELEMENT_NODE: | if node.nodeType != node.ELEMENT_NODE: | ||||
return 0 | return 0 | ||||
return node.localName == name and \ | return node.localName == name and \ | ||||
(nsuri is None or self.nsUriMatch(node.namespaceURI, nsuri)) | |||||
(nsuri is None or self.nsUriMatch(node.namespaceURI, nsuri)) | |||||
def getElement(self, node, name, nsuri=None, default=join): | def getElement(self, node, name, nsuri=None, default=join): | ||||
"""Return the first child of node with a matching name and | """Return the first child of node with a matching name and | ||||
@@ -429,8 +457,7 @@ class DOM: | |||||
for child in node.childNodes: | for child in node.childNodes: | ||||
if child.nodeType == ELEMENT_NODE: | if child.nodeType == ELEMENT_NODE: | ||||
if ((child.localName == name or name is None) and | if ((child.localName == name or name is None) and | ||||
(nsuri is None or nsmatch(child.namespaceURI, nsuri)) | |||||
): | |||||
(nsuri is None or nsmatch(child.namespaceURI, nsuri))): | |||||
return child | return child | ||||
if default is not join: | if default is not join: | ||||
return default | return default | ||||
@@ -555,7 +582,8 @@ class DOM: | |||||
if DOM.looseNamespaces: | if DOM.looseNamespaces: | ||||
return self.findTargetNS(orig_node) | return self.findTargetNS(orig_node) | ||||
else: | else: | ||||
raise DOMException('Value for prefix %s not found.' % prefix) | |||||
raise DOMException('Value for prefix %s not found.' | |||||
% prefix) | |||||
def findDefaultNS(self, node): | def findDefaultNS(self, node): | ||||
"""Return the current default namespace uri for the given node.""" | """Return the current default namespace uri for the given node.""" | ||||
@@ -653,7 +681,7 @@ class DOM: | |||||
try: | try: | ||||
result = self.loadDocument(file) | result = self.loadDocument(file) | ||||
except Exception, ex: | |||||
except Exception as ex: | |||||
file.close() | file.close() | ||||
raise ParseError(('Failed to load document %s' % url,) + ex.args) | raise ParseError(('Failed to load document %s' % url,) + ex.args) | ||||
else: | else: | ||||
@@ -664,9 +692,11 @@ DOM = DOM() | |||||
class MessageInterface: | class MessageInterface: | ||||
'''Higher Level Interface, delegates to DOM singleton, must | '''Higher Level Interface, delegates to DOM singleton, must | ||||
be subclassed and implement all methods that throw NotImplementedError. | be subclassed and implement all methods that throw NotImplementedError. | ||||
''' | ''' | ||||
def __init__(self, sw): | def __init__(self, sw): | ||||
'''Constructor, May be extended, do not override. | '''Constructor, May be extended, do not override. | ||||
sw -- soapWriter instance | sw -- soapWriter instance | ||||
@@ -725,8 +755,7 @@ class MessageInterface: | |||||
class ElementProxy(Base, MessageInterface): | class ElementProxy(Base, MessageInterface): | ||||
''' | |||||
''' | |||||
_soap_env_prefix = 'SOAP-ENV' | _soap_env_prefix = 'SOAP-ENV' | ||||
_soap_enc_prefix = 'SOAP-ENC' | _soap_enc_prefix = 'SOAP-ENC' | ||||
_zsi_prefix = 'ZSI' | _zsi_prefix = 'ZSI' | ||||
@@ -743,11 +772,11 @@ class ElementProxy(Base, MessageInterface): | |||||
_xml_nsuri = XMLNS.XML | _xml_nsuri = XMLNS.XML | ||||
_xmlns_nsuri = XMLNS.BASE | _xmlns_nsuri = XMLNS.BASE | ||||
standard_ns = {\ | |||||
standard_ns = { | |||||
_xml_prefix: _xml_nsuri, | _xml_prefix: _xml_nsuri, | ||||
_xmlns_prefix: _xmlns_nsuri | _xmlns_prefix: _xmlns_nsuri | ||||
} | } | ||||
reserved_ns = {\ | |||||
reserved_ns = { | |||||
_soap_env_prefix: _soap_env_nsuri, | _soap_env_prefix: _soap_env_nsuri, | ||||
_soap_enc_prefix: _soap_enc_nsuri, | _soap_enc_prefix: _soap_enc_nsuri, | ||||
_zsi_prefix: _zsi_nsuri, | _zsi_prefix: _zsi_nsuri, | ||||
@@ -783,9 +812,11 @@ class ElementProxy(Base, MessageInterface): | |||||
''' | ''' | ||||
from Ft.Xml import XPath | from Ft.Xml import XPath | ||||
if not processorNss: | if not processorNss: | ||||
context = XPath.Context.Context(self.node, processorNss=self.processorNss) | |||||
context = XPath.Context.Context(self.node, | |||||
processorNss=self.processorNss) | |||||
else: | else: | ||||
context = XPath.Context.Context(self.node, processorNss=processorNss) | |||||
context = XPath.Context.Context(self.node, | |||||
processorNss=processorNss) | |||||
nodes = expression.evaluate(context) | nodes = expression.evaluate(context) | ||||
return map(lambda node: ElementProxy(self.sw, node), nodes) | return map(lambda node: ElementProxy(self.sw, node), nodes) | ||||
@@ -804,7 +835,8 @@ class ElementProxy(Base, MessageInterface): | |||||
if localName and self.node: | if localName and self.node: | ||||
check = self._dom.isElement(self.node, localName, namespaceURI) | check = self._dom.isElement(self.node, localName, namespaceURI) | ||||
if not check: | if not check: | ||||
raise NamespaceError('unexpected node type %s, expecting %s' % (self.node, localName)) | |||||
raise NamespaceError('unexpected node type %s, expecting %s' | |||||
% (self.node, localName)) | |||||
def setNode(self, node=None): | def setNode(self, node=None): | ||||
if node: | if node: | ||||
@@ -813,13 +845,15 @@ class ElementProxy(Base, MessageInterface): | |||||
else: | else: | ||||
self.node = node | self.node = node | ||||
elif self.node: | elif self.node: | ||||
node = self._dom.getElement(self.node, self.name, self.namespaceURI, default=None) | |||||
node = self._dom.getElement(self.node, self.name, | |||||
self.namespaceURI, default=None) | |||||
if not node: | if not node: | ||||
raise NamespaceError('cant find element (%s, %s)' % (self.namespaceURI, self.name)) | |||||
raise NamespaceError('cant find element (%s, %s)' % | |||||
(self.namespaceURI, self.name)) | |||||
self.node = node | self.node = node | ||||
else: | else: | ||||
#self.node = self._dom.create(self.node, self.name, self.namespaceURI, default=None) | |||||
self.createDocument(self.namespaceURI, localName=self.name, doctype=None) | |||||
self.createDocument(self.namespaceURI, localName=self.name, | |||||
doctype=None) | |||||
self.checkNode() | self.checkNode() | ||||
@@ -845,7 +879,7 @@ class ElementProxy(Base, MessageInterface): | |||||
prefix = 'ns%d' % self._indx | prefix = 'ns%d' % self._indx | ||||
try: | try: | ||||
self._dom.findNamespaceURI(prefix, self._getNode()) | self._dom.findNamespaceURI(prefix, self._getNode()) | ||||
except DOMException, ex: | |||||
except DOMException as ex: | |||||
break | break | ||||
return prefix | return prefix | ||||
@@ -857,9 +891,9 @@ class ElementProxy(Base, MessageInterface): | |||||
''' | ''' | ||||
try: | try: | ||||
if node and (node.nodeType == node.ELEMENT_NODE) and \ | if node and (node.nodeType == node.ELEMENT_NODE) and \ | ||||
(nsuri == self._dom.findDefaultNS(node)): | |||||
(nsuri == self._dom.findDefaultNS(node)): | |||||
return None | return None | ||||
except DOMException, ex: | |||||
except DOMException as ex: | |||||
pass | pass | ||||
if nsuri == XMLNS.XML: | if nsuri == XMLNS.XML: | ||||
return self._xml_prefix | return self._xml_prefix | ||||
@@ -910,7 +944,7 @@ class ElementProxy(Base, MessageInterface): | |||||
def getPrefix(self, namespaceURI): | def getPrefix(self, namespaceURI): | ||||
try: | try: | ||||
prefix = self._getPrefix(node=self.node, nsuri=namespaceURI) | prefix = self._getPrefix(node=self.node, nsuri=namespaceURI) | ||||
except NamespaceError, ex: | |||||
except NamespaceError as ex: | |||||
prefix = self._getUniquePrefix() | prefix = self._getUniquePrefix() | ||||
self.setNamespaceAttribute(prefix, namespaceURI) | self.setNamespaceAttribute(prefix, namespaceURI) | ||||
return prefix | return prefix | ||||
@@ -942,7 +976,8 @@ class ElementProxy(Base, MessageInterface): | |||||
return self.canonicalize() | return self.canonicalize() | ||||
def createDocument(self, namespaceURI, localName, doctype=None): | def createDocument(self, namespaceURI, localName, doctype=None): | ||||
'''If specified must be a SOAP envelope, else may contruct an empty document. | |||||
'''If specified must be a SOAP envelope, else may contruct an empty | |||||
document. | |||||
''' | ''' | ||||
prefix = self._soap_env_prefix | prefix = self._soap_env_prefix | ||||
@@ -952,22 +987,27 @@ class ElementProxy(Base, MessageInterface): | |||||
self.node = self._dom.createDocument(None, None, None) | self.node = self._dom.createDocument(None, None, None) | ||||
return | return | ||||
else: | else: | ||||
raise KeyError('only support creation of document in %s' % self.reserved_ns[prefix]) | |||||
raise KeyError('only support creation of document in %s' % | |||||
self.reserved_ns[prefix]) | |||||
document = self._dom.createDocument(nsuri=namespaceURI, qname=qualifiedName, doctype=doctype) | |||||
document = self._dom.createDocument(nsuri=namespaceURI, | |||||
qname=qualifiedName, | |||||
doctype=doctype) | |||||
self.node = document.childNodes[0] | self.node = document.childNodes[0] | ||||
#set up reserved namespace attributes | #set up reserved namespace attributes | ||||
for prefix, nsuri in self.reserved_ns.items(): | for prefix, nsuri in self.reserved_ns.items(): | ||||
self._setAttributeNS(namespaceURI=self._xmlns_nsuri, | self._setAttributeNS(namespaceURI=self._xmlns_nsuri, | ||||
qualifiedName='%s:%s' % (self._xmlns_prefix, prefix), | |||||
value=nsuri) | |||||
qualifiedName='%s:%s' % (self._xmlns_prefix, | |||||
prefix), | |||||
value=nsuri) | |||||
############################################# | ############################################# | ||||
#Methods for attributes | #Methods for attributes | ||||
############################################# | ############################################# | ||||
def hasAttribute(self, namespaceURI, localName): | def hasAttribute(self, namespaceURI, localName): | ||||
return self._dom.hasAttr(self._getNode(), name=localName, nsuri=namespaceURI) | |||||
return self._dom.hasAttr(self._getNode(), name=localName, | |||||
nsuri=namespaceURI) | |||||
def setAttributeType(self, namespaceURI, localName): | def setAttributeType(self, namespaceURI, localName): | ||||
'''set xsi:type | '''set xsi:type | ||||
@@ -1001,7 +1041,7 @@ class ElementProxy(Base, MessageInterface): | |||||
if namespaceURI: | if namespaceURI: | ||||
try: | try: | ||||
prefix = self.getPrefix(namespaceURI) | prefix = self.getPrefix(namespaceURI) | ||||
except KeyError, ex: | |||||
except KeyError as ex: | |||||
prefix = 'ns2' | prefix = 'ns2' | ||||
self.setNamespaceAttribute(prefix, namespaceURI) | self.setNamespaceAttribute(prefix, namespaceURI) | ||||
qualifiedName = localName | qualifiedName = localName | ||||
@@ -1074,7 +1114,8 @@ class ElementProxy(Base, MessageInterface): | |||||
if prefix: | if prefix: | ||||
qualifiedName = '%s:%s' % (prefix, localName) | qualifiedName = '%s:%s' % (prefix, localName) | ||||
node = self.createElementNS(namespaceURI, qualifiedName) | node = self.createElementNS(namespaceURI, qualifiedName) | ||||
self._insertBefore(newChild=node._getNode(), refChild=refChild._getNode()) | |||||
self._insertBefore(newChild=node._getNode(), | |||||
refChild=refChild._getNode()) | |||||
return node | return node | ||||
def getElement(self, namespaceURI, localName): | def getElement(self, namespaceURI, localName): | ||||
@@ -1083,7 +1124,8 @@ class ElementProxy(Base, MessageInterface): | |||||
namespaceURI -- namespace of element | namespaceURI -- namespace of element | ||||
localName -- local name of element | localName -- local name of element | ||||
''' | ''' | ||||
node = self._dom.getElement(self.node, localName, namespaceURI, default=None) | |||||
node = self._dom.getElement(self.node, localName, namespaceURI, | |||||
default=None) | |||||
if node: | if node: | ||||
return ElementProxy(self.sw, node) | return ElementProxy(self.sw, node) | ||||
return None | return None | ||||
@@ -1137,6 +1179,7 @@ class ElementProxy(Base, MessageInterface): | |||||
class Collection(UserDict): | class Collection(UserDict): | ||||
"""Helper class for maintaining ordered named collections.""" | """Helper class for maintaining ordered named collections.""" | ||||
default = lambda self, k: k.name | default = lambda self, k: k.name | ||||
@@ -1147,7 +1190,8 @@ class Collection(UserDict): | |||||
self._func = key or self.default | self._func = key or self.default | ||||
def __getitem__(self, key): | def __getitem__(self, key): | ||||
NumberTypes = (types.IntType, types.LongType, types.FloatType, types.ComplexType) | |||||
NumberTypes = (types.IntType, types.LongType, types.FloatType, | |||||
types.ComplexType) | |||||
if isinstance(key, NumberTypes): | if isinstance(key, NumberTypes): | ||||
return self.list[key] | return self.list[key] | ||||
return self.data[key] | return self.data[key] | ||||
@@ -1168,7 +1212,9 @@ class Collection(UserDict): | |||||
class CollectionNS(UserDict): | class CollectionNS(UserDict): | ||||
"""Helper class for maintaining ordered named collections.""" | """Helper class for maintaining ordered named collections.""" | ||||
default = lambda self, k: k.name | default = lambda self, k: k.name | ||||
def __init__(self, parent, key=None): | def __init__(self, parent, key=None): | ||||
@@ -1190,18 +1236,21 @@ class CollectionNS(UserDict): | |||||
def __setitem__(self, key, item): | def __setitem__(self, key, item): | ||||
item.parent = weakref.ref(self) | item.parent = weakref.ref(self) | ||||
self.list.append(item) | self.list.append(item) | ||||
targetNamespace = getattr(item, 'targetNamespace', self.parent().targetNamespace) | |||||
targetNamespace = getattr(item, 'targetNamespace', | |||||
self.parent().targetNamespace) | |||||
if not targetNamespace in self.data: | if not targetNamespace in self.data: | ||||
self.data[targetNamespace] = {} | self.data[targetNamespace] = {} | ||||
self.data[targetNamespace][key] = item | self.data[targetNamespace][key] = item | ||||
def __isSequence(self, key): | def __isSequence(self, key): | ||||
return (type(key) in (types.TupleType, types.ListType) and len(key) == 2) | |||||
return (type(key) in (types.TupleType, types.ListType) | |||||
and len(key) == 2) | |||||
def keys(self): | def keys(self): | ||||
keys = [] | keys = [] | ||||
for tns in self.data.keys(): | for tns in self.data.keys(): | ||||
keys.append(map(lambda i: (tns, self._func(i)), self.data[tns].values())) | |||||
keys.append(map(lambda i: (tns, self._func(i)), | |||||
self.data[tns].values())) | |||||
return keys | return keys | ||||
def items(self): | def items(self): | ||||
@@ -1294,8 +1343,10 @@ if 1: | |||||
# prefixed attribute names during cloning. | # prefixed attribute names during cloning. | ||||
# | # | ||||
# key (attr.namespaceURI, tag) | # key (attr.namespaceURI, tag) | ||||
# ('http://www.w3.org/2000/xmlns/', u'xsd') <xml.dom.minidom.Attr instance at 0x82227c4> | |||||
# ('http://www.w3.org/2000/xmlns/', 'xmlns') <xml.dom.minidom.Attr instance at 0x8414b3c> | |||||
# ('http://www.w3.org/2000/xmlns/', u'xsd') | |||||
# <xml.dom.minidom.Attr instance at 0x82227c4> | |||||
# ('http://www.w3.org/2000/xmlns/', 'xmlns') | |||||
# <xml.dom.minidom.Attr instance at 0x8414b3c> | |||||
# | # | ||||
# xml.dom.minidom.Attr.nodeName = xmlns:xsd | # xml.dom.minidom.Attr.nodeName = xmlns:xsd | ||||
# xml.dom.minidom.Attr.value = = http://www.w3.org/2001/XMLSchema | # xml.dom.minidom.Attr.value = = http://www.w3.org/2001/XMLSchema | ||||
@@ -1314,7 +1365,8 @@ if 1: | |||||
clone = newOwnerDocument.createElementNS(node.namespaceURI, | clone = newOwnerDocument.createElementNS(node.namespaceURI, | ||||
node.nodeName) | node.nodeName) | ||||
for attr in node.attributes.values(): | for attr in node.attributes.values(): | ||||
clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value) | |||||
clone.setAttributeNS(attr.namespaceURI, attr.nodeName, | |||||
attr.value) | |||||
prefix, tag = xml.dom.minidom._nssplit(attr.nodeName) | prefix, tag = xml.dom.minidom._nssplit(attr.nodeName) | ||||
if prefix == 'xmlns': | if prefix == 'xmlns': | ||||
@@ -1322,18 +1374,21 @@ if 1: | |||||
elif prefix: | elif prefix: | ||||
a = clone.getAttributeNodeNS(attr.namespaceURI, tag) | a = clone.getAttributeNodeNS(attr.namespaceURI, tag) | ||||
else: | else: | ||||
a = clone.getAttributeNodeNS(attr.namespaceURI, attr.nodeName) | |||||
a = clone.getAttributeNodeNS(attr.namespaceURI, | |||||
attr.nodeName) | |||||
a.specified = attr.specified | a.specified = attr.specified | ||||
if deep: | if deep: | ||||
for child in node.childNodes: | for child in node.childNodes: | ||||
c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument) | |||||
c = xml.dom.minidom._clone_node(child, deep, | |||||
newOwnerDocument) | |||||
clone.appendChild(c) | clone.appendChild(c) | ||||
elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_FRAGMENT_NODE: | elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_FRAGMENT_NODE: | ||||
clone = newOwnerDocument.createDocumentFragment() | clone = newOwnerDocument.createDocumentFragment() | ||||
if deep: | if deep: | ||||
for child in node.childNodes: | for child in node.childNodes: | ||||
c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument) | |||||
c = xml.dom.minidom._clone_node(child, deep, | |||||
newOwnerDocument) | |||||
clone.appendChild(c) | clone.appendChild(c) | ||||
elif node.nodeType == xml.dom.minidom.Node.TEXT_NODE: | elif node.nodeType == xml.dom.minidom.Node.TEXT_NODE: | ||||
@@ -1360,14 +1415,16 @@ if 1: | |||||
clone.entities._seq = [] | clone.entities._seq = [] | ||||
clone.notations._seq = [] | clone.notations._seq = [] | ||||
for n in node.notations._seq: | for n in node.notations._seq: | ||||
notation = xml.dom.minidom.Notation(n.nodeName, n.publicId, n.systemId) | |||||
notation = xml.dom.minidom.Notation(n.nodeName, n.publicId, | |||||
n.systemId) | |||||
notation.ownerDocument = newOwnerDocument | notation.ownerDocument = newOwnerDocument | ||||
clone.notations._seq.append(notation) | clone.notations._seq.append(notation) | ||||
if hasattr(n, '_call_user_data_handler'): | if hasattr(n, '_call_user_data_handler'): | ||||
n._call_user_data_handler(operation, n, notation) | n._call_user_data_handler(operation, n, notation) | ||||
for e in node.entities._seq: | for e in node.entities._seq: | ||||
entity = xml.dom.minidom.Entity(e.nodeName, e.publicId, e.systemId, | |||||
e.notationName) | |||||
entity = xml.dom.minidom.Entity(e.nodeName, e.publicId, | |||||
e.systemId, | |||||
e.notationName) | |||||
entity.actualEncoding = e.actualEncoding | entity.actualEncoding = e.actualEncoding | ||||
entity.encoding = e.encoding | entity.encoding = e.encoding | ||||
entity.version = e.version | entity.version = e.version |
@@ -10,10 +10,14 @@ | |||||
ident = "$Id$" | ident = "$Id$" | ||||
import weakref | import weakref | ||||
from cStringIO import StringIO | |||||
from Namespaces import OASIS, XMLNS, WSA, WSA_LIST, WSAW_LIST, WSRF_V1_2, WSRF | |||||
from Utility import Collection, CollectionNS, DOM, ElementProxy, basejoin | |||||
from XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter | |||||
try: | |||||
from io import StringIO | |||||
except ImportError: | |||||
from cStringIO import StringIO | |||||
from .Namespaces import OASIS, XMLNS, WSA, WSA_LIST, WSAW_LIST, WSRF_V1_2, WSRF | |||||
from .Utility import Collection, CollectionNS, DOM, ElementProxy, basejoin | |||||
from .XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter | |||||
class WSDLReader: | class WSDLReader: | ||||
@@ -1567,6 +1571,7 @@ class HeaderInfo(ParameterInfo): | |||||
def callInfoFromWSDL(port, name): | def callInfoFromWSDL(port, name): | ||||
logger = logging.getLogger(__name__) | |||||
"""Return a SOAPCallInfo given a WSDL port and operation name.""" | """Return a SOAPCallInfo given a WSDL port and operation name.""" | ||||
wsdl = port.getService().getWSDL() | wsdl = port.getService().getWSDL() | ||||
binding = port.getBinding() | binding = port.getBinding() | ||||
@@ -1643,10 +1648,9 @@ def callInfoFromWSDL(port, name): | |||||
operation.output.message) | operation.output.message) | ||||
else: | else: | ||||
message = wsdl.addMessage(operation.output.message) | message = wsdl.addMessage(operation.output.message) | ||||
print "Warning:", \ | |||||
"Recieved message not defined in the WSDL schema.", \ | |||||
"Adding it." | |||||
print "Message:", operation.output.message | |||||
logger.warning("Warning: Received message not defined in the " | |||||
"WSDL schema. Adding it.") | |||||
logger.warning("Message:", operation.output.message) | |||||
msgrole = opbinding.output | msgrole = opbinding.output | ||||
@@ -289,7 +289,7 @@ class DOMAdapter(DOMAdapterInterface): | |||||
else: | else: | ||||
try: | try: | ||||
namespace = DOM.findNamespaceURI(prefix, self.__node) | namespace = DOM.findNamespaceURI(prefix, self.__node) | ||||
except DOMException, ex: | |||||
except DOMException as ex: | |||||
if prefix != 'xml': | if prefix != 'xml': | ||||
raise SchemaError('%s namespace not declared for %s' % (prefix, self.__node._get_tagName())) | raise SchemaError('%s namespace not declared for %s' % (prefix, self.__node._get_tagName())) | ||||
namespace = XMLNS.XML | namespace = XMLNS.XML | ||||
@@ -629,7 +629,7 @@ class XMLSchemaComponent(XMLBase, MarkerInterface): | |||||
if parent.targetNamespace == namespace: | if parent.targetNamespace == namespace: | ||||
try: | try: | ||||
obj = getattr(parent, collection)[name] | obj = getattr(parent, collection)[name] | ||||
except KeyError, ex: | |||||
except KeyError as ex: | |||||
raise KeyError('targetNamespace(%s) collection(%s) has no item(%s)' % (namespace, collection, name)) | raise KeyError('targetNamespace(%s) collection(%s) has no item(%s)' % (namespace, collection, name)) | ||||
return obj | return obj | ||||
@@ -662,7 +662,7 @@ class XMLSchemaComponent(XMLBase, MarkerInterface): | |||||
try: | try: | ||||
obj = getattr(schema, collection)[name] | obj = getattr(schema, collection)[name] | ||||
except KeyError, ex: | |||||
except KeyError as ex: | |||||
raise KeyError('targetNamespace(%s) collection(%s) has no item(%s)' % (namespace, collection, name)) | raise KeyError('targetNamespace(%s) collection(%s) has no item(%s)' % (namespace, collection, name)) | ||||
return obj | return obj | ||||
@@ -1029,7 +1029,7 @@ class XMLSchema(XMLSchemaComponent): | |||||
empty_namespace = '' | empty_namespace = '' | ||||
tag = 'schema' | tag = 'schema' | ||||
def __init__(self, parent=None): | |||||
def __init__(self, parent=None, logger=None): | |||||
"""parent -- | """parent -- | ||||
instance variables: | instance variables: | ||||
targetNamespace -- schema's declared targetNamespace, or empty string. | targetNamespace -- schema's declared targetNamespace, or empty string. | ||||
@@ -1067,7 +1067,7 @@ class XMLSchema(XMLSchemaComponent): | |||||
self._imported_schemas = {} | self._imported_schemas = {} | ||||
self._included_schemas = {} | self._included_schemas = {} | ||||
self._base_url = None | self._base_url = None | ||||
self.logger = logging.getLogger('wstools') | |||||
self.logger = logger or logging.getLogger(__name__) | |||||
def getNode(self): | def getNode(self): | ||||
""" | """ | ||||
@@ -1228,13 +1228,13 @@ class XMLSchema(XMLSchemaComponent): | |||||
slocd[import_ns] = schema | slocd[import_ns] = schema | ||||
try: | try: | ||||
tp.loadSchema(schema) | tp.loadSchema(schema) | ||||
except NoSchemaLocationWarning, ex: | |||||
except NoSchemaLocationWarning as ex: | |||||
# Dependency declaration, hopefully implementation | # Dependency declaration, hopefully implementation | ||||
# is aware of this namespace (eg. SOAP,WSDL,?) | # is aware of this namespace (eg. SOAP,WSDL,?) | ||||
self.logger.debug("IMPORT: %s : %s" % (import_ns, ex)) | self.logger.debug("IMPORT: %s : %s" % (import_ns, ex)) | ||||
del slocd[import_ns] | del slocd[import_ns] | ||||
continue | continue | ||||
except SchemaError, ex: | |||||
except SchemaError as ex: | |||||
#warnings.warn(\ | #warnings.warn(\ | ||||
# '<import namespace="%s" schemaLocation=?>, %s'\ | # '<import namespace="%s" schemaLocation=?>, %s'\ | ||||
# %(import_ns, 'failed to load schema instance') | # %(import_ns, 'failed to load schema instance') |
@@ -3,6 +3,5 @@ | |||||
ident = "$Id$" | ident = "$Id$" | ||||
import WSDLTools | |||||
import XMLname | |||||
import logging | |||||
from . import WSDLTools | |||||
from . import XMLname |
@@ -55,13 +55,13 @@ except: | |||||
class XMLNS: | class XMLNS: | ||||
BASE = "http://www.w3.org/2000/xmlns/" | BASE = "http://www.w3.org/2000/xmlns/" | ||||
XML = "http://www.w3.org/XML/1998/namespace" | XML = "http://www.w3.org/XML/1998/namespace" | ||||
try: | try: | ||||
import cStringIO | |||||
StringIO = cStringIO | |||||
from io import StringIO | |||||
except ImportError: | except ImportError: | ||||
import StringIO | |||||
from cStringIO import StringIO | |||||
_attrs = lambda E: (E.attributes and E.attributes.values()) or [] | |||||
_attrs = lambda E: (E.attributes and list(E.attributes.values())) or [] | |||||
_children = lambda E: E.childNodes or [] | _children = lambda E: E.childNodes or [] | ||||
_IN_XML_NS = lambda n: n.name.startswith("xmlns") | _IN_XML_NS = lambda n: n.name.startswith("xmlns") | ||||
_inclusive = lambda n: n.unsuppressedPrefixes is None | _inclusive = lambda n: n.unsuppressedPrefixes is None | ||||
@@ -69,7 +69,7 @@ _inclusive = lambda n: n.unsuppressedPrefixes is None | |||||
# Does a document/PI has lesser/greater document order than the | # Does a document/PI has lesser/greater document order than the | ||||
# first element? | # first element? | ||||
_LesserElement, _Element, _GreaterElement = range(3) | |||||
_LesserElement, _Element, _GreaterElement = list(range(3)) | |||||
def _sorter(n1, n2): | def _sorter(n1, n2): | ||||
@@ -191,7 +191,7 @@ class _implementation: | |||||
canonicalization.''' | canonicalization.''' | ||||
# Collect the initial list of xml:foo attributes. | # Collect the initial list of xml:foo attributes. | ||||
xmlattrs = filter(_IN_XML_NS, _attrs(node)) | |||||
xmlattrs = list(filter(_IN_XML_NS, _attrs(node))) | |||||
# Walk up and get all xml:XXX attributes we inherit. | # Walk up and get all xml:XXX attributes we inherit. | ||||
inherited, parent = [], node.parentNode | inherited, parent = [], node.parentNode | ||||
@@ -367,7 +367,7 @@ class _implementation: | |||||
# Create list of NS attributes to render. | # Create list of NS attributes to render. | ||||
ns_to_render = [] | ns_to_render = [] | ||||
for n, v in ns_local.items(): | |||||
for n, v in list(ns_local.items()): | |||||
# If default namespace is XMLNS.BASE or empty, | # If default namespace is XMLNS.BASE or empty, | ||||
# and if an ancestor was the same | # and if an ancestor was the same | ||||
@@ -384,7 +384,7 @@ class _implementation: | |||||
# If not previously rendered | # If not previously rendered | ||||
# and it's inclusive or utilized | # and it's inclusive or utilized | ||||
if (n, v) not in ns_rendered.items(): | |||||
if (n, v) not in list(ns_rendered.items()): | |||||
if inclusive or _utilized(n, node, other_attrs, self.unsuppressedPrefixes): | if inclusive or _utilized(n, node, other_attrs, self.unsuppressedPrefixes): | ||||
ns_to_render.append((n, v)) | ns_to_render.append((n, v)) | ||||
elif not inclusive: | elif not inclusive: | ||||
@@ -400,9 +400,9 @@ class _implementation: | |||||
# Else, add all local and ancestor xml attributes | # Else, add all local and ancestor xml attributes | ||||
# Sort and render the attributes. | # Sort and render the attributes. | ||||
if not inclusive or _in_subset(self.subset, node.parentNode): # 0426 | if not inclusive or _in_subset(self.subset, node.parentNode): # 0426 | ||||
other_attrs.extend(xml_attrs_local.values()) | |||||
other_attrs.extend(list(xml_attrs_local.values())) | |||||
else: | else: | ||||
other_attrs.extend(xml_attrs.values()) | |||||
other_attrs.extend(list(xml_attrs.values())) | |||||
other_attrs.sort(_sorter) | other_attrs.sort(_sorter) | ||||
for a in other_attrs: | for a in other_attrs: | ||||
self._do_attr(a.nodeName, a.value) | self._do_attr(a.nodeName, a.value) | ||||
@@ -435,8 +435,8 @@ def Canonicalize(node, output=None, **kw): | |||||
prefixes that should be inherited. | prefixes that should be inherited. | ||||
''' | ''' | ||||
if output: | if output: | ||||
apply(_implementation, (node, output.write), kw) | |||||
_implementation(*(node, output.write), **kw) | |||||
else: | else: | ||||
s = StringIO.StringIO() | s = StringIO.StringIO() | ||||
apply(_implementation, (node, s.write), kw) | |||||
_implementation(*(node, s.write), **kw) | |||||
return s.getvalue() | return s.getvalue() |