mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-18 08:02:49 +01:00
Upgraded google, which required upgrading SOAP.
This commit is contained in:
parent
15b7063eac
commit
da8ebdb64a
85
others/GoogleSOAPFacade.py
Normal file
85
others/GoogleSOAPFacade.py
Normal file
@ -0,0 +1,85 @@
|
||||
"""
|
||||
Facade that hides the differences between the SOAPpy and SOAP.py
|
||||
libraries, so that google.py doesn't have to deal with them.
|
||||
|
||||
@author: Brian Landers <brian@bluecoat93.org>
|
||||
@license: Python
|
||||
@version: 0.5.4
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
__author__ = "Brian Landers <brian@bluecoat93.org>"
|
||||
__version__ = "0.6"
|
||||
__license__ = "Python"
|
||||
|
||||
#
|
||||
# Wrapper around the python 'warnings' facility
|
||||
#
|
||||
def warn( message, level=RuntimeWarning ):
|
||||
warnings.warn( message, level, stacklevel=3 )
|
||||
|
||||
# We can't use older version of SOAPpy, due to bugs that break the Google API
|
||||
minSOAPpyVersion = "0.11.3"
|
||||
|
||||
#
|
||||
# Try loading SOAPpy first. If that fails, fall back to the old SOAP.py
|
||||
#
|
||||
SOAPpy = None
|
||||
try:
|
||||
import SOAPpy
|
||||
from SOAPpy import SOAPProxy, Types
|
||||
|
||||
if LooseVersion( minSOAPpyVersion ) > \
|
||||
LooseVersion( SOAPpy.version.__version__ ):
|
||||
|
||||
warn( "Versions of SOAPpy before %s have known bugs that prevent " +
|
||||
"PyGoogle from functioning." % minSOAPpyVersion )
|
||||
raise ImportError
|
||||
|
||||
except ImportError:
|
||||
warn( "SOAPpy not imported. Trying legacy SOAP.py.",
|
||||
DeprecationWarning )
|
||||
try:
|
||||
import SOAP
|
||||
except ImportError:
|
||||
raise RuntimeError( "Unable to find SOAPpy or SOAP. Can't continue.\n" )
|
||||
|
||||
#
|
||||
# Constants that differ between the modules
|
||||
#
|
||||
if SOAPpy:
|
||||
false = Types.booleanType(0)
|
||||
true = Types.booleanType(1)
|
||||
structType = Types.structType
|
||||
faultType = Types.faultType
|
||||
else:
|
||||
false = SOAP.booleanType(0)
|
||||
true = SOAP.booleanType(1)
|
||||
structType = SOAP.structType
|
||||
faultType = SOAP.faultType
|
||||
|
||||
#
|
||||
# Get a SOAP Proxy object in the correct way for the module we're using
|
||||
#
|
||||
def getProxy( url, namespace, http_proxy ):
|
||||
if SOAPpy:
|
||||
return SOAPProxy( url,
|
||||
namespace = namespace,
|
||||
http_proxy = http_proxy )
|
||||
|
||||
else:
|
||||
return SOAP.SOAPProxy( url,
|
||||
namespace = namespace,
|
||||
http_proxy = http_proxy )
|
||||
|
||||
#
|
||||
# Convert an object to a dictionary in the proper way for the module
|
||||
# we're using for SOAP
|
||||
#
|
||||
def toDict( obj ):
|
||||
if SOAPpy:
|
||||
return obj._asdict()
|
||||
else:
|
||||
return obj._asdict
|
3977
others/SOAP.py
3977
others/SOAP.py
File diff suppressed because it is too large
Load Diff
478
others/SOAPpy/Client.py
Normal file
478
others/SOAPpy/Client.py
Normal file
@ -0,0 +1,478 @@
|
||||
"""
|
||||
################################################################################
|
||||
#
|
||||
# SOAPpy - Cayce Ullman (cayce@actzero.com)
|
||||
# Brian Matthews (blm@actzero.com)
|
||||
# Gregory Warnes (gregory_r_warnes@groton.pfizer.com)
|
||||
# Christopher Blunck (blunck@gst.com)
|
||||
#
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
from __future__ import nested_scopes
|
||||
|
||||
#import xml.sax
|
||||
import urllib
|
||||
from types import *
|
||||
import re
|
||||
import base64
|
||||
|
||||
# SOAPpy modules
|
||||
from Errors import *
|
||||
from Config import Config
|
||||
from Parser import parseSOAPRPC
|
||||
from SOAPBuilder import buildSOAP
|
||||
from Utilities import *
|
||||
from Types import faultType, simplify
|
||||
|
||||
################################################################################
|
||||
# Client
|
||||
################################################################################
|
||||
|
||||
|
||||
def SOAPUserAgent():
|
||||
return "SOAPpy " + __version__ + " (pywebsvcs.sf.net)"
|
||||
|
||||
|
||||
class SOAPAddress:
|
||||
def __init__(self, url, config = Config):
|
||||
proto, uri = urllib.splittype(url)
|
||||
|
||||
# apply some defaults
|
||||
if uri[0:2] != '//':
|
||||
if proto != None:
|
||||
uri = proto + ':' + uri
|
||||
|
||||
uri = '//' + uri
|
||||
proto = 'http'
|
||||
|
||||
host, path = urllib.splithost(uri)
|
||||
|
||||
try:
|
||||
int(host)
|
||||
host = 'localhost:' + host
|
||||
except:
|
||||
pass
|
||||
|
||||
if not path:
|
||||
path = '/'
|
||||
|
||||
if proto not in ('http', 'https', 'httpg'):
|
||||
raise IOError, "unsupported SOAP protocol"
|
||||
if proto == 'httpg' and not config.GSIclient:
|
||||
raise AttributeError, \
|
||||
"GSI client not supported by this Python installation"
|
||||
if proto == 'https' and not config.SSLclient:
|
||||
raise AttributeError, \
|
||||
"SSL client not supported by this Python installation"
|
||||
|
||||
self.user,host = urllib.splituser(host)
|
||||
self.proto = proto
|
||||
self.host = host
|
||||
self.path = path
|
||||
|
||||
def __str__(self):
|
||||
return "%(proto)s://%(host)s%(path)s" % self.__dict__
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
class HTTPTransport:
|
||||
def getNS(self, original_namespace, data):
|
||||
"""Extract the (possibly extended) namespace from the returned
|
||||
SOAP message."""
|
||||
|
||||
if type(original_namespace) == StringType:
|
||||
pattern="xmlns:\w+=['\"](" + original_namespace + "[^'\"]*)['\"]"
|
||||
match = re.search(pattern, data)
|
||||
if match:
|
||||
return match.group(1)
|
||||
else:
|
||||
return original_namespace
|
||||
else:
|
||||
return original_namespace
|
||||
|
||||
# Need a Timeout someday?
|
||||
def call(self, addr, data, namespace, soapaction = None, encoding = None,
|
||||
http_proxy = None, config = Config):
|
||||
|
||||
import httplib
|
||||
|
||||
if not isinstance(addr, SOAPAddress):
|
||||
addr = SOAPAddress(addr, config)
|
||||
|
||||
# Build a request
|
||||
if http_proxy:
|
||||
real_addr = http_proxy
|
||||
real_path = addr.proto + "://" + addr.host + addr.path
|
||||
else:
|
||||
real_addr = addr.host
|
||||
real_path = addr.path
|
||||
|
||||
if addr.proto == 'httpg':
|
||||
from pyGlobus.io import GSIHTTP
|
||||
r = GSIHTTP(real_addr, tcpAttr = config.tcpAttr)
|
||||
elif addr.proto == 'https':
|
||||
r = httplib.HTTPS(real_addr)
|
||||
else:
|
||||
r = httplib.HTTP(real_addr)
|
||||
|
||||
r.putrequest("POST", real_path)
|
||||
|
||||
r.putheader("Host", addr.host)
|
||||
r.putheader("User-agent", SOAPUserAgent())
|
||||
t = 'text/xml';
|
||||
if encoding != None:
|
||||
t += '; charset="%s"' % encoding
|
||||
r.putheader("Content-type", t)
|
||||
r.putheader("Content-length", str(len(data)))
|
||||
|
||||
# if user is not a user:passwd format
|
||||
# we'll receive a failure from the server. . .I guess (??)
|
||||
if addr.user != None:
|
||||
val = base64.encodestring(addr.user)
|
||||
r.putheader('Authorization','Basic ' + val.replace('\012',''))
|
||||
|
||||
# This fixes sending either "" or "None"
|
||||
if soapaction == None or len(soapaction) == 0:
|
||||
r.putheader("SOAPAction", "")
|
||||
else:
|
||||
r.putheader("SOAPAction", '"%s"' % soapaction)
|
||||
|
||||
if config.dumpHeadersOut:
|
||||
s = 'Outgoing HTTP headers'
|
||||
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 "Content-type:", t
|
||||
print "Content-length:", len(data)
|
||||
print 'SOAPAction: "%s"' % soapaction
|
||||
debugFooter(s)
|
||||
|
||||
r.endheaders()
|
||||
|
||||
if config.dumpSOAPOut:
|
||||
s = 'Outgoing SOAP'
|
||||
debugHeader(s)
|
||||
print data,
|
||||
if data[-1] != '\n':
|
||||
print
|
||||
debugFooter(s)
|
||||
|
||||
# send the payload
|
||||
r.send(data)
|
||||
|
||||
# read response line
|
||||
code, msg, headers = r.getreply()
|
||||
|
||||
content_type = headers.get("content-type","text/xml")
|
||||
content_length = headers.get("Content-length")
|
||||
if content_length == None:
|
||||
# No Content-Length provided; just read the whole socket
|
||||
# This won't work with HTTP/1.1 chunked encoding
|
||||
data = r.getfile().read()
|
||||
message_len = len(data)
|
||||
else:
|
||||
message_len = int(content_length)
|
||||
data = r.getfile().read(message_len)
|
||||
|
||||
if(config.debug):
|
||||
print "code=",code
|
||||
print "msg=", msg
|
||||
print "headers=", headers
|
||||
print "content-type=", content_type
|
||||
print "data=", data
|
||||
|
||||
if config.dumpHeadersIn:
|
||||
s = 'Incoming HTTP headers'
|
||||
debugHeader(s)
|
||||
if headers.headers:
|
||||
print "HTTP/1.? %d %s" % (code, msg)
|
||||
print "\n".join(map (lambda x: x.strip(), headers.headers))
|
||||
else:
|
||||
print "HTTP/0.9 %d %s" % (code, msg)
|
||||
debugFooter(s)
|
||||
|
||||
def startswith(string, val):
|
||||
return string[0:len(val)] == val
|
||||
|
||||
if code == 500 and not \
|
||||
( startswith(content_type, "text/xml") and message_len > 0 ):
|
||||
raise HTTPError(code, msg)
|
||||
|
||||
if config.dumpSOAPIn:
|
||||
s = 'Incoming SOAP'
|
||||
debugHeader(s)
|
||||
print data,
|
||||
if (len(data)>0) and (data[-1] != '\n'):
|
||||
print
|
||||
debugFooter(s)
|
||||
|
||||
if code not in (200, 500):
|
||||
raise HTTPError(code, msg)
|
||||
|
||||
|
||||
# get the new namespace
|
||||
if namespace is None:
|
||||
new_ns = None
|
||||
else:
|
||||
new_ns = self.getNS(namespace, data)
|
||||
|
||||
# return response payload
|
||||
return data, new_ns
|
||||
|
||||
################################################################################
|
||||
# SOAP Proxy
|
||||
################################################################################
|
||||
class SOAPProxy:
|
||||
def __init__(self, proxy, namespace = None, soapaction = None,
|
||||
header = None, methodattrs = None, transport = HTTPTransport,
|
||||
encoding = 'UTF-8', throw_faults = 1, unwrap_results = None,
|
||||
http_proxy=None, config = Config, noroot = 0,
|
||||
simplify_objects=None):
|
||||
|
||||
# Test the encoding, raising an exception if it's not known
|
||||
if encoding != None:
|
||||
''.encode(encoding)
|
||||
|
||||
# get default values for unwrap_results and simplify_objects
|
||||
# from config
|
||||
if unwrap_results is None:
|
||||
self.unwrap_results=config.unwrap_results
|
||||
else:
|
||||
self.unwrap_results=unwrap_results
|
||||
|
||||
if simplify_objects is None:
|
||||
self.simplify_objects=config.simplify_objects
|
||||
else:
|
||||
self.simplify_objects=simplify_objects
|
||||
|
||||
self.proxy = SOAPAddress(proxy, config)
|
||||
self.namespace = namespace
|
||||
self.soapaction = soapaction
|
||||
self.header = header
|
||||
self.methodattrs = methodattrs
|
||||
self.transport = transport()
|
||||
self.encoding = encoding
|
||||
self.throw_faults = throw_faults
|
||||
self.http_proxy = http_proxy
|
||||
self.config = config
|
||||
self.noroot = noroot
|
||||
|
||||
# GSI Additions
|
||||
if hasattr(config, "channel_mode") and \
|
||||
hasattr(config, "delegation_mode"):
|
||||
self.channel_mode = config.channel_mode
|
||||
self.delegation_mode = config.delegation_mode
|
||||
#end GSI Additions
|
||||
|
||||
def invoke(self, method, args):
|
||||
return self.__call(method, args, {})
|
||||
|
||||
def __call(self, name, args, kw, ns = None, sa = None, hd = None,
|
||||
ma = None):
|
||||
|
||||
ns = ns or self.namespace
|
||||
ma = ma or self.methodattrs
|
||||
|
||||
if sa: # Get soapaction
|
||||
if type(sa) == TupleType:
|
||||
sa = sa[0]
|
||||
else:
|
||||
if self.soapaction:
|
||||
sa = self.soapaction
|
||||
else:
|
||||
sa = name
|
||||
|
||||
if hd: # Get header
|
||||
if type(hd) == TupleType:
|
||||
hd = hd[0]
|
||||
else:
|
||||
hd = self.header
|
||||
|
||||
hd = hd or self.header
|
||||
|
||||
if ma: # Get methodattrs
|
||||
if type(ma) == TupleType: ma = ma[0]
|
||||
else:
|
||||
ma = self.methodattrs
|
||||
ma = ma or self.methodattrs
|
||||
|
||||
m = buildSOAP(args = args, kw = kw, method = name, namespace = ns,
|
||||
header = hd, methodattrs = ma, encoding = self.encoding,
|
||||
config = self.config, noroot = self.noroot)
|
||||
|
||||
|
||||
call_retry = 0
|
||||
try:
|
||||
|
||||
r, self.namespace = self.transport.call(self.proxy, m, ns, sa,
|
||||
encoding = self.encoding,
|
||||
http_proxy = self.http_proxy,
|
||||
config = self.config)
|
||||
|
||||
except Exception, ex:
|
||||
#
|
||||
# Call failed.
|
||||
#
|
||||
# See if we have a fault handling vector installed in our
|
||||
# config. If we do, invoke it. If it returns a true value,
|
||||
# retry the call.
|
||||
#
|
||||
# In any circumstance other than the fault handler returning
|
||||
# true, reraise the exception. This keeps the semantics of this
|
||||
# code the same as without the faultHandler code.
|
||||
#
|
||||
|
||||
if hasattr(self.config, "faultHandler"):
|
||||
if callable(self.config.faultHandler):
|
||||
call_retry = self.config.faultHandler(self.proxy, ex)
|
||||
if not call_retry:
|
||||
raise
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
raise
|
||||
|
||||
if call_retry:
|
||||
r, self.namespace = self.transport.call(self.proxy, m, ns, sa,
|
||||
encoding = self.encoding,
|
||||
http_proxy = self.http_proxy,
|
||||
config = self.config)
|
||||
|
||||
|
||||
p, attrs = parseSOAPRPC(r, attrs = 1)
|
||||
|
||||
try:
|
||||
throw_struct = self.throw_faults and \
|
||||
isinstance (p, faultType)
|
||||
except:
|
||||
throw_struct = 0
|
||||
|
||||
if throw_struct:
|
||||
print p
|
||||
raise p
|
||||
|
||||
# If unwrap_results=1 and there is only element in the struct,
|
||||
# SOAPProxy will assume that this element is the result
|
||||
# and return it rather than the struct containing it.
|
||||
# Otherwise SOAPproxy will return the struct with all the
|
||||
# elements as attributes.
|
||||
if self.unwrap_results:
|
||||
try:
|
||||
count = 0
|
||||
for i in p.__dict__.keys():
|
||||
if i[0] != "_": # don't count the private stuff
|
||||
count += 1
|
||||
t = getattr(p, i)
|
||||
if count == 1: # Only one piece of data, bubble it up
|
||||
p = t
|
||||
except:
|
||||
pass
|
||||
|
||||
# Automatically simplfy SOAP complex types into the
|
||||
# corresponding python types. (structType --> dict,
|
||||
# arrayType --> array, etc.)
|
||||
if self.simplify_objects:
|
||||
p = simplify(p)
|
||||
|
||||
if self.config.returnAllAttrs:
|
||||
return p, attrs
|
||||
return p
|
||||
|
||||
def _callWithBody(self, body):
|
||||
return self.__call(None, body, {})
|
||||
|
||||
def __getattr__(self, name): # hook to catch method calls
|
||||
if name == '__del__':
|
||||
raise AttributeError, name
|
||||
return self.__Method(self.__call, name, config = self.config)
|
||||
|
||||
# To handle attribute wierdness
|
||||
class __Method:
|
||||
# Some magic to bind a SOAP method to an RPC server.
|
||||
# Supports "nested" methods (e.g. examples.getStateName) -- concept
|
||||
# borrowed from xmlrpc/soaplib -- www.pythonware.com
|
||||
# Altered (improved?) to let you inline namespaces on a per call
|
||||
# basis ala SOAP::LITE -- www.soaplite.com
|
||||
|
||||
def __init__(self, call, name, ns = None, sa = None, hd = None,
|
||||
ma = None, config = Config):
|
||||
|
||||
self.__call = call
|
||||
self.__name = name
|
||||
self.__ns = ns
|
||||
self.__sa = sa
|
||||
self.__hd = hd
|
||||
self.__ma = ma
|
||||
self.__config = config
|
||||
return
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
if self.__name[0] == "_":
|
||||
if self.__name in ["__repr__","__str__"]:
|
||||
return self.__repr__()
|
||||
else:
|
||||
return self.__f_call(*args, **kw)
|
||||
else:
|
||||
return self.__r_call(*args, **kw)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name == '__del__':
|
||||
raise AttributeError, name
|
||||
if self.__name[0] == "_":
|
||||
# Don't nest method if it is a directive
|
||||
return self.__class__(self.__call, name, self.__ns,
|
||||
self.__sa, self.__hd, self.__ma)
|
||||
|
||||
return self.__class__(self.__call, "%s.%s" % (self.__name, name),
|
||||
self.__ns, self.__sa, self.__hd, self.__ma)
|
||||
|
||||
def __f_call(self, *args, **kw):
|
||||
if self.__name == "_ns": self.__ns = args
|
||||
elif self.__name == "_sa": self.__sa = args
|
||||
elif self.__name == "_hd": self.__hd = args
|
||||
elif self.__name == "_ma": self.__ma = args
|
||||
return self
|
||||
|
||||
def __r_call(self, *args, **kw):
|
||||
return self.__call(self.__name, args, kw, self.__ns, self.__sa,
|
||||
self.__hd, self.__ma)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s at %d>" % (self.__class__, id(self))
|
202
others/SOAPpy/Config.py
Normal file
202
others/SOAPpy/Config.py
Normal file
@ -0,0 +1,202 @@
|
||||
"""
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
import copy, socket
|
||||
from types import *
|
||||
|
||||
from NS import NS
|
||||
|
||||
################################################################################
|
||||
# Configuration class
|
||||
################################################################################
|
||||
|
||||
class SOAPConfig:
|
||||
__readonly = ('SSLserver', 'SSLclient', 'GSIserver', 'GSIclient')
|
||||
|
||||
def __init__(self, config = None, **kw):
|
||||
d = self.__dict__
|
||||
|
||||
if config:
|
||||
if not isinstance(config, SOAPConfig):
|
||||
raise AttributeError, \
|
||||
"initializer must be SOAPConfig instance"
|
||||
|
||||
s = config.__dict__
|
||||
|
||||
for k, v in s.items():
|
||||
if k[0] != '_':
|
||||
d[k] = v
|
||||
else:
|
||||
# Setting debug also sets returnFaultInfo,
|
||||
# dumpHeadersIn, dumpHeadersOut, dumpSOAPIn, and dumpSOAPOut
|
||||
self.debug = 0
|
||||
self.dumpFaultInfo = 1
|
||||
# Setting namespaceStyle sets typesNamespace, typesNamespaceURI,
|
||||
# schemaNamespace, and schemaNamespaceURI
|
||||
self.namespaceStyle = '1999'
|
||||
self.strictNamespaces = 0
|
||||
self.typed = 1
|
||||
self.buildWithNamespacePrefix = 1
|
||||
self.returnAllAttrs = 0
|
||||
|
||||
# Strict checking of range for floats and doubles
|
||||
self.strict_range = 0
|
||||
|
||||
# Default encoding for dictionary keys
|
||||
self.dict_encoding = 'ascii'
|
||||
|
||||
# New argument name handling mechanism. See
|
||||
# README.MethodParameterNaming for details
|
||||
self.specialArgs = 1
|
||||
|
||||
# If unwrap_results=1 and there is only element in the struct,
|
||||
# SOAPProxy will assume that this element is the result
|
||||
# and return it rather than the struct containing it.
|
||||
# Otherwise SOAPproxy will return the struct with all the
|
||||
# elements as attributes.
|
||||
self.unwrap_results = 1
|
||||
|
||||
# Automatically convert SOAP complex types, and
|
||||
# (recursively) public contents into the corresponding
|
||||
# python types. (Private subobjects have names that start
|
||||
# with '_'.)
|
||||
#
|
||||
# Conversions:
|
||||
# - faultType --> raise python exception
|
||||
# - arrayType --> array
|
||||
# - compoundType --> dictionary
|
||||
#
|
||||
self.simplify_objects = 0
|
||||
|
||||
# Per-class authorization method. If this is set, before
|
||||
# calling a any class method, the specified authorization
|
||||
# method will be called. If it returns 1, the method call
|
||||
# will proceed, otherwise the call will throw with an
|
||||
# authorization error.
|
||||
self.authMethod = None
|
||||
|
||||
# Globus Support if pyGlobus.io available
|
||||
try:
|
||||
from pyGlobus import io;
|
||||
d['GSIserver'] = 1
|
||||
d['GSIclient'] = 1
|
||||
except:
|
||||
d['GSIserver'] = 0
|
||||
d['GSIclient'] = 0
|
||||
|
||||
|
||||
# Server SSL support if M2Crypto.SSL available
|
||||
try:
|
||||
from M2Crypto import SSL
|
||||
d['SSLserver'] = 1
|
||||
except:
|
||||
d['SSLserver'] = 0
|
||||
|
||||
# Client SSL support if socket.ssl available
|
||||
try:
|
||||
from socket import ssl
|
||||
d['SSLclient'] = 1
|
||||
except:
|
||||
d['SSLclient'] = 0
|
||||
|
||||
for k, v in kw.items():
|
||||
if k[0] != '_':
|
||||
setattr(self, k, v)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name in self.__readonly:
|
||||
raise AttributeError, "readonly configuration setting"
|
||||
|
||||
d = self.__dict__
|
||||
|
||||
if name in ('typesNamespace', 'typesNamespaceURI',
|
||||
'schemaNamespace', 'schemaNamespaceURI'):
|
||||
|
||||
if name[-3:] == 'URI':
|
||||
base, uri = name[:-3], 1
|
||||
else:
|
||||
base, uri = name, 0
|
||||
|
||||
if type(value) == StringType:
|
||||
if NS.NSMAP.has_key(value):
|
||||
n = (value, NS.NSMAP[value])
|
||||
elif NS.NSMAP_R.has_key(value):
|
||||
n = (NS.NSMAP_R[value], value)
|
||||
else:
|
||||
raise AttributeError, "unknown namespace"
|
||||
elif type(value) in (ListType, TupleType):
|
||||
if uri:
|
||||
n = (value[1], value[0])
|
||||
else:
|
||||
n = (value[0], value[1])
|
||||
else:
|
||||
raise AttributeError, "unknown namespace type"
|
||||
|
||||
d[base], d[base + 'URI'] = n
|
||||
|
||||
try:
|
||||
d['namespaceStyle'] = \
|
||||
NS.STMAP_R[(d['typesNamespace'], d['schemaNamespace'])]
|
||||
except:
|
||||
d['namespaceStyle'] = ''
|
||||
|
||||
elif name == 'namespaceStyle':
|
||||
value = str(value)
|
||||
|
||||
if not NS.STMAP.has_key(value):
|
||||
raise AttributeError, "unknown namespace style"
|
||||
|
||||
d[name] = value
|
||||
n = d['typesNamespace'] = NS.STMAP[value][0]
|
||||
d['typesNamespaceURI'] = NS.NSMAP[n]
|
||||
n = d['schemaNamespace'] = NS.STMAP[value][1]
|
||||
d['schemaNamespaceURI'] = NS.NSMAP[n]
|
||||
|
||||
elif name == 'debug':
|
||||
d[name] = \
|
||||
d['returnFaultInfo'] = \
|
||||
d['dumpHeadersIn'] = \
|
||||
d['dumpHeadersOut'] = \
|
||||
d['dumpSOAPIn'] = \
|
||||
d['dumpSOAPOut'] = value
|
||||
|
||||
else:
|
||||
d[name] = value
|
||||
|
||||
|
||||
Config = SOAPConfig()
|
79
others/SOAPpy/Errors.py
Normal file
79
others/SOAPpy/Errors.py
Normal file
@ -0,0 +1,79 @@
|
||||
"""
|
||||
################################################################################
|
||||
#
|
||||
# SOAPpy - Cayce Ullman (cayce@actzero.com)
|
||||
# Brian Matthews (blm@actzero.com)
|
||||
# Gregory Warnes (gregory_r_warnes@groton.pfizer.com)
|
||||
# Christopher Blunck (blunck@gst.com)
|
||||
#
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
import exceptions
|
||||
|
||||
################################################################################
|
||||
# Exceptions
|
||||
################################################################################
|
||||
class Error(exceptions.Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
def __str__(self):
|
||||
return "<Error : %s>" % self.msg
|
||||
__repr__ = __str__
|
||||
def __call__(self):
|
||||
return (msg,)
|
||||
|
||||
class RecursionError(Error):
|
||||
pass
|
||||
|
||||
class UnknownTypeError(Error):
|
||||
pass
|
||||
|
||||
class HTTPError(Error):
|
||||
# indicates an HTTP protocol error
|
||||
def __init__(self, code, msg):
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
def __str__(self):
|
||||
return "<HTTPError %s %s>" % (self.code, self.msg)
|
||||
__repr__ = __str__
|
||||
def __call___(self):
|
||||
return (self.code, self.msg, )
|
||||
|
||||
class UnderflowError(exceptions.ArithmeticError):
|
||||
pass
|
||||
|
143
others/SOAPpy/GSIServer.py
Normal file
143
others/SOAPpy/GSIServer.py
Normal file
@ -0,0 +1,143 @@
|
||||
"""
|
||||
GSIServer - Contributed by Ivan R. Judson <judson@mcs.anl.gov>
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# SOAPpy - Cayce Ullman (cayce@actzero.com)
|
||||
# Brian Matthews (blm@actzero.com)
|
||||
# Gregory Warnes (gregory_r_warnes@groton.pfizer.com)
|
||||
# Christopher Blunck (blunck@gst.com)
|
||||
#
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
from __future__ import nested_scopes
|
||||
|
||||
#import xml.sax
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import SocketServer
|
||||
from types import *
|
||||
import BaseHTTPServer
|
||||
|
||||
# SOAPpy modules
|
||||
from Parser import parseSOAPRPC
|
||||
from Config import SOAPConfig
|
||||
from Types import faultType, voidType, simplify
|
||||
from NS import NS
|
||||
from SOAPBuilder import buildSOAP
|
||||
from Utilities import debugHeader, debugFooter
|
||||
|
||||
try: from M2Crypto import SSL
|
||||
except: pass
|
||||
|
||||
#####
|
||||
|
||||
from Server import *
|
||||
|
||||
from pyGlobus.io import GSITCPSocketServer, ThreadingGSITCPSocketServer
|
||||
from pyGlobus import ioc
|
||||
|
||||
def GSIConfig():
|
||||
config = SOAPConfig()
|
||||
config.channel_mode = ioc.GLOBUS_IO_SECURE_CHANNEL_MODE_GSI_WRAP
|
||||
config.delegation_mode = ioc.GLOBUS_IO_SECURE_DELEGATION_MODE_FULL_PROXY
|
||||
config.tcpAttr = None
|
||||
config.authMethod = "_authorize"
|
||||
return config
|
||||
|
||||
Config = GSIConfig()
|
||||
|
||||
class GSISOAPServer(GSITCPSocketServer, SOAPServerBase):
|
||||
def __init__(self, addr = ('localhost', 8000),
|
||||
RequestHandler = SOAPRequestHandler, log = 0,
|
||||
encoding = 'UTF-8', config = Config, namespace = None):
|
||||
|
||||
# Test the encoding, raising an exception if it's not known
|
||||
if encoding != None:
|
||||
''.encode(encoding)
|
||||
|
||||
self.namespace = namespace
|
||||
self.objmap = {}
|
||||
self.funcmap = {}
|
||||
self.encoding = encoding
|
||||
self.config = config
|
||||
self.log = log
|
||||
|
||||
self.allow_reuse_address= 1
|
||||
|
||||
GSITCPSocketServer.__init__(self, addr, RequestHandler,
|
||||
self.config.channel_mode,
|
||||
self.config.delegation_mode,
|
||||
tcpAttr = self.config.tcpAttr)
|
||||
|
||||
def get_request(self):
|
||||
sock, addr = GSITCPSocketServer.get_request(self)
|
||||
|
||||
return sock, addr
|
||||
|
||||
class ThreadingGSISOAPServer(ThreadingGSITCPSocketServer, SOAPServerBase):
|
||||
|
||||
def __init__(self, addr = ('localhost', 8000),
|
||||
RequestHandler = SOAPRequestHandler, log = 0,
|
||||
encoding = 'UTF-8', config = Config, namespace = None):
|
||||
|
||||
# Test the encoding, raising an exception if it's not known
|
||||
if encoding != None:
|
||||
''.encode(encoding)
|
||||
|
||||
self.namespace = namespace
|
||||
self.objmap = {}
|
||||
self.funcmap = {}
|
||||
self.encoding = encoding
|
||||
self.config = config
|
||||
self.log = log
|
||||
|
||||
self.allow_reuse_address= 1
|
||||
|
||||
ThreadingGSITCPSocketServer.__init__(self, addr, RequestHandler,
|
||||
self.config.channel_mode,
|
||||
self.config.delegation_mode,
|
||||
tcpAttr = self.config.tcpAttr)
|
||||
|
||||
def get_request(self):
|
||||
sock, addr = ThreadingGSITCPSocketServer.get_request(self)
|
||||
|
||||
return sock, addr
|
||||
|
104
others/SOAPpy/NS.py
Normal file
104
others/SOAPpy/NS.py
Normal file
@ -0,0 +1,104 @@
|
||||
"""
|
||||
################################################################################
|
||||
#
|
||||
# SOAPpy - Cayce Ullman (cayce@actzero.com)
|
||||
# Brian Matthews (blm@actzero.com)
|
||||
# Gregory Warnes (gregory_r_warnes@groton.pfizer.com)
|
||||
# Christopher Blunck (blunck@gst.com)
|
||||
#
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
from __future__ import nested_scopes
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
##############################################################################
|
||||
# Namespace Class
|
||||
################################################################################
|
||||
def invertDict(dict):
|
||||
d = {}
|
||||
|
||||
for k, v in dict.items():
|
||||
d[v] = k
|
||||
|
||||
return d
|
||||
|
||||
class NS:
|
||||
XML = "http://www.w3.org/XML/1998/namespace"
|
||||
|
||||
ENV = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
ENC = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
|
||||
XSD = "http://www.w3.org/1999/XMLSchema"
|
||||
XSD2 = "http://www.w3.org/2000/10/XMLSchema"
|
||||
XSD3 = "http://www.w3.org/2001/XMLSchema"
|
||||
|
||||
XSD_L = [XSD, XSD2, XSD3]
|
||||
EXSD_L= [ENC, XSD, XSD2, XSD3]
|
||||
|
||||
XSI = "http://www.w3.org/1999/XMLSchema-instance"
|
||||
XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance"
|
||||
XSI3 = "http://www.w3.org/2001/XMLSchema-instance"
|
||||
XSI_L = [XSI, XSI2, XSI3]
|
||||
|
||||
URN = "http://soapinterop.org/xsd"
|
||||
|
||||
# For generated messages
|
||||
XML_T = "xml"
|
||||
ENV_T = "SOAP-ENV"
|
||||
ENC_T = "SOAP-ENC"
|
||||
XSD_T = "xsd"
|
||||
XSD2_T= "xsd2"
|
||||
XSD3_T= "xsd3"
|
||||
XSI_T = "xsi"
|
||||
XSI2_T= "xsi2"
|
||||
XSI3_T= "xsi3"
|
||||
URN_T = "urn"
|
||||
|
||||
NSMAP = {ENV_T: ENV, ENC_T: ENC, XSD_T: XSD, XSD2_T: XSD2,
|
||||
XSD3_T: XSD3, XSI_T: XSI, XSI2_T: XSI2, XSI3_T: XSI3,
|
||||
URN_T: URN}
|
||||
NSMAP_R = invertDict(NSMAP)
|
||||
|
||||
STMAP = {'1999': (XSD_T, XSI_T), '2000': (XSD2_T, XSI2_T),
|
||||
'2001': (XSD3_T, XSI3_T)}
|
||||
STMAP_R = invertDict(STMAP)
|
||||
|
||||
def __init__(self):
|
||||
raise Error, "Don't instantiate this"
|
||||
|
||||
|
||||
|
1024
others/SOAPpy/Parser.py
Normal file
1024
others/SOAPpy/Parser.py
Normal file
File diff suppressed because it is too large
Load Diff
40
others/SOAPpy/SOAP.py
Normal file
40
others/SOAPpy/SOAP.py
Normal file
@ -0,0 +1,40 @@
|
||||
"""This file is here for backward compatibility with versions <= 0.9.9
|
||||
|
||||
Delete when 1.0.0 is released!
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
from Client import *
|
||||
from Config import *
|
||||
from Errors import *
|
||||
from NS import *
|
||||
from Parser import *
|
||||
from SOAPBuilder import *
|
||||
from Server import *
|
||||
from Types import *
|
||||
from Utilities import *
|
||||
import wstools
|
||||
import WSDL
|
||||
|
||||
from warnings import warn
|
||||
|
||||
warn("""
|
||||
|
||||
The sub-module SOAPpy.SOAP is deprecated and is only
|
||||
provided for short-term backward compatibility. Objects are now
|
||||
available directly within the SOAPpy module. Thus, instead of
|
||||
|
||||
from SOAPpy import SOAP
|
||||
...
|
||||
SOAP.SOAPProxy(...)
|
||||
|
||||
use
|
||||
|
||||
from SOAPpy import SOAPProxy
|
||||
...
|
||||
SOAPProxy(...)
|
||||
|
||||
instead.
|
||||
""", DeprecationWarning)
|
620
others/SOAPpy/SOAPBuilder.py
Normal file
620
others/SOAPpy/SOAPBuilder.py
Normal file
@ -0,0 +1,620 @@
|
||||
"""
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
import cgi
|
||||
import copy
|
||||
from wstools.XMLname import toXMLname, fromXMLname
|
||||
import fpconst
|
||||
|
||||
# SOAPpy modules
|
||||
from Config import Config
|
||||
from NS import NS
|
||||
from Types import *
|
||||
|
||||
# Test whether this Python version has Types.BooleanType
|
||||
# If it doesn't have it, then False and True are serialized as integers
|
||||
try:
|
||||
BooleanType
|
||||
pythonHasBooleanType = 1
|
||||
except NameError:
|
||||
pythonHasBooleanType = 0
|
||||
|
||||
################################################################################
|
||||
# SOAP Builder
|
||||
################################################################################
|
||||
class SOAPBuilder:
|
||||
_xml_top = '<?xml version="1.0"?>\n'
|
||||
_xml_enc_top = '<?xml version="1.0" encoding="%s"?>\n'
|
||||
_env_top = '%(ENV_T)s:Envelope %(ENV_T)s:encodingStyle="%(ENC)s"' % \
|
||||
NS.__dict__
|
||||
_env_bot = '</%(ENV_T)s:Envelope>\n' % NS.__dict__
|
||||
|
||||
# Namespaces potentially defined in the Envelope tag.
|
||||
|
||||
_env_ns = {NS.ENC: NS.ENC_T, NS.ENV: NS.ENV_T,
|
||||
NS.XSD: NS.XSD_T, NS.XSD2: NS.XSD2_T, NS.XSD3: NS.XSD3_T,
|
||||
NS.XSI: NS.XSI_T, NS.XSI2: NS.XSI2_T, NS.XSI3: NS.XSI3_T}
|
||||
|
||||
def __init__(self, args = (), kw = {}, method = None, namespace = None,
|
||||
header = None, methodattrs = None, envelope = 1, encoding = 'UTF-8',
|
||||
use_refs = 0, config = Config, noroot = 0):
|
||||
|
||||
# Test the encoding, raising an exception if it's not known
|
||||
if encoding != None:
|
||||
''.encode(encoding)
|
||||
|
||||
self.args = args
|
||||
self.kw = kw
|
||||
self.envelope = envelope
|
||||
self.encoding = encoding
|
||||
self.method = method
|
||||
self.namespace = namespace
|
||||
self.header = header
|
||||
self.methodattrs= methodattrs
|
||||
self.use_refs = use_refs
|
||||
self.config = config
|
||||
self.out = []
|
||||
self.tcounter = 0
|
||||
self.ncounter = 1
|
||||
self.icounter = 1
|
||||
self.envns = {}
|
||||
self.ids = {}
|
||||
self.depth = 0
|
||||
self.multirefs = []
|
||||
self.multis = 0
|
||||
self.body = not isinstance(args, bodyType)
|
||||
self.noroot = noroot
|
||||
|
||||
def build(self):
|
||||
if Config.debug: print "In build."
|
||||
ns_map = {}
|
||||
|
||||
# Cache whether typing is on or not
|
||||
typed = self.config.typed
|
||||
|
||||
if self.header:
|
||||
# Create a header.
|
||||
self.dump(self.header, "Header", typed = typed)
|
||||
self.header = None # Wipe it out so no one is using it.
|
||||
|
||||
if self.body:
|
||||
# Call genns to record that we've used SOAP-ENV.
|
||||
self.depth += 1
|
||||
body_ns = self.genns(ns_map, NS.ENV)[0]
|
||||
self.out.append("<%sBody>\n" % body_ns)
|
||||
|
||||
if self.method:
|
||||
self.depth += 1
|
||||
a = ''
|
||||
if self.methodattrs:
|
||||
for (k, v) in self.methodattrs.items():
|
||||
a += ' %s="%s"' % (k, v)
|
||||
|
||||
if self.namespace: # Use the namespace info handed to us
|
||||
methodns, n = self.genns(ns_map, self.namespace)
|
||||
else:
|
||||
methodns, n = '', ''
|
||||
|
||||
self.out.append('<%s%s%s%s%s>\n' % (
|
||||
methodns, self.method, n, a, self.genroot(ns_map)))
|
||||
|
||||
try:
|
||||
if type(self.args) != TupleType:
|
||||
args = (self.args,)
|
||||
else:
|
||||
args = self.args
|
||||
|
||||
for i in args:
|
||||
self.dump(i, typed = typed, ns_map = ns_map)
|
||||
|
||||
if hasattr(self.config, "argsOrdering") and self.config.argsOrdering.has_key(self.method):
|
||||
for k in self.config.argsOrdering.get(self.method):
|
||||
self.dump(self.kw.get(k), k, typed = typed, ns_map = ns_map)
|
||||
else:
|
||||
for (k, v) in self.kw.items():
|
||||
self.dump(v, k, typed = typed, ns_map = ns_map)
|
||||
|
||||
except RecursionError:
|
||||
if self.use_refs == 0:
|
||||
# restart
|
||||
b = SOAPBuilder(args = self.args, kw = self.kw,
|
||||
method = self.method, namespace = self.namespace,
|
||||
header = self.header, methodattrs = self.methodattrs,
|
||||
envelope = self.envelope, encoding = self.encoding,
|
||||
use_refs = 1, config = self.config)
|
||||
return b.build()
|
||||
raise
|
||||
|
||||
if self.method:
|
||||
self.out.append("</%s%s>\n" % (methodns, self.method))
|
||||
self.depth -= 1
|
||||
|
||||
if self.body:
|
||||
# dump may add to self.multirefs, but the for loop will keep
|
||||
# going until it has used all of self.multirefs, even those
|
||||
# entries added while in the loop.
|
||||
|
||||
self.multis = 1
|
||||
|
||||
for obj, tag in self.multirefs:
|
||||
self.dump(obj, tag, typed = typed, ns_map = ns_map)
|
||||
|
||||
self.out.append("</%sBody>\n" % body_ns)
|
||||
self.depth -= 1
|
||||
|
||||
if self.envelope:
|
||||
e = map (lambda ns: ' xmlns:%s="%s"' % (ns[1], ns[0]),
|
||||
self.envns.items())
|
||||
|
||||
self.out = ['<', self._env_top] + e + ['>\n'] + \
|
||||
self.out + \
|
||||
[self._env_bot]
|
||||
|
||||
if self.encoding != None:
|
||||
self.out.insert(0, self._xml_enc_top % self.encoding)
|
||||
return ''.join(self.out).encode(self.encoding)
|
||||
|
||||
self.out.insert(0, self._xml_top)
|
||||
return ''.join(self.out)
|
||||
|
||||
def gentag(self):
|
||||
if Config.debug: print "In gentag."
|
||||
self.tcounter += 1
|
||||
return "v%d" % self.tcounter
|
||||
|
||||
def genns(self, ns_map, nsURI):
|
||||
if nsURI == None:
|
||||
return ('', '')
|
||||
|
||||
if type(nsURI) == TupleType: # already a tuple
|
||||
if len(nsURI) == 2:
|
||||
ns, nsURI = nsURI
|
||||
else:
|
||||
ns, nsURI = None, nsURI[0]
|
||||
else:
|
||||
ns = None
|
||||
|
||||
if ns_map.has_key(nsURI):
|
||||
return (ns_map[nsURI] + ':', '')
|
||||
|
||||
if self._env_ns.has_key(nsURI):
|
||||
ns = self.envns[nsURI] = ns_map[nsURI] = self._env_ns[nsURI]
|
||||
return (ns + ':', '')
|
||||
|
||||
if not ns:
|
||||
ns = "ns%d" % self.ncounter
|
||||
self.ncounter += 1
|
||||
ns_map[nsURI] = ns
|
||||
if self.config.buildWithNamespacePrefix:
|
||||
return (ns + ':', ' xmlns:%s="%s"' % (ns, nsURI))
|
||||
else:
|
||||
return ('', ' xmlns="%s"' % (nsURI))
|
||||
|
||||
def genroot(self, ns_map):
|
||||
if self.noroot:
|
||||
return ''
|
||||
|
||||
if self.depth != 2:
|
||||
return ''
|
||||
|
||||
ns, n = self.genns(ns_map, NS.ENC)
|
||||
return ' %sroot="%d"%s' % (ns, not self.multis, n)
|
||||
|
||||
# checkref checks an element to see if it needs to be encoded as a
|
||||
# multi-reference element or not. If it returns None, the element has
|
||||
# been handled and the caller can continue with subsequent elements.
|
||||
# If it returns a string, the string should be included in the opening
|
||||
# tag of the marshaled element.
|
||||
|
||||
def checkref(self, obj, tag, ns_map):
|
||||
if self.depth < 2:
|
||||
return ''
|
||||
|
||||
if not self.ids.has_key(id(obj)):
|
||||
n = self.ids[id(obj)] = self.icounter
|
||||
self.icounter = n + 1
|
||||
|
||||
if self.use_refs == 0:
|
||||
return ''
|
||||
|
||||
if self.depth == 2:
|
||||
return ' id="i%d"' % n
|
||||
|
||||
self.multirefs.append((obj, tag))
|
||||
else:
|
||||
if self.use_refs == 0:
|
||||
raise RecursionError, "Cannot serialize recursive object"
|
||||
|
||||
n = self.ids[id(obj)]
|
||||
|
||||
if self.multis and self.depth == 2:
|
||||
return ' id="i%d"' % n
|
||||
|
||||
self.out.append('<%s href="#i%d"%s/>\n' %
|
||||
(tag, n, self.genroot(ns_map)))
|
||||
return None
|
||||
|
||||
# dumpers
|
||||
|
||||
def dump(self, obj, tag = None, typed = 1, ns_map = {}):
|
||||
if Config.debug: print "In dump.", "obj=", obj
|
||||
ns_map = ns_map.copy()
|
||||
self.depth += 1
|
||||
|
||||
if type(tag) not in (NoneType, StringType, UnicodeType):
|
||||
raise KeyError, "tag must be a string or None"
|
||||
|
||||
try:
|
||||
meth = getattr(self, "dump_" + type(obj).__name__)
|
||||
except AttributeError:
|
||||
if type(obj) == LongType:
|
||||
obj_type = "integer"
|
||||
elif pythonHasBooleanType and type(obj) == BooleanType:
|
||||
obj_type = "boolean"
|
||||
else:
|
||||
obj_type = type(obj).__name__
|
||||
|
||||
self.out.append(self.dumper(None, obj_type, obj, tag, typed,
|
||||
ns_map, self.genroot(ns_map)))
|
||||
else:
|
||||
meth(obj, tag, typed, ns_map)
|
||||
|
||||
|
||||
self.depth -= 1
|
||||
|
||||
# generic dumper
|
||||
def dumper(self, nsURI, obj_type, obj, tag, typed = 1, ns_map = {},
|
||||
rootattr = '', id = '',
|
||||
xml = '<%(tag)s%(type)s%(id)s%(attrs)s%(root)s>%(data)s</%(tag)s>\n'):
|
||||
if Config.debug: print "In dumper."
|
||||
|
||||
if nsURI == None:
|
||||
nsURI = self.config.typesNamespaceURI
|
||||
|
||||
tag = tag or self.gentag()
|
||||
|
||||
tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding
|
||||
|
||||
a = n = t = ''
|
||||
if typed and obj_type:
|
||||
ns, n = self.genns(ns_map, nsURI)
|
||||
ins = self.genns(ns_map, self.config.schemaNamespaceURI)[0]
|
||||
t = ' %stype="%s%s"%s' % (ins, ns, obj_type, n)
|
||||
|
||||
try: a = obj._marshalAttrs(ns_map, self)
|
||||
except: pass
|
||||
|
||||
try: data = obj._marshalData()
|
||||
except:
|
||||
if (obj_type != "string"): # strings are already encoded
|
||||
data = cgi.escape(str(obj))
|
||||
else:
|
||||
data = obj
|
||||
|
||||
|
||||
return xml % {"tag": tag, "type": t, "data": data, "root": rootattr,
|
||||
"id": id, "attrs": a}
|
||||
|
||||
def dump_float(self, obj, tag, typed = 1, ns_map = {}):
|
||||
if Config.debug: print "In dump_float."
|
||||
tag = tag or self.gentag()
|
||||
|
||||
tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding
|
||||
|
||||
if Config.strict_range:
|
||||
doubleType(obj)
|
||||
|
||||
if fpconst.isPosInf(obj):
|
||||
obj = "INF"
|
||||
elif fpconst.isNegInf(obj):
|
||||
obj = "-INF"
|
||||
elif fpconst.isNaN(obj):
|
||||
obj = "NaN"
|
||||
else:
|
||||
obj = str(obj)
|
||||
|
||||
# Note: python 'float' is actually a SOAP 'double'.
|
||||
self.out.append(self.dumper(None, "double", obj, tag, typed, ns_map,
|
||||
self.genroot(ns_map)))
|
||||
|
||||
def dump_string(self, obj, tag, typed = 0, ns_map = {}):
|
||||
if Config.debug: print "In dump_string."
|
||||
tag = tag or self.gentag()
|
||||
tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding
|
||||
|
||||
id = self.checkref(obj, tag, ns_map)
|
||||
if id == None:
|
||||
return
|
||||
|
||||
try: data = obj._marshalData()
|
||||
except: data = obj
|
||||
|
||||
self.out.append(self.dumper(None, "string", cgi.escape(data), tag,
|
||||
typed, ns_map, self.genroot(ns_map), id))
|
||||
|
||||
dump_str = dump_string # For Python 2.2+
|
||||
dump_unicode = dump_string
|
||||
|
||||
def dump_None(self, obj, tag, typed = 0, ns_map = {}):
|
||||
if Config.debug: print "In dump_None."
|
||||
tag = tag or self.gentag()
|
||||
tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding
|
||||
ns = self.genns(ns_map, self.config.schemaNamespaceURI)[0]
|
||||
|
||||
self.out.append('<%s %snull="1"%s/>\n' %
|
||||
(tag, ns, self.genroot(ns_map)))
|
||||
|
||||
dump_NoneType = dump_None # For Python 2.2+
|
||||
|
||||
def dump_list(self, obj, tag, typed = 1, ns_map = {}):
|
||||
if Config.debug: print "In dump_list.", "obj=", obj
|
||||
tag = tag or self.gentag()
|
||||
tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding
|
||||
|
||||
if type(obj) == InstanceType:
|
||||
data = obj.data
|
||||
else:
|
||||
data = obj
|
||||
|
||||
id = self.checkref(obj, tag, ns_map)
|
||||
if id == None:
|
||||
return
|
||||
|
||||
try:
|
||||
sample = data[0]
|
||||
empty = 0
|
||||
except:
|
||||
# preserve type if present
|
||||
if getattr(obj,"_typed",None) and getattr(obj,"_type",None):
|
||||
if getattr(obj, "_complexType", None):
|
||||
sample = typedArrayType(typed=obj._type,
|
||||
complexType = obj._complexType)
|
||||
sample._typename = obj._type
|
||||
obj._ns = NS.URN
|
||||
else:
|
||||
sample = typedArrayType(typed=obj._type)
|
||||
else:
|
||||
sample = structType()
|
||||
empty = 1
|
||||
|
||||
# First scan list to see if all are the same type
|
||||
same_type = 1
|
||||
|
||||
if not empty:
|
||||
for i in data[1:]:
|
||||
if type(sample) != type(i) or \
|
||||
(type(sample) == InstanceType and \
|
||||
sample.__class__ != i.__class__):
|
||||
same_type = 0
|
||||
break
|
||||
|
||||
ndecl = ''
|
||||
if same_type:
|
||||
if (isinstance(sample, structType)) or \
|
||||
type(sample) == DictType or \
|
||||
(isinstance(sample, anyType) and \
|
||||
(getattr(sample, "_complexType", None) and \
|
||||
sample._complexType)): # force to urn struct
|
||||
try:
|
||||
tns = obj._ns or NS.URN
|
||||
except:
|
||||
tns = NS.URN
|
||||
|
||||
ns, ndecl = self.genns(ns_map, tns)
|
||||
|
||||
try:
|
||||
typename = sample._typename
|
||||
except:
|
||||
typename = "SOAPStruct"
|
||||
|
||||
t = ns + typename
|
||||
|
||||
elif isinstance(sample, anyType):
|
||||
ns = sample._validNamespaceURI(self.config.typesNamespaceURI,
|
||||
self.config.strictNamespaces)
|
||||
if ns:
|
||||
ns, ndecl = self.genns(ns_map, ns)
|
||||
t = ns + sample._type
|
||||
else:
|
||||
t = 'ur-type'
|
||||
else:
|
||||
typename = type(sample).__name__
|
||||
|
||||
# For Python 2.2+
|
||||
if type(sample) == StringType: typename = 'string'
|
||||
|
||||
# HACK: python 'float' is actually a SOAP 'double'.
|
||||
if typename=="float": typename="double"
|
||||
t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \
|
||||
typename
|
||||
|
||||
else:
|
||||
t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \
|
||||
"ur-type"
|
||||
|
||||
try: a = obj._marshalAttrs(ns_map, self)
|
||||
except: a = ''
|
||||
|
||||
ens, edecl = self.genns(ns_map, NS.ENC)
|
||||
ins, idecl = self.genns(ns_map, self.config.schemaNamespaceURI)
|
||||
|
||||
self.out.append(
|
||||
'<%s %sarrayType="%s[%d]" %stype="%sArray"%s%s%s%s%s%s>\n' %
|
||||
(tag, ens, t, len(data), ins, ens, ndecl, edecl, idecl,
|
||||
self.genroot(ns_map), id, a))
|
||||
|
||||
typed = not same_type
|
||||
|
||||
try: elemsname = obj._elemsname
|
||||
except: elemsname = "item"
|
||||
|
||||
for i in data:
|
||||
self.dump(i, elemsname, typed, ns_map)
|
||||
|
||||
self.out.append('</%s>\n' % tag)
|
||||
|
||||
dump_tuple = dump_list
|
||||
|
||||
def dump_dictionary(self, obj, tag, typed = 1, ns_map = {}):
|
||||
if Config.debug: print "In dump_dictionary."
|
||||
tag = tag or self.gentag()
|
||||
tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding
|
||||
|
||||
id = self.checkref(obj, tag, ns_map)
|
||||
if id == None:
|
||||
return
|
||||
|
||||
try: a = obj._marshalAttrs(ns_map, self)
|
||||
except: a = ''
|
||||
|
||||
self.out.append('<%s%s%s%s>\n' %
|
||||
(tag, id, a, self.genroot(ns_map)))
|
||||
|
||||
for (k, v) in obj.items():
|
||||
if k[0] != "_":
|
||||
self.dump(v, k, 1, ns_map)
|
||||
|
||||
self.out.append('</%s>\n' % tag)
|
||||
|
||||
dump_dict = dump_dictionary # For Python 2.2+
|
||||
|
||||
def dump_instance(self, obj, tag, typed = 1, ns_map = {}):
|
||||
if Config.debug: print "In dump_instance.", "obj=", obj, "tag=", tag
|
||||
if not tag:
|
||||
# If it has a name use it.
|
||||
if isinstance(obj, anyType) and obj._name:
|
||||
tag = obj._name
|
||||
else:
|
||||
tag = self.gentag()
|
||||
tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding
|
||||
|
||||
if isinstance(obj, arrayType): # Array
|
||||
self.dump_list(obj, tag, typed, ns_map)
|
||||
return
|
||||
|
||||
if isinstance(obj, faultType): # Fault
|
||||
cns, cdecl = self.genns(ns_map, NS.ENC)
|
||||
vns, vdecl = self.genns(ns_map, NS.ENV)
|
||||
self.out.append('''<%sFault %sroot="1"%s%s>
|
||||
<faultcode>%s</faultcode>
|
||||
<faultstring>%s</faultstring>
|
||||
''' % (vns, cns, vdecl, cdecl, obj.faultcode, obj.faultstring))
|
||||
if hasattr(obj, "detail"):
|
||||
self.dump(obj.detail, "detail", typed, ns_map)
|
||||
self.out.append("</%sFault>\n" % vns)
|
||||
return
|
||||
|
||||
r = self.genroot(ns_map)
|
||||
|
||||
try: a = obj._marshalAttrs(ns_map, self)
|
||||
except: a = ''
|
||||
|
||||
if isinstance(obj, voidType): # void
|
||||
self.out.append("<%s%s%s></%s>\n" % (tag, a, r, tag))
|
||||
return
|
||||
|
||||
id = self.checkref(obj, tag, ns_map)
|
||||
if id == None:
|
||||
return
|
||||
|
||||
if isinstance(obj, structType):
|
||||
# Check for namespace
|
||||
ndecl = ''
|
||||
ns = obj._validNamespaceURI(self.config.typesNamespaceURI,
|
||||
self.config.strictNamespaces)
|
||||
if ns:
|
||||
ns, ndecl = self.genns(ns_map, ns)
|
||||
tag = ns + tag
|
||||
self.out.append("<%s%s%s%s%s>\n" % (tag, ndecl, id, a, r))
|
||||
|
||||
keylist = obj.__dict__.keys()
|
||||
|
||||
# first write out items with order information
|
||||
if hasattr(obj, '_keyord'):
|
||||
for i in range(len(obj._keyord)):
|
||||
self.dump(obj._aslist(i), obj._keyord[i], 1, ns_map)
|
||||
keylist.remove(obj._keyord[i])
|
||||
|
||||
# now write out the rest
|
||||
for k in keylist:
|
||||
if (k[0] != "_"):
|
||||
self.dump(getattr(obj,k), k, 1, ns_map)
|
||||
|
||||
if isinstance(obj, bodyType):
|
||||
self.multis = 1
|
||||
|
||||
for v, k in self.multirefs:
|
||||
self.dump(v, k, typed = typed, ns_map = ns_map)
|
||||
|
||||
self.out.append('</%s>\n' % tag)
|
||||
|
||||
elif isinstance(obj, anyType):
|
||||
t = ''
|
||||
|
||||
if typed:
|
||||
ns = obj._validNamespaceURI(self.config.typesNamespaceURI,
|
||||
self.config.strictNamespaces)
|
||||
if ns:
|
||||
ons, ondecl = self.genns(ns_map, ns)
|
||||
ins, indecl = self.genns(ns_map,
|
||||
self.config.schemaNamespaceURI)
|
||||
t = ' %stype="%s%s"%s%s' % \
|
||||
(ins, ons, obj._type, ondecl, indecl)
|
||||
|
||||
self.out.append('<%s%s%s%s%s>%s</%s>\n' %
|
||||
(tag, t, id, a, r, obj._marshalData(), tag))
|
||||
|
||||
else: # Some Class
|
||||
self.out.append('<%s%s%s>\n' % (tag, id, r))
|
||||
|
||||
for (k, v) in obj.__dict__.items():
|
||||
if k[0] != "_":
|
||||
self.dump(v, k, 1, ns_map)
|
||||
|
||||
self.out.append('</%s>\n' % tag)
|
||||
|
||||
|
||||
################################################################################
|
||||
# SOAPBuilder's more public interface
|
||||
################################################################################
|
||||
def buildSOAP(args=(), kw={}, method=None, namespace=None, header=None,
|
||||
methodattrs=None,envelope=1,encoding='UTF-8',config=Config,noroot = 0):
|
||||
t = SOAPBuilder(args=args,kw=kw, method=method, namespace=namespace,
|
||||
header=header, methodattrs=methodattrs,envelope=envelope,
|
||||
encoding=encoding, config=config,noroot=noroot)
|
||||
return t.build()
|
706
others/SOAPpy/Server.py
Normal file
706
others/SOAPpy/Server.py
Normal file
@ -0,0 +1,706 @@
|
||||
"""
|
||||
################################################################################
|
||||
#
|
||||
# SOAPpy - Cayce Ullman (cayce@actzero.com)
|
||||
# Brian Matthews (blm@actzero.com)
|
||||
# Gregory Warnes (gregory_r_warnes@groton.pfizer.com)
|
||||
# Christopher Blunck (blunck@gst.com)
|
||||
#
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
from __future__ import nested_scopes
|
||||
|
||||
#import xml.sax
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import SocketServer
|
||||
from types import *
|
||||
import BaseHTTPServer
|
||||
import thread
|
||||
|
||||
# SOAPpy modules
|
||||
from Parser import parseSOAPRPC
|
||||
from Config import Config
|
||||
from Types import faultType, voidType, simplify
|
||||
from NS import NS
|
||||
from SOAPBuilder import buildSOAP
|
||||
from Utilities import debugHeader, debugFooter
|
||||
|
||||
try: from M2Crypto import SSL
|
||||
except: pass
|
||||
|
||||
ident = '$Id$'
|
||||
|
||||
from version import __version__
|
||||
|
||||
################################################################################
|
||||
# Call context dictionary
|
||||
################################################################################
|
||||
|
||||
_contexts = dict()
|
||||
|
||||
def GetSOAPContext():
|
||||
global _contexts
|
||||
return _contexts[thread.get_ident()]
|
||||
|
||||
################################################################################
|
||||
# Server
|
||||
################################################################################
|
||||
|
||||
# Method Signature class for adding extra info to registered funcs, right now
|
||||
# used just to indicate it should be called with keywords, instead of ordered
|
||||
# params.
|
||||
class MethodSig:
|
||||
def __init__(self, func, keywords=0, context=0):
|
||||
self.func = func
|
||||
self.keywords = keywords
|
||||
self.context = context
|
||||
self.__name__ = func.__name__
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
return apply(self.func,args,kw)
|
||||
|
||||
class SOAPContext:
|
||||
def __init__(self, header, body, attrs, xmldata, connection, httpheaders,
|
||||
soapaction):
|
||||
|
||||
self.header = header
|
||||
self.body = body
|
||||
self.attrs = attrs
|
||||
self.xmldata = xmldata
|
||||
self.connection = connection
|
||||
self.httpheaders= httpheaders
|
||||
self.soapaction = soapaction
|
||||
|
||||
# A class to describe how header messages are handled
|
||||
class HeaderHandler:
|
||||
# Initially fail out if there are any problems.
|
||||
def __init__(self, header, attrs):
|
||||
for i in header.__dict__.keys():
|
||||
if i[0] == "_":
|
||||
continue
|
||||
|
||||
d = getattr(header, i)
|
||||
|
||||
try:
|
||||
fault = int(attrs[id(d)][(NS.ENV, 'mustUnderstand')])
|
||||
except:
|
||||
fault = 0
|
||||
|
||||
if fault:
|
||||
raise faultType, ("%s:MustUnderstand" % NS.ENV_T,
|
||||
"Required Header Misunderstood",
|
||||
"%s" % i)
|
||||
|
||||
################################################################################
|
||||
# SOAP Server
|
||||
################################################################################
|
||||
class SOAPServerBase:
|
||||
|
||||
def get_request(self):
|
||||
sock, addr = SocketServer.TCPServer.get_request(self)
|
||||
|
||||
if self.ssl_context:
|
||||
sock = SSL.Connection(self.ssl_context, sock)
|
||||
sock._setup_ssl(addr)
|
||||
if sock.accept_ssl() != 1:
|
||||
raise socket.error, "Couldn't accept SSL connection"
|
||||
|
||||
return sock, addr
|
||||
|
||||
def registerObject(self, object, namespace = '', path = ''):
|
||||
if namespace == '' and path == '': namespace = self.namespace
|
||||
if namespace == '' and path != '':
|
||||
namespace = path.replace("/", ":")
|
||||
if namespace[0] == ":": namespace = namespace[1:]
|
||||
self.objmap[namespace] = object
|
||||
|
||||
def registerFunction(self, function, namespace = '', funcName = None,
|
||||
path = ''):
|
||||
if not funcName : funcName = function.__name__
|
||||
if namespace == '' and path == '': namespace = self.namespace
|
||||
if namespace == '' and path != '':
|
||||
namespace = path.replace("/", ":")
|
||||
if namespace[0] == ":": namespace = namespace[1:]
|
||||
if self.funcmap.has_key(namespace):
|
||||
self.funcmap[namespace][funcName] = function
|
||||
else:
|
||||
self.funcmap[namespace] = {funcName : function}
|
||||
|
||||
def registerKWObject(self, object, namespace = '', path = ''):
|
||||
if namespace == '' and path == '': namespace = self.namespace
|
||||
if namespace == '' and path != '':
|
||||
namespace = path.replace("/", ":")
|
||||
if namespace[0] == ":": namespace = namespace[1:]
|
||||
for i in dir(object.__class__):
|
||||
if i[0] != "_" and callable(getattr(object, i)):
|
||||
self.registerKWFunction(getattr(object,i), namespace)
|
||||
|
||||
# convenience - wraps your func for you.
|
||||
def registerKWFunction(self, function, namespace = '', funcName = None,
|
||||
path = ''):
|
||||
if namespace == '' and path == '': namespace = self.namespace
|
||||
if namespace == '' and path != '':
|
||||
namespace = path.replace("/", ":")
|
||||
if namespace[0] == ":": namespace = namespace[1:]
|
||||
self.registerFunction(MethodSig(function,keywords=1), namespace,
|
||||
funcName)
|
||||
|
||||
def unregisterObject(self, object, namespace = '', path = ''):
|
||||
if namespace == '' and path == '': namespace = self.namespace
|
||||
if namespace == '' and path != '':
|
||||
namespace = path.replace("/", ":")
|
||||
if namespace[0] == ":": namespace = namespace[1:]
|
||||
|
||||
del self.objmap[namespace]
|
||||
|
||||
class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def version_string(self):
|
||||
return '<a href="http://pywebsvcs.sf.net">' + \
|
||||
'SOAPpy ' + __version__ + '</a> (Python ' + \
|
||||
sys.version.split()[0] + ')'
|
||||
|
||||
def date_time_string(self):
|
||||
self.__last_date_time_string = \
|
||||
BaseHTTPServer.BaseHTTPRequestHandler.\
|
||||
date_time_string(self)
|
||||
|
||||
return self.__last_date_time_string
|
||||
|
||||
def do_POST(self):
|
||||
global _contexts
|
||||
|
||||
status = 500
|
||||
try:
|
||||
if self.server.config.dumpHeadersIn:
|
||||
s = 'Incoming HTTP headers'
|
||||
debugHeader(s)
|
||||
print self.raw_requestline.strip()
|
||||
print "\n".join(map (lambda x: x.strip(),
|
||||
self.headers.headers))
|
||||
debugFooter(s)
|
||||
|
||||
data = self.rfile.read(int(self.headers["Content-length"]))
|
||||
|
||||
if self.server.config.dumpSOAPIn:
|
||||
s = 'Incoming SOAP'
|
||||
debugHeader(s)
|
||||
print data,
|
||||
if data[-1] != '\n':
|
||||
print
|
||||
debugFooter(s)
|
||||
|
||||
(r, header, body, attrs) = \
|
||||
parseSOAPRPC(data, header = 1, body = 1, attrs = 1)
|
||||
|
||||
method = r._name
|
||||
args = r._aslist()
|
||||
kw = r._asdict()
|
||||
|
||||
if Config.simplify_objects:
|
||||
args = simplify(args)
|
||||
kw = simplify(kw)
|
||||
|
||||
# Handle mixed named and unnamed arguments by assuming
|
||||
# that all arguments with names of the form "v[0-9]+"
|
||||
# are unnamed and should be passed in numeric order,
|
||||
# other arguments are named and should be passed using
|
||||
# this name.
|
||||
|
||||
# This is a non-standard exension to the SOAP protocol,
|
||||
# but is supported by Apache AXIS.
|
||||
|
||||
# It is enabled by default. To disable, set
|
||||
# Config.specialArgs to False.
|
||||
|
||||
if Config.specialArgs:
|
||||
|
||||
ordered_args = {}
|
||||
named_args = {}
|
||||
|
||||
for (k,v) in kw.items():
|
||||
|
||||
if k[0]=="v":
|
||||
try:
|
||||
i = int(k[1:])
|
||||
ordered_args[i] = v
|
||||
except ValueError:
|
||||
named_args[str(k)] = v
|
||||
|
||||
else:
|
||||
named_args[str(k)] = v
|
||||
|
||||
# We have to decide namespace precedence
|
||||
# I'm happy with the following scenario
|
||||
# if r._ns is specified use it, if not check for
|
||||
# a path, if it's specified convert it and use it as the
|
||||
# namespace. If both are specified, use r._ns.
|
||||
|
||||
ns = r._ns
|
||||
|
||||
if len(self.path) > 1 and not ns:
|
||||
ns = self.path.replace("/", ":")
|
||||
if ns[0] == ":": ns = ns[1:]
|
||||
|
||||
# authorization method
|
||||
a = None
|
||||
|
||||
keylist = ordered_args.keys()
|
||||
keylist.sort()
|
||||
|
||||
# create list in proper order w/o names
|
||||
tmp = map( lambda x: ordered_args[x], keylist)
|
||||
ordered_args = tmp
|
||||
|
||||
#print '<-> Argument Matching Yielded:'
|
||||
#print '<-> Ordered Arguments:' + str(ordered_args)
|
||||
#print '<-> Named Arguments :' + str(named_args)
|
||||
|
||||
resp = ""
|
||||
|
||||
# For fault messages
|
||||
if ns:
|
||||
nsmethod = "%s:%s" % (ns, method)
|
||||
else:
|
||||
nsmethod = method
|
||||
|
||||
try:
|
||||
# First look for registered functions
|
||||
if self.server.funcmap.has_key(ns) and \
|
||||
self.server.funcmap[ns].has_key(method):
|
||||
f = self.server.funcmap[ns][method]
|
||||
|
||||
# look for the authorization method
|
||||
if self.server.config.authMethod != None:
|
||||
authmethod = self.server.config.authMethod
|
||||
if self.server.funcmap.has_key(ns) and \
|
||||
self.server.funcmap[ns].has_key(authmethod):
|
||||
a = self.server.funcmap[ns][authmethod]
|
||||
else:
|
||||
# Now look at registered objects
|
||||
# Check for nested attributes. This works even if
|
||||
# there are none, because the split will return
|
||||
# [method]
|
||||
f = self.server.objmap[ns]
|
||||
|
||||
# Look for the authorization method
|
||||
if self.server.config.authMethod != None:
|
||||
authmethod = self.server.config.authMethod
|
||||
if hasattr(f, authmethod):
|
||||
a = getattr(f, authmethod)
|
||||
|
||||
# then continue looking for the method
|
||||
l = method.split(".")
|
||||
for i in l:
|
||||
f = getattr(f, i)
|
||||
except:
|
||||
info = sys.exc_info()
|
||||
try:
|
||||
resp = buildSOAP(faultType("%s:Client" % NS.ENV_T,
|
||||
"Method Not Found",
|
||||
"%s : %s %s %s" % (nsmethod,
|
||||
info[0],
|
||||
info[1],
|
||||
info[2])),
|
||||
encoding = self.server.encoding,
|
||||
config = self.server.config)
|
||||
finally:
|
||||
del info
|
||||
status = 500
|
||||
else:
|
||||
try:
|
||||
if header:
|
||||
x = HeaderHandler(header, attrs)
|
||||
|
||||
fr = 1
|
||||
|
||||
# call context book keeping
|
||||
# We're stuffing the method into the soapaction if there
|
||||
# isn't one, someday, we'll set that on the client
|
||||
# and it won't be necessary here
|
||||
# for now we're doing both
|
||||
|
||||
if "SOAPAction".lower() not in self.headers.keys() or \
|
||||
self.headers["SOAPAction"] == "\"\"":
|
||||
self.headers["SOAPAction"] = method
|
||||
|
||||
thread_id = thread.get_ident()
|
||||
_contexts[thread_id] = SOAPContext(header, body,
|
||||
attrs, data,
|
||||
self.connection,
|
||||
self.headers,
|
||||
self.headers["SOAPAction"])
|
||||
|
||||
# Do an authorization check
|
||||
if a != None:
|
||||
if not apply(a, (), {"_SOAPContext" :
|
||||
_contexts[thread_id] }):
|
||||
raise faultType("%s:Server" % NS.ENV_T,
|
||||
"Authorization failed.",
|
||||
"%s" % nsmethod)
|
||||
|
||||
# If it's wrapped, some special action may be needed
|
||||
if isinstance(f, MethodSig):
|
||||
c = None
|
||||
|
||||
if f.context: # retrieve context object
|
||||
c = _contexts[thread_id]
|
||||
|
||||
if Config.specialArgs:
|
||||
if c:
|
||||
named_args["_SOAPContext"] = c
|
||||
fr = apply(f, ordered_args, named_args)
|
||||
elif f.keywords:
|
||||
# This is lame, but have to de-unicode
|
||||
# keywords
|
||||
|
||||
strkw = {}
|
||||
|
||||
for (k, v) in kw.items():
|
||||
strkw[str(k)] = v
|
||||
if c:
|
||||
strkw["_SOAPContext"] = c
|
||||
fr = apply(f, (), strkw)
|
||||
elif c:
|
||||
fr = apply(f, args, {'_SOAPContext':c})
|
||||
else:
|
||||
fr = apply(f, args, {})
|
||||
|
||||
else:
|
||||
if Config.specialArgs:
|
||||
fr = apply(f, ordered_args, named_args)
|
||||
else:
|
||||
fr = apply(f, args, {})
|
||||
|
||||
|
||||
if type(fr) == type(self) and \
|
||||
isinstance(fr, voidType):
|
||||
resp = buildSOAP(kw = {'%sResponse' % method: fr},
|
||||
encoding = self.server.encoding,
|
||||
config = self.server.config)
|
||||
else:
|
||||
resp = buildSOAP(kw =
|
||||
{'%sResponse' % method: {'Result': fr}},
|
||||
encoding = self.server.encoding,
|
||||
config = self.server.config)
|
||||
|
||||
# Clean up _contexts
|
||||
if _contexts.has_key(thread_id):
|
||||
del _contexts[thread_id]
|
||||
|
||||
except Exception, e:
|
||||
import traceback
|
||||
info = sys.exc_info()
|
||||
|
||||
try:
|
||||
if self.server.config.dumpFaultInfo:
|
||||
s = 'Method %s exception' % nsmethod
|
||||
debugHeader(s)
|
||||
traceback.print_exception(info[0], info[1],
|
||||
info[2])
|
||||
debugFooter(s)
|
||||
|
||||
if isinstance(e, faultType):
|
||||
f = e
|
||||
else:
|
||||
f = faultType("%s:Server" % NS.ENV_T,
|
||||
"Method Failed",
|
||||
"%s" % nsmethod)
|
||||
|
||||
if self.server.config.returnFaultInfo:
|
||||
f._setDetail("".join(traceback.format_exception(
|
||||
info[0], info[1], info[2])))
|
||||
elif not hasattr(f, 'detail'):
|
||||
f._setDetail("%s %s" % (info[0], info[1]))
|
||||
finally:
|
||||
del info
|
||||
|
||||
resp = buildSOAP(f, encoding = self.server.encoding,
|
||||
config = self.server.config)
|
||||
status = 500
|
||||
else:
|
||||
status = 200
|
||||
except faultType, e:
|
||||
import traceback
|
||||
info = sys.exc_info()
|
||||
try:
|
||||
if self.server.config.dumpFaultInfo:
|
||||
s = 'Received fault exception'
|
||||
debugHeader(s)
|
||||
traceback.print_exception(info[0], info[1],
|
||||
info[2])
|
||||
debugFooter(s)
|
||||
|
||||
if self.server.config.returnFaultInfo:
|
||||
e._setDetail("".join(traceback.format_exception(
|
||||
info[0], info[1], info[2])))
|
||||
elif not hasattr(e, 'detail'):
|
||||
e._setDetail("%s %s" % (info[0], info[1]))
|
||||
finally:
|
||||
del info
|
||||
|
||||
resp = buildSOAP(e, encoding = self.server.encoding,
|
||||
config = self.server.config)
|
||||
status = 500
|
||||
except Exception, e:
|
||||
# internal error, report as HTTP server error
|
||||
|
||||
if self.server.config.dumpFaultInfo:
|
||||
s = 'Internal exception %s' % e
|
||||
import traceback
|
||||
debugHeader(s)
|
||||
info = sys.exc_info()
|
||||
try:
|
||||
traceback.print_exception(info[0], info[1], info[2])
|
||||
finally:
|
||||
del info
|
||||
|
||||
debugFooter(s)
|
||||
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
|
||||
if self.server.config.dumpHeadersOut and \
|
||||
self.request_version != 'HTTP/0.9':
|
||||
s = 'Outgoing HTTP headers'
|
||||
debugHeader(s)
|
||||
if self.responses.has_key(status):
|
||||
s = ' ' + self.responses[status][0]
|
||||
else:
|
||||
s = ''
|
||||
print "%s %d%s" % (self.protocol_version, 500, s)
|
||||
print "Server:", self.version_string()
|
||||
print "Date:", self.__last_date_time_string
|
||||
debugFooter(s)
|
||||
else:
|
||||
# got a valid SOAP response
|
||||
self.send_response(status)
|
||||
|
||||
t = 'text/xml';
|
||||
if self.server.encoding != None:
|
||||
t += '; charset="%s"' % self.server.encoding
|
||||
self.send_header("Content-type", t)
|
||||
self.send_header("Content-length", str(len(resp)))
|
||||
self.end_headers()
|
||||
|
||||
if self.server.config.dumpHeadersOut and \
|
||||
self.request_version != 'HTTP/0.9':
|
||||
s = 'Outgoing HTTP headers'
|
||||
debugHeader(s)
|
||||
if self.responses.has_key(status):
|
||||
s = ' ' + self.responses[status][0]
|
||||
else:
|
||||
s = ''
|
||||
print "%s %d%s" % (self.protocol_version, status, s)
|
||||
print "Server:", self.version_string()
|
||||
print "Date:", self.__last_date_time_string
|
||||
print "Content-type:", t
|
||||
print "Content-length:", len(resp)
|
||||
debugFooter(s)
|
||||
|
||||
if self.server.config.dumpSOAPOut:
|
||||
s = 'Outgoing SOAP'
|
||||
debugHeader(s)
|
||||
print resp,
|
||||
if resp[-1] != '\n':
|
||||
print
|
||||
debugFooter(s)
|
||||
|
||||
self.wfile.write(resp)
|
||||
self.wfile.flush()
|
||||
|
||||
# We should be able to shut down both a regular and an SSL
|
||||
# connection, but under Python 2.1, calling shutdown on an
|
||||
# SSL connections drops the output, so this work-around.
|
||||
# This should be investigated more someday.
|
||||
|
||||
if self.server.config.SSLserver and \
|
||||
isinstance(self.connection, SSL.Connection):
|
||||
self.connection.set_shutdown(SSL.SSL_SENT_SHUTDOWN |
|
||||
SSL.SSL_RECEIVED_SHUTDOWN)
|
||||
else:
|
||||
self.connection.shutdown(1)
|
||||
|
||||
def do_GET(self):
|
||||
|
||||
#print 'command ', self.command
|
||||
#print 'path ', self.path
|
||||
#print 'request_version', self.request_version
|
||||
#print 'headers'
|
||||
#print ' type ', self.headers.type
|
||||
#print ' maintype', self.headers.maintype
|
||||
#print ' subtype ', self.headers.subtype
|
||||
#print ' params ', self.headers.plist
|
||||
|
||||
path = self.path.lower()
|
||||
if path.endswith('wsdl'):
|
||||
method = 'wsdl'
|
||||
function = namespace = None
|
||||
if self.server.funcmap.has_key(namespace) \
|
||||
and self.server.funcmap[namespace].has_key(method):
|
||||
function = self.server.funcmap[namespace][method]
|
||||
else:
|
||||
if namespace in self.server.objmap.keys():
|
||||
function = self.server.objmap[namespace]
|
||||
l = method.split(".")
|
||||
for i in l:
|
||||
function = getattr(function, i)
|
||||
|
||||
if function:
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", 'text/plain')
|
||||
self.end_headers()
|
||||
response = apply(function, ())
|
||||
self.wfile.write(str(response))
|
||||
return
|
||||
|
||||
# return error
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", 'text/html')
|
||||
self.end_headers()
|
||||
self.wfile.write('''\
|
||||
<title>
|
||||
<head>Error!</head>
|
||||
</title>
|
||||
|
||||
<body>
|
||||
<h1>Oops!</h1>
|
||||
|
||||
<p>
|
||||
This server supports HTTP GET requests only for the the purpose of
|
||||
obtaining Web Services Description Language (WSDL) for a specific
|
||||
service.
|
||||
|
||||
Either you requested an URL that does not end in "wsdl" or this
|
||||
server does not implement a wsdl method.
|
||||
</p>
|
||||
|
||||
|
||||
</body>''')
|
||||
|
||||
|
||||
def log_message(self, format, *args):
|
||||
if self.server.log:
|
||||
BaseHTTPServer.BaseHTTPRequestHandler.\
|
||||
log_message (self, format, *args)
|
||||
|
||||
|
||||
|
||||
class SOAPServer(SOAPServerBase, SocketServer.TCPServer):
|
||||
|
||||
def __init__(self, addr = ('localhost', 8000),
|
||||
RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8',
|
||||
config = Config, namespace = None, ssl_context = None):
|
||||
|
||||
# Test the encoding, raising an exception if it's not known
|
||||
if encoding != None:
|
||||
''.encode(encoding)
|
||||
|
||||
if ssl_context != None and not config.SSLserver:
|
||||
raise AttributeError, \
|
||||
"SSL server not supported by this Python installation"
|
||||
|
||||
self.namespace = namespace
|
||||
self.objmap = {}
|
||||
self.funcmap = {}
|
||||
self.ssl_context = ssl_context
|
||||
self.encoding = encoding
|
||||
self.config = config
|
||||
self.log = log
|
||||
|
||||
self.allow_reuse_address= 1
|
||||
|
||||
SocketServer.TCPServer.__init__(self, addr, RequestHandler)
|
||||
|
||||
|
||||
class ThreadingSOAPServer(SOAPServerBase, SocketServer.ThreadingTCPServer):
|
||||
|
||||
def __init__(self, addr = ('localhost', 8000),
|
||||
RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8',
|
||||
config = Config, namespace = None, ssl_context = None):
|
||||
|
||||
# Test the encoding, raising an exception if it's not known
|
||||
if encoding != None:
|
||||
''.encode(encoding)
|
||||
|
||||
if ssl_context != None and not config.SSLserver:
|
||||
raise AttributeError, \
|
||||
"SSL server not supported by this Python installation"
|
||||
|
||||
self.namespace = namespace
|
||||
self.objmap = {}
|
||||
self.funcmap = {}
|
||||
self.ssl_context = ssl_context
|
||||
self.encoding = encoding
|
||||
self.config = config
|
||||
self.log = log
|
||||
|
||||
self.allow_reuse_address= 1
|
||||
|
||||
SocketServer.ThreadingTCPServer.__init__(self, addr, RequestHandler)
|
||||
|
||||
# only define class if Unix domain sockets are available
|
||||
if hasattr(socket, "AF_UNIX"):
|
||||
|
||||
class SOAPUnixSocketServer(SOAPServerBase, SocketServer.UnixStreamServer):
|
||||
|
||||
def __init__(self, addr = 8000,
|
||||
RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8',
|
||||
config = Config, namespace = None, ssl_context = None):
|
||||
|
||||
# Test the encoding, raising an exception if it's not known
|
||||
if encoding != None:
|
||||
''.encode(encoding)
|
||||
|
||||
if ssl_context != None and not config.SSLserver:
|
||||
raise AttributeError, \
|
||||
"SSL server not supported by this Python installation"
|
||||
|
||||
self.namespace = namespace
|
||||
self.objmap = {}
|
||||
self.funcmap = {}
|
||||
self.ssl_context = ssl_context
|
||||
self.encoding = encoding
|
||||
self.config = config
|
||||
self.log = log
|
||||
|
||||
self.allow_reuse_address= 1
|
||||
|
||||
SocketServer.UnixStreamServer.__init__(self, str(addr), RequestHandler)
|
||||
|
1734
others/SOAPpy/Types.py
Normal file
1734
others/SOAPpy/Types.py
Normal file
File diff suppressed because it is too large
Load Diff
23
others/SOAPpy/URLopener.py
Normal file
23
others/SOAPpy/URLopener.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""Provide a class for loading data from URL's that handles basic
|
||||
authentication"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
from Config import Config
|
||||
from urllib import FancyURLopener
|
||||
|
||||
class URLopener(FancyURLopener):
|
||||
|
||||
username = None
|
||||
passwd = None
|
||||
|
||||
|
||||
def __init__(self, username=None, passwd=None, *args, **kw):
|
||||
FancyURLopener.__init__( self, *args, **kw)
|
||||
self.username = username
|
||||
self.passwd = passwd
|
||||
|
||||
|
||||
def prompt_user_passwd(self, host, realm):
|
||||
return self.username, self.passwd
|
178
others/SOAPpy/Utilities.py
Normal file
178
others/SOAPpy/Utilities.py
Normal file
@ -0,0 +1,178 @@
|
||||
"""
|
||||
################################################################################
|
||||
# Copyright (c) 2003, Pfizer
|
||||
# Copyright (c) 2001, Cayce Ullman.
|
||||
# Copyright (c) 2001, Brian Matthews.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of actzero, inc. nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
import exceptions
|
||||
import copy
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
from types import *
|
||||
|
||||
# SOAPpy modules
|
||||
from Errors import *
|
||||
|
||||
################################################################################
|
||||
# Utility infielders
|
||||
################################################################################
|
||||
def collapseWhiteSpace(s):
|
||||
return re.sub('\s+', ' ', s).strip()
|
||||
|
||||
def decodeHexString(data):
|
||||
conv = {
|
||||
'0': 0x0, '1': 0x1, '2': 0x2, '3': 0x3, '4': 0x4,
|
||||
'5': 0x5, '6': 0x6, '7': 0x7, '8': 0x8, '9': 0x9,
|
||||
|
||||
'a': 0xa, 'b': 0xb, 'c': 0xc, 'd': 0xd, 'e': 0xe,
|
||||
'f': 0xf,
|
||||
|
||||
'A': 0xa, 'B': 0xb, 'C': 0xc, 'D': 0xd, 'E': 0xe,
|
||||
'F': 0xf,
|
||||
}
|
||||
|
||||
ws = string.whitespace
|
||||
|
||||
bin = ''
|
||||
|
||||
i = 0
|
||||
|
||||
while i < len(data):
|
||||
if data[i] not in ws:
|
||||
break
|
||||
i += 1
|
||||
|
||||
low = 0
|
||||
|
||||
while i < len(data):
|
||||
c = data[i]
|
||||
|
||||
if c in string.whitespace:
|
||||
break
|
||||
|
||||
try:
|
||||
c = conv[c]
|
||||
except KeyError:
|
||||
raise ValueError, \
|
||||
"invalid hex string character `%s'" % c
|
||||
|
||||
if low:
|
||||
bin += chr(high * 16 + c)
|
||||
low = 0
|
||||
else:
|
||||
high = c
|
||||
low = 1
|
||||
|
||||
i += 1
|
||||
|
||||
if low:
|
||||
raise ValueError, "invalid hex string length"
|
||||
|
||||
while i < len(data):
|
||||
if data[i] not in string.whitespace:
|
||||
raise ValueError, \
|
||||
"invalid hex string character `%s'" % c
|
||||
|
||||
i += 1
|
||||
|
||||
return bin
|
||||
|
||||
def encodeHexString(data):
|
||||
h = ''
|
||||
|
||||
for i in data:
|
||||
h += "%02X" % ord(i)
|
||||
|
||||
return h
|
||||
|
||||
def leapMonth(year, month):
|
||||
return month == 2 and \
|
||||
year % 4 == 0 and \
|
||||
(year % 100 != 0 or year % 400 == 0)
|
||||
|
||||
def cleanDate(d, first = 0):
|
||||
ranges = (None, (1, 12), (1, 31), (0, 23), (0, 59), (0, 61))
|
||||
months = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
||||
names = ('year', 'month', 'day', 'hours', 'minutes', 'seconds')
|
||||
|
||||
if len(d) != 6:
|
||||
raise ValueError, "date must have 6 elements"
|
||||
|
||||
for i in range(first, 6):
|
||||
s = d[i]
|
||||
|
||||
if type(s) == FloatType:
|
||||
if i < 5:
|
||||
try:
|
||||
s = int(s)
|
||||
except OverflowError:
|
||||
if i > 0:
|
||||
raise
|
||||
s = long(s)
|
||||
|
||||
if s != d[i]:
|
||||
raise ValueError, "%s must be integral" % names[i]
|
||||
|
||||
d[i] = s
|
||||
elif type(s) == LongType:
|
||||
try: s = int(s)
|
||||
except: pass
|
||||
elif type(s) != IntType:
|
||||
raise TypeError, "%s isn't a valid type" % names[i]
|
||||
|
||||
if i == first and s < 0:
|
||||
continue
|
||||
|
||||
if ranges[i] != None and \
|
||||
(s < ranges[i][0] or ranges[i][1] < s):
|
||||
raise ValueError, "%s out of range" % names[i]
|
||||
|
||||
if first < 6 and d[5] >= 61:
|
||||
raise ValueError, "seconds out of range"
|
||||
|
||||
if first < 2:
|
||||
leap = first < 1 and leapMonth(d[0], d[1])
|
||||
|
||||
if d[2] > months[d[1]] + leap:
|
||||
raise ValueError, "day out of range"
|
||||
|
||||
def debugHeader(title):
|
||||
s = '*** ' + title + ' '
|
||||
print s + ('*' * (72 - len(s)))
|
||||
|
||||
def debugFooter(title):
|
||||
print '*' * 72
|
||||
sys.stdout.flush()
|
102
others/SOAPpy/WSDL.py
Normal file
102
others/SOAPpy/WSDL.py
Normal file
@ -0,0 +1,102 @@
|
||||
"""Parse web services description language to get SOAP methods.
|
||||
|
||||
Rudimentary support."""
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
import wstools
|
||||
from Client import SOAPProxy, SOAPAddress
|
||||
from Config import Config
|
||||
import urllib
|
||||
|
||||
class Proxy:
|
||||
"""WSDL Proxy.
|
||||
|
||||
SOAPProxy wrapper that parses method names, namespaces, soap actions from
|
||||
the web service description language (WSDL) file passed into the
|
||||
constructor. The WSDL reference can be passed in as a stream, an url, a
|
||||
file name, or a string.
|
||||
|
||||
Loads info into self.methods, a dictionary with methodname keys and values
|
||||
of WSDLTools.SOAPCallinfo.
|
||||
|
||||
For example,
|
||||
|
||||
url = 'http://www.xmethods.org/sd/2001/TemperatureService.wsdl'
|
||||
wsdl = WSDL.Proxy(url)
|
||||
print len(wsdl.methods) # 1
|
||||
print wsdl.methods.keys() # getTemp
|
||||
|
||||
|
||||
See WSDLTools.SOAPCallinfo for more info on each method's attributes.
|
||||
"""
|
||||
|
||||
def __init__(self, wsdlsource, config=Config, **kw ):
|
||||
|
||||
reader = wstools.WSDLTools.WSDLReader()
|
||||
self.wsdl = None
|
||||
|
||||
# From Mark Pilgrim's "Dive Into Python" toolkit.py--open anything.
|
||||
if self.wsdl is None and hasattr(wsdlsource, "read"):
|
||||
#print 'stream'
|
||||
self.wsdl = reader.loadFromStream(wsdlsource)
|
||||
|
||||
# NOT TESTED (as of April 17, 2003)
|
||||
#if self.wsdl is None and wsdlsource == '-':
|
||||
# import sys
|
||||
# self.wsdl = reader.loadFromStream(sys.stdin)
|
||||
# print 'stdin'
|
||||
|
||||
if self.wsdl is None:
|
||||
try:
|
||||
file(wsdlsource)
|
||||
self.wsdl = reader.loadFromFile(wsdlsource)
|
||||
#print 'file'
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
if self.wsdl is None:
|
||||
try:
|
||||
stream = urllib.urlopen(wsdlsource)
|
||||
self.wsdl = reader.loadFromStream(stream, wsdlsource)
|
||||
except (IOError, OSError): pass
|
||||
|
||||
if self.wsdl is None:
|
||||
import StringIO
|
||||
self.wsdl = reader.loadFromString(str(wsdlsource))
|
||||
#print 'string'
|
||||
|
||||
# Package wsdl info as a dictionary of remote methods, with method name
|
||||
# as key (based on ServiceProxy.__init__ in ZSI library).
|
||||
self.methods = {}
|
||||
service = self.wsdl.services[0]
|
||||
port = service.ports[0]
|
||||
name = service.name
|
||||
binding = port.getBinding()
|
||||
portType = binding.getPortType()
|
||||
for operation in portType.operations:
|
||||
callinfo = wstools.WSDLTools.callInfoFromWSDL(port, operation.name)
|
||||
self.methods[callinfo.methodName] = callinfo
|
||||
|
||||
self.soapproxy = SOAPProxy('http://localhost/dummy.webservice',
|
||||
config=config, **kw)
|
||||
|
||||
def __str__(self):
|
||||
s = ''
|
||||
for method in self.methods.values():
|
||||
s += str(method)
|
||||
return s
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Set up environment then let parent class handle call.
|
||||
|
||||
Raises AttributeError is method name is not found."""
|
||||
|
||||
if not self.methods.has_key(name): raise AttributeError, name
|
||||
|
||||
callinfo = self.methods[name]
|
||||
self.soapproxy.proxy = SOAPAddress(callinfo.location)
|
||||
self.soapproxy.namespace = callinfo.namespace
|
||||
self.soapproxy.soapaction = callinfo.soapAction
|
||||
return self.soapproxy.__getattr__(name)
|
15
others/SOAPpy/__init__.py
Normal file
15
others/SOAPpy/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
ident = '$Id$'
|
||||
from version import __version__
|
||||
|
||||
from Client import *
|
||||
from Config import *
|
||||
from Errors import *
|
||||
from NS import *
|
||||
from Parser import *
|
||||
from SOAPBuilder import *
|
||||
from Server import *
|
||||
from Types import *
|
||||
from Utilities import *
|
||||
import wstools
|
||||
import WSDL
|
2
others/SOAPpy/version.py
Normal file
2
others/SOAPpy/version.py
Normal file
@ -0,0 +1,2 @@
|
||||
__version__="0.11.6"
|
||||
|
92
others/SOAPpy/wstools/Namespaces.py
Executable file
92
others/SOAPpy/wstools/Namespaces.py
Executable file
@ -0,0 +1,92 @@
|
||||
#! /usr/bin/env python
|
||||
"""Namespace module, so you don't need PyXML
|
||||
"""
|
||||
|
||||
try:
|
||||
from xml.ns import SOAP, SCHEMA, WSDL, XMLNS, DSIG, ENCRYPTION
|
||||
except:
|
||||
class SOAP:
|
||||
ENV = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
ENC = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
ACTOR_NEXT = "http://schemas.xmlsoap.org/soap/actor/next"
|
||||
|
||||
class SCHEMA:
|
||||
XSD1 = "http://www.w3.org/1999/XMLSchema"
|
||||
XSD2 = "http://www.w3.org/2000/10/XMLSchema"
|
||||
XSD3 = "http://www.w3.org/2001/XMLSchema"
|
||||
XSD_LIST = [ XSD1, XSD2, XSD3 ]
|
||||
XSI1 = "http://www.w3.org/1999/XMLSchema-instance"
|
||||
XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance"
|
||||
XSI3 = "http://www.w3.org/2001/XMLSchema-instance"
|
||||
XSI_LIST = [ XSI1, XSI2, XSI3 ]
|
||||
BASE = XSD3
|
||||
|
||||
class WSDL:
|
||||
BASE = "http://schemas.xmlsoap.org/wsdl/"
|
||||
BIND_HTTP = "http://schemas.xmlsoap.org/wsdl/http/"
|
||||
BIND_MIME = "http://schemas.xmlsoap.org/wsdl/mime/"
|
||||
BIND_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
|
||||
class XMLNS:
|
||||
BASE = "http://www.w3.org/2000/xmlns/"
|
||||
XML = "http://www.w3.org/XML/1998/namespace"
|
||||
HTML = "http://www.w3.org/TR/REC-html40"
|
||||
|
||||
class DSIG:
|
||||
BASE = "http://www.w3.org/2000/09/xmldsig#"
|
||||
C14N = "http://www.w3.org/TR/2000/CR-xml-c14n-20010315"
|
||||
C14N_COMM = "http://www.w3.org/TR/2000/CR-xml-c14n-20010315#WithComments"
|
||||
C14N_EXCL = "http://www.w3.org/2001/10/xml-exc-c14n#"
|
||||
DIGEST_MD2 = "http://www.w3.org/2000/09/xmldsig#md2"
|
||||
DIGEST_MD5 = "http://www.w3.org/2000/09/xmldsig#md5"
|
||||
DIGEST_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
|
||||
ENC_BASE64 = "http://www.w3.org/2000/09/xmldsig#base64"
|
||||
ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
|
||||
HMAC_SHA1 = "http://www.w3.org/2000/09/xmldsig#hmac-sha1"
|
||||
SIG_DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"
|
||||
SIG_RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
|
||||
XPATH = "http://www.w3.org/TR/1999/REC-xpath-19991116"
|
||||
XSLT = "http://www.w3.org/TR/1999/REC-xslt-19991116"
|
||||
|
||||
class ENCRYPTION:
|
||||
BASE = "http://www.w3.org/2001/04/xmlenc#"
|
||||
BLOCK_3DES = "http://www.w3.org/2001/04/xmlenc#des-cbc"
|
||||
BLOCK_AES128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
|
||||
BLOCK_AES192 = "http://www.w3.org/2001/04/xmlenc#aes192-cbc"
|
||||
BLOCK_AES256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
|
||||
DIGEST_RIPEMD160 = "http://www.w3.org/2001/04/xmlenc#ripemd160"
|
||||
DIGEST_SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256"
|
||||
DIGEST_SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512"
|
||||
KA_DH = "http://www.w3.org/2001/04/xmlenc#dh"
|
||||
KT_RSA_1_5 = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
|
||||
KT_RSA_OAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"
|
||||
STREAM_ARCFOUR = "http://www.w3.org/2001/04/xmlenc#arcfour"
|
||||
WRAP_3DES = "http://www.w3.org/2001/04/xmlenc#kw-3des"
|
||||
WRAP_AES128 = "http://www.w3.org/2001/04/xmlenc#kw-aes128"
|
||||
WRAP_AES192 = "http://www.w3.org/2001/04/xmlenc#kw-aes192"
|
||||
WRAP_AES256 = "http://www.w3.org/2001/04/xmlenc#kw-aes256"
|
||||
|
||||
|
||||
class WSSE:
|
||||
BASE = "http://schemas.xmlsoap.org/ws/2002/04/secext"
|
||||
|
||||
class WSU:
|
||||
BASE = "http://schemas.xmlsoap.org/ws/2002/04/utility"
|
||||
UTILITY = "http://schemas.xmlsoap.org/ws/2002/07/utility"
|
||||
|
||||
class WSR:
|
||||
PROPERTIES = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties"
|
||||
LIFETIME = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime"
|
||||
|
||||
class WSA:
|
||||
ADDRESS = "http://schemas.xmlsoap.org/ws/2003/03/addressing"
|
||||
ADDRESS2004 = "http://schemas.xmlsoap.org/ws/2004/03/addressing"
|
||||
ANONYMOUS = "%s/role/anonymous" %ADDRESS
|
||||
ANONYMOUS2004 = "%s/role/anonymous" %ADDRESS2004
|
||||
FAULT = "http://schemas.xmlsoap.org/ws/2004/03/addressing/fault"
|
||||
|
||||
class WSP:
|
||||
POLICY = "http://schemas.xmlsoap.org/ws/2002/12/policy"
|
||||
|
||||
|
||||
|
179
others/SOAPpy/wstools/TimeoutSocket.py
Executable file
179
others/SOAPpy/wstools/TimeoutSocket.py
Executable file
@ -0,0 +1,179 @@
|
||||
"""Based on code from timeout_socket.py, with some tweaks for compatibility.
|
||||
These tweaks should really be rolled back into timeout_socket, but it's
|
||||
not totally clear who is maintaining it at this point. In the meantime,
|
||||
we'll use a different module name for our tweaked version to avoid any
|
||||
confusion.
|
||||
|
||||
The original timeout_socket is by:
|
||||
|
||||
Scott Cotton <scott@chronis.pobox.com>
|
||||
Lloyd Zusman <ljz@asfast.com>
|
||||
Phil Mayes <pmayes@olivebr.com>
|
||||
Piers Lauder <piers@cs.su.oz.au>
|
||||
Radovan Garabik <garabik@melkor.dnp.fmph.uniba.sk>
|
||||
"""
|
||||
|
||||
ident = "$Id$"
|
||||
|
||||
import string, socket, select, errno
|
||||
|
||||
WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022)
|
||||
|
||||
|
||||
class TimeoutSocket:
|
||||
"""A socket imposter that supports timeout limits."""
|
||||
|
||||
def __init__(self, timeout=20, sock=None):
|
||||
self.timeout = float(timeout)
|
||||
self.inbuf = ''
|
||||
if sock is None:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock = sock
|
||||
self.sock.setblocking(0)
|
||||
self._rbuf = ''
|
||||
self._wbuf = ''
|
||||
|
||||
def __getattr__(self, name):
|
||||
# Delegate to real socket attributes.
|
||||
return getattr(self.sock, name)
|
||||
|
||||
def connect(self, *addr):
|
||||
timeout = self.timeout
|
||||
sock = self.sock
|
||||
try:
|
||||
# Non-blocking mode
|
||||
sock.setblocking(0)
|
||||
apply(sock.connect, addr)
|
||||
sock.setblocking(timeout != 0)
|
||||
return 1
|
||||
except socket.error,why:
|
||||
if not timeout:
|
||||
raise
|
||||
sock.setblocking(1)
|
||||
if len(why.args) == 1:
|
||||
code = 0
|
||||
else:
|
||||
code, why = why
|
||||
if code not in (
|
||||
errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK
|
||||
):
|
||||
raise
|
||||
r,w,e = select.select([],[sock],[],timeout)
|
||||
if w:
|
||||
try:
|
||||
apply(sock.connect, addr)
|
||||
return 1
|
||||
except socket.error,why:
|
||||
if len(why.args) == 1:
|
||||
code = 0
|
||||
else:
|
||||
code, why = why
|
||||
if code in (errno.EISCONN, WSAEINVAL):
|
||||
return 1
|
||||
raise
|
||||
raise TimeoutError('socket connect() timeout.')
|
||||
|
||||
def send(self, data, flags=0):
|
||||
total = len(data)
|
||||
next = 0
|
||||
while 1:
|
||||
r, w, e = select.select([],[self.sock], [], self.timeout)
|
||||
if w:
|
||||
buff = data[next:next + 8192]
|
||||
sent = self.sock.send(buff, flags)
|
||||
next = next + sent
|
||||
if next == total:
|
||||
return total
|
||||
continue
|
||||
raise TimeoutError('socket send() timeout.')
|
||||
|
||||
def recv(self, amt, flags=0):
|
||||
if select.select([self.sock], [], [], self.timeout)[0]:
|
||||
return self.sock.recv(amt, flags)
|
||||
raise TimeoutError('socket recv() timeout.')
|
||||
|
||||
buffsize = 4096
|
||||
handles = 1
|
||||
|
||||
def makefile(self, mode="r", buffsize=-1):
|
||||
self.handles = self.handles + 1
|
||||
self.mode = mode
|
||||
return self
|
||||
|
||||
def close(self):
|
||||
self.handles = self.handles - 1
|
||||
if self.handles == 0 and self.sock.fileno() >= 0:
|
||||
self.sock.close()
|
||||
|
||||
def read(self, n=-1):
|
||||
if not isinstance(n, type(1)):
|
||||
n = -1
|
||||
if n >= 0:
|
||||
k = len(self._rbuf)
|
||||
if n <= k:
|
||||
data = self._rbuf[:n]
|
||||
self._rbuf = self._rbuf[n:]
|
||||
return data
|
||||
n = n - k
|
||||
L = [self._rbuf]
|
||||
self._rbuf = ""
|
||||
while n > 0:
|
||||
new = self.recv(max(n, self.buffsize))
|
||||
if not new: break
|
||||
k = len(new)
|
||||
if k > n:
|
||||
L.append(new[:n])
|
||||
self._rbuf = new[n:]
|
||||
break
|
||||
L.append(new)
|
||||
n = n - k
|
||||
return "".join(L)
|
||||
k = max(4096, self.buffsize)
|
||||
L = [self._rbuf]
|
||||
self._rbuf = ""
|
||||
while 1:
|
||||
new = self.recv(k)
|
||||
if not new: break
|
||||
L.append(new)
|
||||
k = min(k*2, 1024**2)
|
||||
return "".join(L)
|
||||
|
||||
def readline(self, limit=-1):
|
||||
data = ""
|
||||
i = self._rbuf.find('\n')
|
||||
while i < 0 and not (0 < limit <= len(self._rbuf)):
|
||||
new = self.recv(self.buffsize)
|
||||
if not new: break
|
||||
i = new.find('\n')
|
||||
if i >= 0: i = i + len(self._rbuf)
|
||||
self._rbuf = self._rbuf + new
|
||||
if i < 0: i = len(self._rbuf)
|
||||
else: i = i+1
|
||||
if 0 <= limit < len(self._rbuf): i = limit
|
||||
data, self._rbuf = self._rbuf[:i], self._rbuf[i:]
|
||||
return data
|
||||
|
||||
def readlines(self, sizehint = 0):
|
||||
total = 0
|
||||
list = []
|
||||
while 1:
|
||||
line = self.readline()
|
||||
if not line: break
|
||||
list.append(line)
|
||||
total += len(line)
|
||||
if sizehint and total >= sizehint:
|
||||
break
|
||||
return list
|
||||
|
||||
def writelines(self, list):
|
||||
self.send(''.join(list))
|
||||
|
||||
def write(self, data):
|
||||
self.send(data)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
|
||||
class TimeoutError(Exception):
|
||||
pass
|
99
others/SOAPpy/wstools/UserTuple.py
Executable file
99
others/SOAPpy/wstools/UserTuple.py
Executable file
@ -0,0 +1,99 @@
|
||||
"""
|
||||
A more or less complete user-defined wrapper around tuple objects.
|
||||
Adapted version of the standard library's UserList.
|
||||
|
||||
Taken from Stefan Schwarzer's ftputil library, available at
|
||||
<http://www.ndh.net/home/sschwarzer/python/python_software.html>, and used under this license:
|
||||
|
||||
|
||||
|
||||
|
||||
Copyright (C) 1999, Stefan Schwarzer
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the above author nor the names of the
|
||||
contributors to the software may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
# $Id$
|
||||
|
||||
#XXX tuple instances (in Python 2.2) contain also:
|
||||
# __class__, __delattr__, __getattribute__, __hash__, __new__,
|
||||
# __reduce__, __setattr__, __str__
|
||||
# What about these?
|
||||
|
||||
class UserTuple:
|
||||
def __init__(self, inittuple=None):
|
||||
self.data = ()
|
||||
if inittuple is not None:
|
||||
# XXX should this accept an arbitrary sequence?
|
||||
if type(inittuple) == type(self.data):
|
||||
self.data = inittuple
|
||||
elif isinstance(inittuple, UserTuple):
|
||||
# this results in
|
||||
# self.data is inittuple.data
|
||||
# but that's ok for tuples because they are
|
||||
# immutable. (Builtin tuples behave the same.)
|
||||
self.data = inittuple.data[:]
|
||||
else:
|
||||
# the same applies here; (t is tuple(t)) == 1
|
||||
self.data = tuple(inittuple)
|
||||
def __repr__(self): return repr(self.data)
|
||||
def __lt__(self, other): return self.data < self.__cast(other)
|
||||
def __le__(self, other): return self.data <= self.__cast(other)
|
||||
def __eq__(self, other): return self.data == self.__cast(other)
|
||||
def __ne__(self, other): return self.data != self.__cast(other)
|
||||
def __gt__(self, other): return self.data > self.__cast(other)
|
||||
def __ge__(self, other): return self.data >= self.__cast(other)
|
||||
def __cast(self, other):
|
||||
if isinstance(other, UserTuple): return other.data
|
||||
else: return other
|
||||
def __cmp__(self, other):
|
||||
return cmp(self.data, self.__cast(other))
|
||||
def __contains__(self, item): return item in self.data
|
||||
def __len__(self): return len(self.data)
|
||||
def __getitem__(self, i): return self.data[i]
|
||||
def __getslice__(self, i, j):
|
||||
i = max(i, 0); j = max(j, 0)
|
||||
return self.__class__(self.data[i:j])
|
||||
def __add__(self, other):
|
||||
if isinstance(other, UserTuple):
|
||||
return self.__class__(self.data + other.data)
|
||||
elif isinstance(other, type(self.data)):
|
||||
return self.__class__(self.data + other)
|
||||
else:
|
||||
return self.__class__(self.data + tuple(other))
|
||||
# dir( () ) contains no __radd__ (at least in Python 2.2)
|
||||
def __mul__(self, n):
|
||||
return self.__class__(self.data*n)
|
||||
__rmul__ = __mul__
|
||||
|
839
others/SOAPpy/wstools/Utility.py
Executable file
839
others/SOAPpy/wstools/Utility.py
Executable file
@ -0,0 +1,839 @@
|
||||
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE.
|
||||
|
||||
ident = "$Id$"
|
||||
|
||||
import types
|
||||
import string, httplib, smtplib, urllib, socket, weakref
|
||||
import xml.dom.minidom
|
||||
from string import join, strip, split
|
||||
from UserDict import UserDict
|
||||
from StringIO import StringIO
|
||||
from TimeoutSocket import TimeoutSocket, TimeoutError
|
||||
from urlparse import urlparse
|
||||
from httplib import HTTPConnection, HTTPSConnection
|
||||
from exceptions import Exception
|
||||
|
||||
try:
|
||||
from xml.dom.ext import SplitQName
|
||||
except:
|
||||
def SplitQName(qname):
|
||||
'''SplitQName(qname) -> (string, string)
|
||||
|
||||
Split Qualified Name into a tuple of len 2, consisting
|
||||
of the prefix and the local name.
|
||||
|
||||
(prefix, localName)
|
||||
|
||||
Special Cases:
|
||||
xmlns -- (localName, 'xmlns')
|
||||
None -- (None, localName)
|
||||
'''
|
||||
|
||||
l = qname.split(':')
|
||||
if len(l) == 1:
|
||||
l.insert(0, None)
|
||||
elif len(l) == 2:
|
||||
if l[0] == 'xmlns':
|
||||
l.reverse()
|
||||
else:
|
||||
return
|
||||
return tuple(l)
|
||||
|
||||
class RecursionError(Exception):
|
||||
"""Used to indicate a HTTP redirect recursion."""
|
||||
pass
|
||||
|
||||
class HTTPResponse:
|
||||
"""Captures the information in an HTTP response message."""
|
||||
|
||||
def __init__(self, response):
|
||||
self.status = response.status
|
||||
self.reason = response.reason
|
||||
self.headers = response.msg
|
||||
self.body = response.read() or None
|
||||
response.close()
|
||||
|
||||
class TimeoutHTTP(HTTPConnection):
|
||||
"""A custom http connection object that supports socket timeout."""
|
||||
def __init__(self, host, port=None, timeout=20):
|
||||
HTTPConnection.__init__(self, host, port)
|
||||
self.timeout = timeout
|
||||
|
||||
def connect(self):
|
||||
self.sock = TimeoutSocket(self.timeout)
|
||||
self.sock.connect((self.host, self.port))
|
||||
|
||||
|
||||
class TimeoutHTTPS(HTTPSConnection):
|
||||
"""A custom https object that supports socket timeout. Note that this
|
||||
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
|
||||
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
|
||||
connect() time, it should at least provide some timeout protection."""
|
||||
def __init__(self, host, port=None, timeout=20, **kwargs):
|
||||
HTTPSConnection.__init__(self, str(host), port, **kwargs)
|
||||
self.timeout = timeout
|
||||
|
||||
def connect(self):
|
||||
sock = TimeoutSocket(self.timeout)
|
||||
sock.connect((self.host, self.port))
|
||||
realsock = getattr(sock.sock, '_sock', sock.sock)
|
||||
ssl = socket.ssl(realsock, self.key_file, self.cert_file)
|
||||
self.sock = httplib.FakeSocket(sock, ssl)
|
||||
|
||||
def urlopen(url, timeout=20, redirects=None):
|
||||
"""A minimal urlopen replacement hack that supports timeouts for http.
|
||||
Note that this supports GET only."""
|
||||
scheme, host, path, params, query, frag = urlparse(url)
|
||||
if not scheme in ('http', 'https'):
|
||||
return urllib.urlopen(url)
|
||||
if params: path = '%s;%s' % (path, params)
|
||||
if query: path = '%s?%s' % (path, query)
|
||||
if frag: path = '%s#%s' % (path, frag)
|
||||
|
||||
if scheme == 'https':
|
||||
# If ssl is not compiled into Python, you will not get an exception
|
||||
# until a conn.endheaders() call. We need to know sooner, so use
|
||||
# getattr.
|
||||
if hasattr(socket, 'ssl'):
|
||||
conn = TimeoutHTTPS(host, None, timeout)
|
||||
else:
|
||||
import M2Crypto
|
||||
ctx = M2Crypto.SSL.Context()
|
||||
ctx.set_session_timeout(timeout)
|
||||
conn = M2Crypto.httpslib.HTTPSConnection(host, ssl_context=ctx)
|
||||
#conn.set_debuglevel(1)
|
||||
else:
|
||||
conn = TimeoutHTTP(host, None, timeout)
|
||||
|
||||
conn.putrequest('GET', path)
|
||||
conn.putheader('Connection', 'close')
|
||||
conn.endheaders()
|
||||
response = None
|
||||
while 1:
|
||||
response = conn.getresponse()
|
||||
if response.status != 100:
|
||||
break
|
||||
conn._HTTPConnection__state = httplib._CS_REQ_SENT
|
||||
conn._HTTPConnection__response = None
|
||||
|
||||
status = response.status
|
||||
|
||||
# If we get an HTTP redirect, we will follow it automatically.
|
||||
if status >= 300 and status < 400:
|
||||
location = response.msg.getheader('location')
|
||||
if location is not None:
|
||||
response.close()
|
||||
if redirects is not None and redirects.has_key(location):
|
||||
raise RecursionError(
|
||||
'Circular HTTP redirection detected.'
|
||||
)
|
||||
if redirects is None:
|
||||
redirects = {}
|
||||
redirects[location] = 1
|
||||
return urlopen(location, timeout, redirects)
|
||||
raise HTTPResponse(response)
|
||||
|
||||
if not (status >= 200 and status < 300):
|
||||
raise HTTPResponse(response)
|
||||
|
||||
body = StringIO(response.read())
|
||||
response.close()
|
||||
return body
|
||||
|
||||
class DOM:
|
||||
"""The DOM singleton defines a number of XML related constants and
|
||||
provides a number of utility methods for DOM related tasks. It
|
||||
also provides some basic abstractions so that the rest of the
|
||||
package need not care about actual DOM implementation in use."""
|
||||
|
||||
# Namespace stuff related to the SOAP specification.
|
||||
|
||||
NS_SOAP_ENV_1_1 = 'http://schemas.xmlsoap.org/soap/envelope/'
|
||||
NS_SOAP_ENC_1_1 = 'http://schemas.xmlsoap.org/soap/encoding/'
|
||||
|
||||
NS_SOAP_ENV_1_2 = 'http://www.w3.org/2001/06/soap-envelope'
|
||||
NS_SOAP_ENC_1_2 = 'http://www.w3.org/2001/06/soap-encoding'
|
||||
|
||||
NS_SOAP_ENV_ALL = (NS_SOAP_ENV_1_1, NS_SOAP_ENV_1_2)
|
||||
NS_SOAP_ENC_ALL = (NS_SOAP_ENC_1_1, NS_SOAP_ENC_1_2)
|
||||
|
||||
NS_SOAP_ENV = NS_SOAP_ENV_1_1
|
||||
NS_SOAP_ENC = NS_SOAP_ENC_1_1
|
||||
|
||||
_soap_uri_mapping = {
|
||||
NS_SOAP_ENV_1_1 : '1.1',
|
||||
NS_SOAP_ENV_1_2 : '1.2',
|
||||
}
|
||||
|
||||
SOAP_ACTOR_NEXT_1_1 = 'http://schemas.xmlsoap.org/soap/actor/next'
|
||||
SOAP_ACTOR_NEXT_1_2 = 'http://www.w3.org/2001/06/soap-envelope/actor/next'
|
||||
SOAP_ACTOR_NEXT_ALL = (SOAP_ACTOR_NEXT_1_1, SOAP_ACTOR_NEXT_1_2)
|
||||
|
||||
def SOAPUriToVersion(self, uri):
|
||||
"""Return the SOAP version related to an envelope uri."""
|
||||
value = self._soap_uri_mapping.get(uri)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported SOAP envelope uri: %s' % uri
|
||||
)
|
||||
|
||||
def GetSOAPEnvUri(self, version):
|
||||
"""Return the appropriate SOAP envelope uri for a given
|
||||
human-friendly SOAP version string (e.g. '1.1')."""
|
||||
attrname = 'NS_SOAP_ENV_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attrname, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported SOAP version: %s' % version
|
||||
)
|
||||
|
||||
def GetSOAPEncUri(self, version):
|
||||
"""Return the appropriate SOAP encoding uri for a given
|
||||
human-friendly SOAP version string (e.g. '1.1')."""
|
||||
attrname = 'NS_SOAP_ENC_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attrname, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported SOAP version: %s' % version
|
||||
)
|
||||
|
||||
def GetSOAPActorNextUri(self, version):
|
||||
"""Return the right special next-actor uri for a given
|
||||
human-friendly SOAP version string (e.g. '1.1')."""
|
||||
attrname = 'SOAP_ACTOR_NEXT_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attrname, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported SOAP version: %s' % version
|
||||
)
|
||||
|
||||
|
||||
# Namespace stuff related to XML Schema.
|
||||
|
||||
NS_XSD_99 = 'http://www.w3.org/1999/XMLSchema'
|
||||
NS_XSI_99 = 'http://www.w3.org/1999/XMLSchema-instance'
|
||||
|
||||
NS_XSD_00 = 'http://www.w3.org/2000/10/XMLSchema'
|
||||
NS_XSI_00 = 'http://www.w3.org/2000/10/XMLSchema-instance'
|
||||
|
||||
NS_XSD_01 = 'http://www.w3.org/2001/XMLSchema'
|
||||
NS_XSI_01 = 'http://www.w3.org/2001/XMLSchema-instance'
|
||||
|
||||
NS_XSD_ALL = (NS_XSD_99, NS_XSD_00, NS_XSD_01)
|
||||
NS_XSI_ALL = (NS_XSI_99, NS_XSI_00, NS_XSI_01)
|
||||
|
||||
NS_XSD = NS_XSD_01
|
||||
NS_XSI = NS_XSI_01
|
||||
|
||||
_xsd_uri_mapping = {
|
||||
NS_XSD_99 : NS_XSI_99,
|
||||
NS_XSD_00 : NS_XSI_00,
|
||||
NS_XSD_01 : NS_XSI_01,
|
||||
}
|
||||
|
||||
for key, value in _xsd_uri_mapping.items():
|
||||
_xsd_uri_mapping[value] = key
|
||||
|
||||
|
||||
def InstanceUriForSchemaUri(self, uri):
|
||||
"""Return the appropriate matching XML Schema instance uri for
|
||||
the given XML Schema namespace uri."""
|
||||
return self._xsd_uri_mapping.get(uri)
|
||||
|
||||
def SchemaUriForInstanceUri(self, uri):
|
||||
"""Return the appropriate matching XML Schema namespace uri for
|
||||
the given XML Schema instance namespace uri."""
|
||||
return self._xsd_uri_mapping.get(uri)
|
||||
|
||||
|
||||
# Namespace stuff related to WSDL.
|
||||
|
||||
NS_WSDL_1_1 = 'http://schemas.xmlsoap.org/wsdl/'
|
||||
NS_WSDL_ALL = (NS_WSDL_1_1,)
|
||||
NS_WSDL = NS_WSDL_1_1
|
||||
|
||||
NS_SOAP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/soap/'
|
||||
NS_HTTP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/http/'
|
||||
NS_MIME_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/mime/'
|
||||
|
||||
NS_SOAP_BINDING_ALL = (NS_SOAP_BINDING_1_1,)
|
||||
NS_HTTP_BINDING_ALL = (NS_HTTP_BINDING_1_1,)
|
||||
NS_MIME_BINDING_ALL = (NS_MIME_BINDING_1_1,)
|
||||
|
||||
NS_SOAP_BINDING = NS_SOAP_BINDING_1_1
|
||||
NS_HTTP_BINDING = NS_HTTP_BINDING_1_1
|
||||
NS_MIME_BINDING = NS_MIME_BINDING_1_1
|
||||
|
||||
NS_SOAP_HTTP_1_1 = 'http://schemas.xmlsoap.org/soap/http'
|
||||
NS_SOAP_HTTP_ALL = (NS_SOAP_HTTP_1_1,)
|
||||
NS_SOAP_HTTP = NS_SOAP_HTTP_1_1
|
||||
|
||||
|
||||
_wsdl_uri_mapping = {
|
||||
NS_WSDL_1_1 : '1.1',
|
||||
}
|
||||
|
||||
def WSDLUriToVersion(self, uri):
|
||||
"""Return the WSDL version related to a WSDL namespace uri."""
|
||||
value = self._wsdl_uri_mapping.get(uri)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported SOAP envelope uri: %s' % uri
|
||||
)
|
||||
|
||||
def GetWSDLUri(self, version):
|
||||
attr = 'NS_WSDL_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attr, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported WSDL version: %s' % version
|
||||
)
|
||||
|
||||
def GetWSDLSoapBindingUri(self, version):
|
||||
attr = 'NS_SOAP_BINDING_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attr, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported WSDL version: %s' % version
|
||||
)
|
||||
|
||||
def GetWSDLHttpBindingUri(self, version):
|
||||
attr = 'NS_HTTP_BINDING_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attr, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported WSDL version: %s' % version
|
||||
)
|
||||
|
||||
def GetWSDLMimeBindingUri(self, version):
|
||||
attr = 'NS_MIME_BINDING_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attr, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported WSDL version: %s' % version
|
||||
)
|
||||
|
||||
def GetWSDLHttpTransportUri(self, version):
|
||||
attr = 'NS_SOAP_HTTP_%s' % join(split(version, '.'), '_')
|
||||
value = getattr(self, attr, None)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(
|
||||
'Unsupported WSDL version: %s' % version
|
||||
)
|
||||
|
||||
|
||||
# Other xml namespace constants.
|
||||
NS_XMLNS = 'http://www.w3.org/2000/xmlns/'
|
||||
|
||||
|
||||
|
||||
def isElement(self, node, name, nsuri=None):
|
||||
"""Return true if the given node is an element with the given
|
||||
name and optional namespace uri."""
|
||||
if node.nodeType != node.ELEMENT_NODE:
|
||||
return 0
|
||||
return node.localName == name and \
|
||||
(nsuri is None or self.nsUriMatch(node.namespaceURI, nsuri))
|
||||
|
||||
def getElement(self, node, name, nsuri=None, default=join):
|
||||
"""Return the first child of node with a matching name and
|
||||
namespace uri, or the default if one is provided."""
|
||||
nsmatch = self.nsUriMatch
|
||||
ELEMENT_NODE = node.ELEMENT_NODE
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == ELEMENT_NODE:
|
||||
if ((child.localName == name or name is None) and
|
||||
(nsuri is None or nsmatch(child.namespaceURI, nsuri))
|
||||
):
|
||||
return child
|
||||
if default is not join:
|
||||
return default
|
||||
raise KeyError, name
|
||||
|
||||
def getElementById(self, node, id, default=join):
|
||||
"""Return the first child of node matching an id reference."""
|
||||
attrget = self.getAttr
|
||||
ELEMENT_NODE = node.ELEMENT_NODE
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == ELEMENT_NODE:
|
||||
if attrget(child, 'id') == id:
|
||||
return child
|
||||
if default is not join:
|
||||
return default
|
||||
raise KeyError, name
|
||||
|
||||
def getMappingById(self, document, depth=None, element=None,
|
||||
mapping=None, level=1):
|
||||
"""Create an id -> element mapping of those elements within a
|
||||
document that define an id attribute. The depth of the search
|
||||
may be controlled by using the (1-based) depth argument."""
|
||||
if document is not None:
|
||||
element = document.documentElement
|
||||
mapping = {}
|
||||
attr = element._attrs.get('id', None)
|
||||
if attr is not None:
|
||||
mapping[attr.value] = element
|
||||
if depth is None or depth > level:
|
||||
level = level + 1
|
||||
ELEMENT_NODE = element.ELEMENT_NODE
|
||||
for child in element.childNodes:
|
||||
if child.nodeType == ELEMENT_NODE:
|
||||
self.getMappingById(None, depth, child, mapping, level)
|
||||
return mapping
|
||||
|
||||
def getElements(self, node, name, nsuri=None):
|
||||
"""Return a sequence of the child elements of the given node that
|
||||
match the given name and optional namespace uri."""
|
||||
nsmatch = self.nsUriMatch
|
||||
result = []
|
||||
ELEMENT_NODE = node.ELEMENT_NODE
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == ELEMENT_NODE:
|
||||
if ((child.localName == name or name is None) and (
|
||||
(nsuri is None) or nsmatch(child.namespaceURI, nsuri))):
|
||||
result.append(child)
|
||||
return result
|
||||
|
||||
def hasAttr(self, node, name, nsuri=None):
|
||||
"""Return true if element has attribute with the given name and
|
||||
optional nsuri. If nsuri is not specified, returns true if an
|
||||
attribute exists with the given name with any namespace."""
|
||||
if nsuri is None:
|
||||
if node.hasAttribute(name):
|
||||
return True
|
||||
return False
|
||||
return node.hasAttributeNS(nsuri, name)
|
||||
|
||||
def getAttr(self, node, name, nsuri=None, default=join):
|
||||
"""Return the value of the attribute named 'name' with the
|
||||
optional nsuri, or the default if one is specified. If
|
||||
nsuri is not specified, an attribute that matches the
|
||||
given name will be returned regardless of namespace."""
|
||||
if nsuri is None:
|
||||
result = node._attrs.get(name, None)
|
||||
if result is None:
|
||||
for item in node._attrsNS.keys():
|
||||
if item[1] == name:
|
||||
result = node._attrsNS[item]
|
||||
break
|
||||
else:
|
||||
result = node._attrsNS.get((nsuri, name), None)
|
||||
if result is not None:
|
||||
return result.value
|
||||
if default is not join:
|
||||
return default
|
||||
return ''
|
||||
|
||||
def getAttrs(self, node):
|
||||
"""Return a Collection of all attributes
|
||||
"""
|
||||
attrs = {}
|
||||
for k,v in node._attrs.items():
|
||||
attrs[k] = v.value
|
||||
return attrs
|
||||
|
||||
def getElementText(self, node, preserve_ws=None):
|
||||
"""Return the text value of an xml element node. Leading and trailing
|
||||
whitespace is stripped from the value unless the preserve_ws flag
|
||||
is passed with a true value."""
|
||||
result = []
|
||||
for child in node.childNodes:
|
||||
nodetype = child.nodeType
|
||||
if nodetype == child.TEXT_NODE or \
|
||||
nodetype == child.CDATA_SECTION_NODE:
|
||||
result.append(child.nodeValue)
|
||||
value = join(result, '')
|
||||
if preserve_ws is None:
|
||||
value = strip(value)
|
||||
return value
|
||||
|
||||
def findNamespaceURI(self, prefix, node):
|
||||
"""Find a namespace uri given a prefix and a context node."""
|
||||
attrkey = (self.NS_XMLNS, prefix)
|
||||
DOCUMENT_NODE = node.DOCUMENT_NODE
|
||||
ELEMENT_NODE = node.ELEMENT_NODE
|
||||
while 1:
|
||||
if node.nodeType != ELEMENT_NODE:
|
||||
node = node.parentNode
|
||||
continue
|
||||
result = node._attrsNS.get(attrkey, None)
|
||||
if result is not None:
|
||||
return result.value
|
||||
if hasattr(node, '__imported__'):
|
||||
raise DOMException('Value for prefix %s not found.' % prefix)
|
||||
node = node.parentNode
|
||||
if node.nodeType == DOCUMENT_NODE:
|
||||
raise DOMException('Value for prefix %s not found.' % prefix)
|
||||
|
||||
def findDefaultNS(self, node):
|
||||
"""Return the current default namespace uri for the given node."""
|
||||
attrkey = (self.NS_XMLNS, 'xmlns')
|
||||
DOCUMENT_NODE = node.DOCUMENT_NODE
|
||||
ELEMENT_NODE = node.ELEMENT_NODE
|
||||
while 1:
|
||||
if node.nodeType != ELEMENT_NODE:
|
||||
node = node.parentNode
|
||||
continue
|
||||
result = node._attrsNS.get(attrkey, None)
|
||||
if result is not None:
|
||||
return result.value
|
||||
if hasattr(node, '__imported__'):
|
||||
raise DOMException('Cannot determine default namespace.')
|
||||
node = node.parentNode
|
||||
if node.nodeType == DOCUMENT_NODE:
|
||||
raise DOMException('Cannot determine default namespace.')
|
||||
|
||||
def findTargetNS(self, node):
|
||||
"""Return the defined target namespace uri for the given node."""
|
||||
attrget = self.getAttr
|
||||
attrkey = (self.NS_XMLNS, 'xmlns')
|
||||
DOCUMENT_NODE = node.DOCUMENT_NODE
|
||||
ELEMENT_NODE = node.ELEMENT_NODE
|
||||
while 1:
|
||||
if node.nodeType != ELEMENT_NODE:
|
||||
node = node.parentNode
|
||||
continue
|
||||
result = attrget(node, 'targetNamespace', default=None)
|
||||
if result is not None:
|
||||
return result
|
||||
node = node.parentNode
|
||||
if node.nodeType == DOCUMENT_NODE:
|
||||
raise DOMException('Cannot determine target namespace.')
|
||||
|
||||
def getTypeRef(self, element):
|
||||
"""Return (namespaceURI, name) for a type attribue of the given
|
||||
element, or None if the element does not have a type attribute."""
|
||||
typeattr = self.getAttr(element, 'type', default=None)
|
||||
if typeattr is None:
|
||||
return None
|
||||
parts = typeattr.split(':', 1)
|
||||
if len(parts) == 2:
|
||||
nsuri = self.findNamespaceURI(parts[0], element)
|
||||
else:
|
||||
nsuri = self.findDefaultNS(element)
|
||||
return (nsuri, parts[1])
|
||||
|
||||
def importNode(self, document, node, deep=0):
|
||||
"""Implements (well enough for our purposes) DOM node import."""
|
||||
nodetype = node.nodeType
|
||||
if nodetype in (node.DOCUMENT_NODE, node.DOCUMENT_TYPE_NODE):
|
||||
raise DOMException('Illegal node type for importNode')
|
||||
if nodetype == node.ENTITY_REFERENCE_NODE:
|
||||
deep = 0
|
||||
clone = node.cloneNode(deep)
|
||||
self._setOwnerDoc(document, clone)
|
||||
clone.__imported__ = 1
|
||||
return clone
|
||||
|
||||
def _setOwnerDoc(self, document, node):
|
||||
node.ownerDocument = document
|
||||
for child in node.childNodes:
|
||||
self._setOwnerDoc(document, child)
|
||||
|
||||
def nsUriMatch(self, value, wanted, strict=0, tt=type(())):
|
||||
"""Return a true value if two namespace uri values match."""
|
||||
if value == wanted or (type(wanted) is tt) and value in wanted:
|
||||
return 1
|
||||
if not strict:
|
||||
wanted = type(wanted) is tt and wanted or (wanted,)
|
||||
value = value[-1:] != '/' and value or value[:-1]
|
||||
for item in wanted:
|
||||
if item == value or item[:-1] == value:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def createDocument(self, nsuri, qname, doctype=None):
|
||||
"""Create a new writable DOM document object."""
|
||||
impl = xml.dom.minidom.getDOMImplementation()
|
||||
return impl.createDocument(nsuri, qname, doctype)
|
||||
|
||||
def loadDocument(self, data):
|
||||
"""Load an xml file from a file-like object and return a DOM
|
||||
document instance."""
|
||||
return xml.dom.minidom.parse(data)
|
||||
|
||||
def loadFromURL(self, url):
|
||||
"""Load an xml file from a URL and return a DOM document."""
|
||||
file = urlopen(url)
|
||||
try: result = self.loadDocument(file)
|
||||
finally: file.close()
|
||||
return result
|
||||
|
||||
|
||||
class DOMException(Exception):
|
||||
pass
|
||||
|
||||
DOM = DOM()
|
||||
|
||||
|
||||
class Collection(UserDict):
|
||||
"""Helper class for maintaining ordered named collections."""
|
||||
default = lambda self,k: k.name
|
||||
def __init__(self, parent, key=None):
|
||||
UserDict.__init__(self)
|
||||
self.parent = weakref.ref(parent)
|
||||
self.list = []
|
||||
self._func = key or self.default
|
||||
|
||||
def __getitem__(self, key):
|
||||
if type(key) is type(1):
|
||||
return self.list[key]
|
||||
return self.data[key]
|
||||
|
||||
def __setitem__(self, key, item):
|
||||
item.parent = weakref.ref(self)
|
||||
self.list.append(item)
|
||||
self.data[key] = item
|
||||
|
||||
def keys(self):
|
||||
return map(lambda i: self._func(i), self.list)
|
||||
|
||||
def items(self):
|
||||
return map(lambda i: (self._func(i), i), self.list)
|
||||
|
||||
def values(self):
|
||||
return self.list
|
||||
|
||||
|
||||
class CollectionNS(UserDict):
|
||||
"""Helper class for maintaining ordered named collections."""
|
||||
default = lambda self,k: k.name
|
||||
def __init__(self, parent, key=None):
|
||||
UserDict.__init__(self)
|
||||
self.parent = weakref.ref(parent)
|
||||
self.targetNamespace = None
|
||||
self.list = []
|
||||
self._func = key or self.default
|
||||
|
||||
def __getitem__(self, key):
|
||||
self.targetNamespace = self.parent().targetNamespace
|
||||
if type(key) is types.IntType:
|
||||
return self.list[key]
|
||||
elif self.__isSequence(key):
|
||||
nsuri,name = key
|
||||
return self.data[nsuri][name]
|
||||
return self.data[self.parent().targetNamespace][key]
|
||||
|
||||
def __setitem__(self, key, item):
|
||||
item.parent = weakref.ref(self)
|
||||
self.list.append(item)
|
||||
targetNamespace = getattr(item, 'targetNamespace', self.parent().targetNamespace)
|
||||
if not self.data.has_key(targetNamespace):
|
||||
self.data[targetNamespace] = {}
|
||||
self.data[targetNamespace][key] = item
|
||||
|
||||
def __isSequence(self, key):
|
||||
return (type(key) in (types.TupleType,types.ListType) and len(key) == 2)
|
||||
|
||||
def keys(self):
|
||||
keys = []
|
||||
for tns in self.data.keys():
|
||||
keys.append(map(lambda i: (tns,self._func(i)), self.data[tns].values()))
|
||||
return keys
|
||||
|
||||
def items(self):
|
||||
return map(lambda i: (self._func(i), i), self.list)
|
||||
|
||||
def values(self):
|
||||
return self.list
|
||||
|
||||
|
||||
|
||||
# This is a runtime guerilla patch for pulldom (used by minidom) so
|
||||
# that xml namespace declaration attributes are not lost in parsing.
|
||||
# We need them to do correct QName linking for XML Schema and WSDL.
|
||||
# The patch has been submitted to SF for the next Python version.
|
||||
|
||||
from xml.dom.pulldom import PullDOM, START_ELEMENT
|
||||
if 1:
|
||||
def startPrefixMapping(self, prefix, uri):
|
||||
if not hasattr(self, '_xmlns_attrs'):
|
||||
self._xmlns_attrs = []
|
||||
self._xmlns_attrs.append((prefix or 'xmlns', uri))
|
||||
self._ns_contexts.append(self._current_context.copy())
|
||||
self._current_context[uri] = prefix or ''
|
||||
|
||||
PullDOM.startPrefixMapping = startPrefixMapping
|
||||
|
||||
def startElementNS(self, name, tagName , attrs):
|
||||
# Retrieve xml namespace declaration attributes.
|
||||
xmlns_uri = 'http://www.w3.org/2000/xmlns/'
|
||||
xmlns_attrs = getattr(self, '_xmlns_attrs', None)
|
||||
if xmlns_attrs is not None:
|
||||
for aname, value in xmlns_attrs:
|
||||
attrs._attrs[(xmlns_uri, aname)] = value
|
||||
self._xmlns_attrs = []
|
||||
uri, localname = name
|
||||
if uri:
|
||||
# When using namespaces, the reader may or may not
|
||||
# provide us with the original name. If not, create
|
||||
# *a* valid tagName from the current context.
|
||||
if tagName is None:
|
||||
prefix = self._current_context[uri]
|
||||
if prefix:
|
||||
tagName = prefix + ":" + localname
|
||||
else:
|
||||
tagName = localname
|
||||
if self.document:
|
||||
node = self.document.createElementNS(uri, tagName)
|
||||
else:
|
||||
node = self.buildDocument(uri, tagName)
|
||||
else:
|
||||
# When the tagname is not prefixed, it just appears as
|
||||
# localname
|
||||
if self.document:
|
||||
node = self.document.createElement(localname)
|
||||
else:
|
||||
node = self.buildDocument(None, localname)
|
||||
|
||||
for aname,value in attrs.items():
|
||||
a_uri, a_localname = aname
|
||||
if a_uri == xmlns_uri:
|
||||
if a_localname == 'xmlns':
|
||||
qname = a_localname
|
||||
else:
|
||||
qname = 'xmlns:' + a_localname
|
||||
attr = self.document.createAttributeNS(a_uri, qname)
|
||||
node.setAttributeNodeNS(attr)
|
||||
elif a_uri:
|
||||
prefix = self._current_context[a_uri]
|
||||
if prefix:
|
||||
qname = prefix + ":" + a_localname
|
||||
else:
|
||||
qname = a_localname
|
||||
attr = self.document.createAttributeNS(a_uri, qname)
|
||||
node.setAttributeNodeNS(attr)
|
||||
else:
|
||||
attr = self.document.createAttribute(a_localname)
|
||||
node.setAttributeNode(attr)
|
||||
attr.value = value
|
||||
|
||||
self.lastEvent[1] = [(START_ELEMENT, node), None]
|
||||
self.lastEvent = self.lastEvent[1]
|
||||
self.push(node)
|
||||
|
||||
PullDOM.startElementNS = startElementNS
|
||||
|
||||
#
|
||||
# This is a runtime guerilla patch for minidom so
|
||||
# that xmlns prefixed attributes dont raise AttributeErrors
|
||||
# during cloning.
|
||||
#
|
||||
# Namespace declarations can appear in any start-tag, must look for xmlns
|
||||
# prefixed attribute names during cloning.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# xml.dom.minidom.Attr.nodeName = xmlns:xsd
|
||||
# xml.dom.minidom.Attr.value = = http://www.w3.org/2001/XMLSchema
|
||||
|
||||
if 1:
|
||||
def _clone_node(node, deep, newOwnerDocument):
|
||||
"""
|
||||
Clone a node and give it the new owner document.
|
||||
Called by Node.cloneNode and Document.importNode
|
||||
"""
|
||||
if node.ownerDocument.isSameNode(newOwnerDocument):
|
||||
operation = xml.dom.UserDataHandler.NODE_CLONED
|
||||
else:
|
||||
operation = xml.dom.UserDataHandler.NODE_IMPORTED
|
||||
if node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE:
|
||||
clone = newOwnerDocument.createElementNS(node.namespaceURI,
|
||||
node.nodeName)
|
||||
for attr in node.attributes.values():
|
||||
clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
|
||||
|
||||
prefix, tag = xml.dom.minidom._nssplit(attr.nodeName)
|
||||
if prefix == 'xmlns':
|
||||
a = clone.getAttributeNodeNS(attr.namespaceURI, tag)
|
||||
elif prefix:
|
||||
a = clone.getAttributeNodeNS(attr.namespaceURI, tag)
|
||||
else:
|
||||
a = clone.getAttributeNodeNS(attr.namespaceURI, attr.nodeName)
|
||||
a.specified = attr.specified
|
||||
|
||||
if deep:
|
||||
for child in node.childNodes:
|
||||
c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument)
|
||||
clone.appendChild(c)
|
||||
elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_FRAGMENT_NODE:
|
||||
clone = newOwnerDocument.createDocumentFragment()
|
||||
if deep:
|
||||
for child in node.childNodes:
|
||||
c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument)
|
||||
clone.appendChild(c)
|
||||
|
||||
elif node.nodeType == xml.dom.minidom.Node.TEXT_NODE:
|
||||
clone = newOwnerDocument.createTextNode(node.data)
|
||||
elif node.nodeType == xml.dom.minidom.Node.CDATA_SECTION_NODE:
|
||||
clone = newOwnerDocument.createCDATASection(node.data)
|
||||
elif node.nodeType == xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE:
|
||||
clone = newOwnerDocument.createProcessingInstruction(node.target,
|
||||
node.data)
|
||||
elif node.nodeType == xml.dom.minidom.Node.COMMENT_NODE:
|
||||
clone = newOwnerDocument.createComment(node.data)
|
||||
elif node.nodeType == xml.dom.minidom.Node.ATTRIBUTE_NODE:
|
||||
clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
|
||||
node.nodeName)
|
||||
clone.specified = True
|
||||
clone.value = node.value
|
||||
elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_TYPE_NODE:
|
||||
assert node.ownerDocument is not newOwnerDocument
|
||||
operation = xml.dom.UserDataHandler.NODE_IMPORTED
|
||||
clone = newOwnerDocument.implementation.createDocumentType(
|
||||
node.name, node.publicId, node.systemId)
|
||||
clone.ownerDocument = newOwnerDocument
|
||||
if deep:
|
||||
clone.entities._seq = []
|
||||
clone.notations._seq = []
|
||||
for n in node.notations._seq:
|
||||
notation = xml.dom.minidom.Notation(n.nodeName, n.publicId, n.systemId)
|
||||
notation.ownerDocument = newOwnerDocument
|
||||
clone.notations._seq.append(notation)
|
||||
if hasattr(n, '_call_user_data_handler'):
|
||||
n._call_user_data_handler(operation, n, notation)
|
||||
for e in node.entities._seq:
|
||||
entity = xml.dom.minidom.Entity(e.nodeName, e.publicId, e.systemId,
|
||||
e.notationName)
|
||||
entity.actualEncoding = e.actualEncoding
|
||||
entity.encoding = e.encoding
|
||||
entity.version = e.version
|
||||
entity.ownerDocument = newOwnerDocument
|
||||
clone.entities._seq.append(entity)
|
||||
if hasattr(e, '_call_user_data_handler'):
|
||||
e._call_user_data_handler(operation, n, entity)
|
||||
else:
|
||||
# Note the cloning of Document and DocumentType nodes is
|
||||
# implemenetation specific. minidom handles those cases
|
||||
# directly in the cloneNode() methods.
|
||||
raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
|
||||
|
||||
# Check for _call_user_data_handler() since this could conceivably
|
||||
# used with other DOM implementations (one of the FourThought
|
||||
# DOMs, perhaps?).
|
||||
if hasattr(node, '_call_user_data_handler'):
|
||||
node._call_user_data_handler(operation, node, clone)
|
||||
return clone
|
||||
|
||||
xml.dom.minidom._clone_node = _clone_node
|
1336
others/SOAPpy/wstools/WSDLTools.py
Executable file
1336
others/SOAPpy/wstools/WSDLTools.py
Executable file
File diff suppressed because it is too large
Load Diff
2976
others/SOAPpy/wstools/XMLSchema.py
Executable file
2976
others/SOAPpy/wstools/XMLSchema.py
Executable file
File diff suppressed because it is too large
Load Diff
88
others/SOAPpy/wstools/XMLname.py
Executable file
88
others/SOAPpy/wstools/XMLname.py
Executable file
@ -0,0 +1,88 @@
|
||||
"""Translate strings to and from SOAP 1.2 XML name encoding
|
||||
|
||||
Implements rules for mapping application defined name to XML names
|
||||
specified by the w3 SOAP working group for SOAP version 1.2 in
|
||||
Appendix A of "SOAP Version 1.2 Part 2: Adjuncts", W3C Working Draft
|
||||
17, December 2001, <http://www.w3.org/TR/soap12-part2/#namemap>
|
||||
|
||||
Also see <http://www.w3.org/2000/xp/Group/xmlp-issues>.
|
||||
|
||||
Author: Gregory R. Warnes <gregory_r_warnes@groton.pfizer.com>
|
||||
Date:: 2002-04-25
|
||||
Version 0.9.0
|
||||
|
||||
"""
|
||||
|
||||
ident = "$Id$"
|
||||
|
||||
from re import *
|
||||
|
||||
|
||||
def _NCNameChar(x):
|
||||
return x.isalpha() or x.isdigit() or x=="." or x=='-' or x=="_"
|
||||
|
||||
|
||||
def _NCNameStartChar(x):
|
||||
return x.isalpha() or x=="_"
|
||||
|
||||
|
||||
def _toUnicodeHex(x):
|
||||
hexval = hex(ord(x[0]))[2:]
|
||||
hexlen = len(hexval)
|
||||
# Make hexval have either 4 or 8 digits by prepending 0's
|
||||
if (hexlen==1): hexval = "000" + hexval
|
||||
elif (hexlen==2): hexval = "00" + hexval
|
||||
elif (hexlen==3): hexval = "0" + hexval
|
||||
elif (hexlen==4): hexval = "" + hexval
|
||||
elif (hexlen==5): hexval = "000" + hexval
|
||||
elif (hexlen==6): hexval = "00" + hexval
|
||||
elif (hexlen==7): hexval = "0" + hexval
|
||||
elif (hexlen==8): hexval = "" + hexval
|
||||
else: raise Exception, "Illegal Value returned from hex(ord(x))"
|
||||
|
||||
return "_x"+ hexval + "_"
|
||||
|
||||
|
||||
def _fromUnicodeHex(x):
|
||||
return eval( r'u"\u'+x[2:-1]+'"' )
|
||||
|
||||
|
||||
def toXMLname(string):
|
||||
"""Convert string to a XML name."""
|
||||
if string.find(':') != -1 :
|
||||
(prefix, localname) = string.split(':',1)
|
||||
else:
|
||||
prefix = None
|
||||
localname = string
|
||||
|
||||
T = unicode(localname)
|
||||
|
||||
N = len(localname)
|
||||
X = [];
|
||||
for i in range(N) :
|
||||
if i< N-1 and T[i]==u'_' and T[i+1]==u'x':
|
||||
X.append(u'_x005F_')
|
||||
elif i==0 and N >= 3 and \
|
||||
( T[0]==u'x' or T[0]==u'X' ) and \
|
||||
( T[1]==u'm' or T[1]==u'M' ) and \
|
||||
( T[2]==u'l' or T[2]==u'L' ):
|
||||
X.append(u'_xFFFF_' + T[0])
|
||||
elif (not _NCNameChar(T[i])) or (i==0 and not _NCNameStartChar(T[i])):
|
||||
X.append(_toUnicodeHex(T[i]))
|
||||
else:
|
||||
X.append(T[i])
|
||||
|
||||
return u''.join(X)
|
||||
|
||||
|
||||
def fromXMLname(string):
|
||||
"""Convert XML name to unicode string."""
|
||||
|
||||
retval = sub(r'_xFFFF_','', string )
|
||||
|
||||
def fun( matchobj ):
|
||||
return _fromUnicodeHex( matchobj.group(0) )
|
||||
|
||||
retval = sub(r'_x[0-9A-Za-z]+_', fun, retval )
|
||||
|
||||
return retval
|
36
others/SOAPpy/wstools/__init__.py
Normal file
36
others/SOAPpy/wstools/__init__.py
Normal file
@ -0,0 +1,36 @@
|
||||
#! /usr/bin/env python
|
||||
"""WSDL parsing services package for Web Services for Python."""
|
||||
|
||||
ident = "$Id$"
|
||||
|
||||
import WSDLTools
|
||||
import XMLname
|
||||
from logging import getLogger as _getLogger
|
||||
import logging.config as _config
|
||||
|
||||
LOGGING = 'logging.txt'
|
||||
DEBUG = True
|
||||
|
||||
#
|
||||
# If LOGGING configuration file is not found, turn off logging
|
||||
# and use _noLogger class because logging module's performance
|
||||
# is terrible.
|
||||
#
|
||||
|
||||
try:
|
||||
_config.fileConfig(LOGGING)
|
||||
except:
|
||||
DEBUG = False
|
||||
|
||||
|
||||
class Base:
|
||||
def __init__(self, module=__name__):
|
||||
self.logger = _noLogger()
|
||||
if DEBUG is True:
|
||||
self.logger = _getLogger('%s-%s(%x)' %(module, self.__class__, id(self)))
|
||||
|
||||
class _noLogger:
|
||||
def __init__(self, *args): pass
|
||||
def warning(self, *args): pass
|
||||
def debug(self, *args): pass
|
||||
def error(self, *args): pass
|
703
others/google.py
703
others/google.py
@ -1,40 +1,51 @@
|
||||
"""Python wrapper for Google web APIs
|
||||
"""
|
||||
Python wrapper for Google web APIs
|
||||
|
||||
This module allows you to access Google's web APIs through SOAP,
|
||||
to do things like search Google and get the results programmatically.
|
||||
Described here:
|
||||
http://www.google.com/apis/
|
||||
Described U{here <http://www.google.com/apis/>}
|
||||
|
||||
You need a Google-provided license key to use these services.
|
||||
Follow the link above to get one. These functions will look in
|
||||
several places (in this order) for the license key:
|
||||
- the "license_key" argument of each function
|
||||
- the module-level LICENSE_KEY variable (call setLicense once to set it)
|
||||
- an environment variable called GOOGLE_LICENSE_KEY
|
||||
- a file called ".googlekey" in the current directory
|
||||
- a file called "googlekey.txt" in the current directory
|
||||
- a file called ".googlekey" in your home directory
|
||||
- a file called "googlekey.txt" in your home directory
|
||||
- a file called ".googlekey" in the same directory as google.py
|
||||
- a file called "googlekey.txt" in the same directory as google.py
|
||||
|
||||
Sample usage:
|
||||
>>> import google
|
||||
>>> google.setLicense('...') # must get your own key!
|
||||
>>> data = google.doGoogleSearch('python')
|
||||
>>> data.meta.searchTime
|
||||
0.043221000000000002
|
||||
>>> data.results[0].URL
|
||||
'http://www.python.org/'
|
||||
>>> data.results[0].title
|
||||
'<b>Python</b> Language Website'
|
||||
- the "license_key" argument of each function
|
||||
- the module-level LICENSE_KEY variable (call setLicense once to set it)
|
||||
- an environment variable called GOOGLE_LICENSE_KEY
|
||||
- a file called ".googlekey" in the current directory
|
||||
- a file called "googlekey.txt" in the current directory
|
||||
- a file called ".googlekey" in your home directory
|
||||
- a file called "googlekey.txt" in your home directory
|
||||
- a file called ".googlekey" in the same directory as google.py
|
||||
- a file called "googlekey.txt" in the same directory as google.py
|
||||
|
||||
See documentation of SearchResultsMetaData and SearchResult classes
|
||||
for other available attributes.
|
||||
Sample usage::
|
||||
|
||||
>>> import google
|
||||
>>> google.setLicense('...') # must get your own key!
|
||||
>>> data = google.doGoogleSearch('python')
|
||||
>>> data.meta.searchTime
|
||||
0.043221000000000002
|
||||
|
||||
>>> data.results[0].URL
|
||||
'http://www.python.org/'
|
||||
|
||||
>>> data.results[0].title
|
||||
'<b>Python</b> Language Website'
|
||||
|
||||
@newfield contrib: Contributors
|
||||
@author: Mark Pilgrim <f8dy@diveintomark.org>
|
||||
@author: Brian Landers <brian@bluecoat93.org>
|
||||
@license: Python
|
||||
@version: 0.6
|
||||
@contrib: David Ascher, for the install script
|
||||
@contrib: Erik Max Francis, for the command line interface
|
||||
@contrib: Michael Twomey, for HTTP proxy support
|
||||
@contrib: Mark Recht, for patches to support SOAPpy
|
||||
"""
|
||||
|
||||
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
|
||||
__version__ = "0.5.2"
|
||||
__version__ = "0.6"
|
||||
__cvsversion__ = "$Revision$"[11:-2]
|
||||
__date__ = "$Date$"[7:-2]
|
||||
__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
|
||||
@ -43,34 +54,62 @@ __credits__ = """David Ascher, for the install script
|
||||
Erik Max Francis, for the command line interface
|
||||
Michael Twomey, for HTTP proxy support"""
|
||||
|
||||
import SOAP
|
||||
import os, sys, getopt
|
||||
import GoogleSOAPFacade
|
||||
|
||||
LICENSE_KEY = None
|
||||
HTTP_PROXY = None
|
||||
|
||||
# don't touch the rest of these constants
|
||||
class NoLicenseKey(Exception): pass
|
||||
#
|
||||
# Constants
|
||||
#
|
||||
_url = 'http://api.google.com/search/beta2'
|
||||
_namespace = 'urn:GoogleSearch'
|
||||
_false = SOAP.booleanType(0)
|
||||
_true = SOAP.booleanType(1)
|
||||
_googlefile1 = ".googlekey"
|
||||
_googlefile2 = "googlekey.txt"
|
||||
_licenseLocations = (
|
||||
(lambda key: key, 'passed to the function in license_key variable'),
|
||||
(lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
|
||||
(lambda key: os.environ.get('GOOGLE_LICENSE_KEY', None), 'an environment variable called GOOGLE_LICENSE_KEY'),
|
||||
(lambda key: _contentsOf(os.getcwd(), _googlefile1), '%s in the current directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(os.getcwd(), _googlefile2), '%s in the current directory' % _googlefile2),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _googlefile1), '%s in your home directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(os.environ.get('HOME', ''), _googlefile2), '%s in your home directory' % _googlefile2),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _googlefile1), '%s in the google.py directory' % _googlefile1),
|
||||
(lambda key: _contentsOf(_getScriptDir(), _googlefile2), '%s in the google.py directory' % _googlefile2)
|
||||
)
|
||||
|
||||
## administrative functions
|
||||
def version():
|
||||
_false = GoogleSOAPFacade.false
|
||||
_true = GoogleSOAPFacade.true
|
||||
|
||||
_licenseLocations = (
|
||||
( lambda key: key,
|
||||
'passed to the function in license_key variable' ),
|
||||
( lambda key: LICENSE_KEY,
|
||||
'module-level LICENSE_KEY variable (call setLicense to set it)' ),
|
||||
( lambda key: os.environ.get( 'GOOGLE_LICENSE_KEY', None ),
|
||||
'an environment variable called GOOGLE_LICENSE_KEY' ),
|
||||
( lambda key: _contentsOf( os.getcwd(), _googlefile1 ),
|
||||
'%s in the current directory' % _googlefile1),
|
||||
( lambda key: _contentsOf( os.getcwd(), _googlefile2 ),
|
||||
'%s in the current directory' % _googlefile2),
|
||||
( lambda key: _contentsOf( os.environ.get( 'HOME', '' ), _googlefile1 ),
|
||||
'%s in your home directory' % _googlefile1),
|
||||
( lambda key: _contentsOf( os.environ.get( 'HOME', '' ), _googlefile2 ),
|
||||
'%s in your home directory' % _googlefile2 ),
|
||||
( lambda key: _contentsOf( _getScriptDir(), _googlefile1 ),
|
||||
'%s in the google.py directory' % _googlefile1 ),
|
||||
( lambda key: _contentsOf( _getScriptDir(), _googlefile2 ),
|
||||
'%s in the google.py directory' % _googlefile2 )
|
||||
)
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
## Exceptions
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
class NoLicenseKey(Exception):
|
||||
"""
|
||||
Thrown when the API is unable to find a valid license key.
|
||||
"""
|
||||
pass
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
## administrative functions (non-API)
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
def _version():
|
||||
"""
|
||||
Display a formatted version string for the module
|
||||
"""
|
||||
print """PyGoogle %(__version__)s
|
||||
%(__copyright__)s
|
||||
released %(__date__)s
|
||||
@ -78,7 +117,11 @@ released %(__date__)s
|
||||
Thanks to:
|
||||
%(__credits__)s""" % globals()
|
||||
|
||||
def usage():
|
||||
|
||||
def _usage():
|
||||
"""
|
||||
Display usage information for the command-line interface
|
||||
"""
|
||||
program = os.path.basename(sys.argv[0])
|
||||
print """Usage: %(program)s [options] [querytype] query
|
||||
|
||||
@ -104,32 +147,62 @@ these places (in order) and use the first license key it finds:
|
||||
for get, location in _licenseLocations[2:]:
|
||||
print " *", location
|
||||
|
||||
## utility functions
|
||||
## ----------------------------------------------------------------------
|
||||
## utility functions (API)
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
def setLicense(license_key):
|
||||
"""set license key"""
|
||||
"""
|
||||
Set the U{Google APIs <http://www.google.com/api>} license key
|
||||
|
||||
@param license_key: The new key to use
|
||||
@type license_key: String
|
||||
@todo: validate the key?
|
||||
"""
|
||||
global LICENSE_KEY
|
||||
LICENSE_KEY = license_key
|
||||
|
||||
def getLicense(license_key = None):
|
||||
"""get license key
|
||||
|
||||
license key can come from any number of locations;
|
||||
see module docs for search order"""
|
||||
def getLicense(license_key = None):
|
||||
"""
|
||||
Get the U{Google APIs <http://www.google.com/api>} license key
|
||||
|
||||
The key can be read from any number of locations. See the module-leve
|
||||
documentation for the search order.
|
||||
|
||||
@return: the license key
|
||||
@rtype: String
|
||||
@raise NoLicenseKey: if no valid key could be found
|
||||
"""
|
||||
for get, location in _licenseLocations:
|
||||
rc = get(license_key)
|
||||
if rc: return rc
|
||||
#usage()
|
||||
_usage()
|
||||
raise NoLicenseKey, 'get a license key at http://www.google.com/apis/'
|
||||
|
||||
|
||||
def setProxy(http_proxy):
|
||||
"""set HTTP proxy"""
|
||||
"""
|
||||
Set the HTTP proxy to be used when accessing Google
|
||||
|
||||
@param http_proxy: the proxy to use
|
||||
@type http_proxy: String
|
||||
@todo: validiate the input?
|
||||
"""
|
||||
global HTTP_PROXY
|
||||
HTTP_PROXY = http_proxy
|
||||
|
||||
|
||||
def getProxy(http_proxy = None):
|
||||
"""get HTTP proxy"""
|
||||
"""
|
||||
Get the HTTP proxy we use for accessing Google
|
||||
|
||||
@return: the proxy
|
||||
@rtype: String
|
||||
"""
|
||||
return http_proxy or HTTP_PROXY
|
||||
|
||||
|
||||
def _contentsOf(dirname, filename):
|
||||
filename = os.path.join(dirname, filename)
|
||||
if not os.path.exists(filename): return None
|
||||
@ -138,42 +211,335 @@ def _contentsOf(dirname, filename):
|
||||
fsock.close()
|
||||
return contents
|
||||
|
||||
|
||||
def _getScriptDir():
|
||||
if __name__ == '__main__':
|
||||
return os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
else:
|
||||
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
|
||||
|
||||
|
||||
def _marshalBoolean(value):
|
||||
if value:
|
||||
return _true
|
||||
else:
|
||||
return _false
|
||||
|
||||
## output formatters
|
||||
def makeFormatter(outputFormat):
|
||||
classname = "%sOutputFormatter" % outputFormat.capitalize()
|
||||
return globals()[classname]()
|
||||
|
||||
def output(results, params):
|
||||
formatter = makeFormatter(params.get("outputFormat", "text"))
|
||||
outputmethod = getattr(formatter, params["func"])
|
||||
outputmethod(results, params)
|
||||
def _getRemoteServer( http_proxy ):
|
||||
return GoogleSOAPFacade.getProxy( _url, _namespace, http_proxy )
|
||||
|
||||
class OutputFormatter:
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
## search results classes
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
class _SearchBase:
|
||||
def __init__(self, params):
|
||||
for k, v in params.items():
|
||||
if isinstance(v, GoogleSOAPFacade.structType):
|
||||
v = GoogleSOAPFacade.toDict( v )
|
||||
|
||||
try:
|
||||
if isinstance(v[0], GoogleSOAPFacade.structType):
|
||||
v = [ SOAPProxy.toDict( node ) for node in v ]
|
||||
|
||||
except:
|
||||
pass
|
||||
self.__dict__[str(k)] = v
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
class SearchResultsMetaData(_SearchBase):
|
||||
"""
|
||||
Container class for metadata about a given search query's results.
|
||||
|
||||
@ivar documentFiltering: is duplicate page filtering active?
|
||||
|
||||
@ivar searchComments: human-readable informational message
|
||||
|
||||
example::
|
||||
|
||||
"'the' is a very common word and was not included in your search"
|
||||
|
||||
@ivar estimatedTotalResultsCount: estimated total number of results
|
||||
for this query.
|
||||
|
||||
@ivar estimateIsExact: is estimatedTotalResultsCount an exact value?
|
||||
|
||||
@ivar searchQuery: search string that initiated this search
|
||||
|
||||
@ivar startIndex: index of the first result returned (zero-based)
|
||||
|
||||
@ivar endIndex: index of the last result returned (zero-based)
|
||||
|
||||
@ivar searchTips: human-readable informational message on how to better
|
||||
use Google.
|
||||
|
||||
@ivar directoryCategories: list of categories for the search results
|
||||
|
||||
This field is a list of dictionaries, like so::
|
||||
|
||||
{ 'fullViewableName': 'the Open Directory category',
|
||||
'specialEncoding': 'encoding scheme of this directory category'
|
||||
}
|
||||
|
||||
@ivar searchTime: total search time, in seconds
|
||||
"""
|
||||
pass
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
class SearchResult(_SearchBase):
|
||||
"""
|
||||
Encapsulates the results from a search.
|
||||
|
||||
@ivar URL: URL
|
||||
|
||||
@ivar title: title (HTML)
|
||||
|
||||
@ivar snippet: snippet showing query context (HTML
|
||||
|
||||
@ivar cachedSize: size of cached version of this result, (KB)
|
||||
|
||||
@ivar relatedInformationPresent: is the "related:" keyword supported?
|
||||
|
||||
Flag indicates that the "related:" keyword is supported for this URL
|
||||
|
||||
@ivar hostName: used when filtering occurs
|
||||
|
||||
When filtering occurs, a maximum of two results from any given
|
||||
host is returned. When this occurs, the second resultElement
|
||||
that comes from that host contains the host name in this parameter.
|
||||
|
||||
@ivar directoryCategory: Open Directory category information
|
||||
|
||||
This field is a dictionary with the following values::
|
||||
|
||||
{ 'fullViewableName': 'the Open Directory category',
|
||||
'specialEncoding' : 'encoding scheme of this directory category'
|
||||
}
|
||||
|
||||
@ivar directoryTitle: Open Directory title of this result (or blank)
|
||||
|
||||
@ivar summary: Open Directory summary for this result (or blank)
|
||||
"""
|
||||
pass
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
class SearchReturnValue:
|
||||
"""
|
||||
complete search results for a single query
|
||||
|
||||
@ivar meta: L{SearchResultsMetaData} instance for this query
|
||||
|
||||
@ivar results: list of L{SearchResult} objects for this query
|
||||
"""
|
||||
def __init__( self, metadata, results ):
|
||||
self.meta = metadata
|
||||
self.results = results
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
## main functions
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
def doGoogleSearch( q, start = 0, maxResults = 10, filter = 1,
|
||||
restrict='', safeSearch = 0, language = '',
|
||||
inputencoding = '', outputencoding = '',\
|
||||
license_key = None, http_proxy = None ):
|
||||
"""
|
||||
Search Google using the SOAP API and return the results.
|
||||
|
||||
You need a license key to call this function; see the
|
||||
U{Google APIs <http://www.google.com/apis/>} site to get one.
|
||||
Then you can either pass it to this function every time, or
|
||||
set it globally; see the L{google} module-level docs for details.
|
||||
|
||||
See U{http://www.google.com/help/features.html}
|
||||
for examples of advanced features. Anything that works at the
|
||||
Google web site will work as a query string in this method.
|
||||
|
||||
You can use the C{start} and C{maxResults} parameters to page
|
||||
through multiple pages of results. Note that 'maxResults' is
|
||||
currently limited by Google to 10.
|
||||
|
||||
See the API reference for more advanced examples and a full list of
|
||||
country codes and topics for use in the C{restrict} parameter, along
|
||||
with legal values for the C{language}, C{inputencoding}, and
|
||||
C{outputencoding} parameters.
|
||||
|
||||
You can download the API documentation
|
||||
U{http://www.google.com/apis/download.html <here>}.
|
||||
|
||||
@param q: search string.
|
||||
@type q: String
|
||||
|
||||
@param start: (optional) zero-based index of first desired result.
|
||||
@type start: int
|
||||
|
||||
@param maxResults: (optional) maximum number of results to return.
|
||||
@type maxResults: int
|
||||
|
||||
@param filter: (optional) flag to request filtering of similar results
|
||||
@type filter: int
|
||||
|
||||
@param restrict: (optional) restrict results by country or topic.
|
||||
@type restrict: String
|
||||
|
||||
@param safeSearch: (optional)
|
||||
@type safeSearch: int
|
||||
|
||||
@param language: (optional)
|
||||
@type language: String
|
||||
|
||||
@param inputencoding: (optional)
|
||||
@type inputencoding: String
|
||||
|
||||
@param outputencoding: (optional)
|
||||
@type outputencoding: String
|
||||
|
||||
@param license_key: (optional) the Google API license key to use
|
||||
@type license_key: String
|
||||
|
||||
@param http_proxy: (optional) the HTTP proxy to use for talking to Google
|
||||
@type http_proxy: String
|
||||
|
||||
@return: the search results encapsulated in an object
|
||||
@rtype: L{SearchReturnValue}
|
||||
"""
|
||||
license_key = getLicense( license_key )
|
||||
http_proxy = getProxy( http_proxy )
|
||||
remoteserver = _getRemoteServer( http_proxy )
|
||||
|
||||
filter = _marshalBoolean( filter )
|
||||
safeSearch = _marshalBoolean( safeSearch )
|
||||
|
||||
data = remoteserver.doGoogleSearch( license_key, q, start, maxResults,
|
||||
filter, restrict, safeSearch,
|
||||
language, inputencoding,
|
||||
outputencoding )
|
||||
|
||||
metadata = GoogleSOAPFacade.toDict( data )
|
||||
del metadata["resultElements"]
|
||||
|
||||
metadata = SearchResultsMetaData( metadata )
|
||||
|
||||
results = [ SearchResult( GoogleSOAPFacade.toDict( node ) ) \
|
||||
for node in data.resultElements ]
|
||||
|
||||
return SearchReturnValue( metadata, results )
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
def doGetCachedPage( url, license_key = None, http_proxy = None ):
|
||||
"""
|
||||
Retrieve a page from the Google cache.
|
||||
|
||||
You need a license key to call this function; see the
|
||||
U{Google APIs <http://www.google.com/apis/>} site to get one.
|
||||
Then you can either pass it to this function every time, or
|
||||
set it globally; see the L{google} module-level docs for details.
|
||||
|
||||
@param url: full URL to the page to retrieve
|
||||
@type url: String
|
||||
|
||||
@param license_key: (optional) the Google API key to use
|
||||
@type license_key: String
|
||||
|
||||
@param http_proxy: (optional) the HTTP proxy server to use
|
||||
@type http_proxy: String
|
||||
|
||||
@return: full text of the cached page
|
||||
@rtype: String
|
||||
"""
|
||||
license_key = getLicense( license_key )
|
||||
http_proxy = getProxy( http_proxy )
|
||||
remoteserver = _getRemoteServer( http_proxy )
|
||||
|
||||
return remoteserver.doGetCachedPage( license_key, url )
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
def doSpellingSuggestion( phrase, license_key = None, http_proxy = None ):
|
||||
"""
|
||||
Get spelling suggestions from Google
|
||||
|
||||
You need a license key to call this function; see the
|
||||
U{Google APIs <http://www.google.com/apis/>} site to get one.
|
||||
Then you can either pass it to this function every time, or
|
||||
set it globally; see the L{google} module-level docs for details.
|
||||
|
||||
@param phrase: word or phrase to spell-check
|
||||
@type phrase: String
|
||||
|
||||
@param license_key: (optional) the Google API key to use
|
||||
@type license_key: String
|
||||
|
||||
@param http_proxy: (optional) the HTTP proxy to use
|
||||
@type http_proxy: String
|
||||
|
||||
@return: text of any suggested replacement, or None
|
||||
"""
|
||||
license_key = getLicense( license_key )
|
||||
http_proxy = getProxy( http_proxy)
|
||||
remoteserver = _getRemoteServer( http_proxy )
|
||||
|
||||
return remoteserver.doSpellingSuggestion( license_key, phrase )
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
## functional test suite (see googletest.py for unit test suite)
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
def _test():
|
||||
"""
|
||||
Run functional test suite.
|
||||
"""
|
||||
try:
|
||||
getLicense(None)
|
||||
except NoLicenseKey:
|
||||
return
|
||||
|
||||
print "Searching for Python at google.com..."
|
||||
data = doGoogleSearch( "Python" )
|
||||
_output( data, { "func": "doGoogleSearch"} )
|
||||
|
||||
print "\nSearching for 5 _French_ pages about Python, "
|
||||
print "encoded in ISO-8859-1..."
|
||||
|
||||
data = doGoogleSearch( "Python", language = 'lang_fr',
|
||||
outputencoding = 'ISO-8859-1',
|
||||
maxResults = 5 )
|
||||
|
||||
_output( data, { "func": "doGoogleSearch" } )
|
||||
|
||||
phrase = "Pyhton programming languager"
|
||||
print "\nTesting spelling suggestions for '%s'..." % phrase
|
||||
|
||||
data = doSpellingSuggestion( phrase )
|
||||
|
||||
_output( data, { "func": "doSpellingSuggestion" } )
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
## Command-line interface
|
||||
## ----------------------------------------------------------------------
|
||||
|
||||
class _OutputFormatter:
|
||||
def boil(self, data):
|
||||
if type(data) == type(u""):
|
||||
return data.encode("utf-8", "replace")
|
||||
return data.encode("ISO-8859-1", "replace")
|
||||
else:
|
||||
return data
|
||||
|
||||
class TextOutputFormatter(OutputFormatter):
|
||||
class _TextOutputFormatter(_OutputFormatter):
|
||||
def common(self, data, params):
|
||||
if params.get("showMeta", 0):
|
||||
meta = data.meta
|
||||
for category in meta.directoryCategories:
|
||||
print "directoryCategory: %s" % self.boil(category["fullViewableName"])
|
||||
for attr in [node for node in dir(meta) if node <> "directoryCategories" and node[:2] <> '__']:
|
||||
print "directoryCategory: %s" % \
|
||||
self.boil(category["fullViewableName"])
|
||||
for attr in [node for node in dir(meta) if \
|
||||
node <> "directoryCategories" and node[:2] <> '__']:
|
||||
print "%s:" % attr, self.boil(getattr(meta, attr))
|
||||
|
||||
def doGoogleSearch(self, data, params):
|
||||
@ -185,7 +551,8 @@ class TextOutputFormatter(OutputFormatter):
|
||||
for result in results:
|
||||
for attr in dir(result):
|
||||
if attr == "directoryCategory":
|
||||
print "directoryCategory:", self.boil(result.directoryCategory["fullViewableName"])
|
||||
print "directoryCategory:", \
|
||||
self.boil(result.directoryCategory["fullViewableName"])
|
||||
elif attr[:2] <> '__':
|
||||
print "%s:" % attr, self.boil(getattr(result, attr))
|
||||
print
|
||||
@ -197,184 +564,21 @@ class TextOutputFormatter(OutputFormatter):
|
||||
|
||||
doSpellingSuggestion = doGetCachedPage
|
||||
|
||||
## search results classes
|
||||
class _SearchBase:
|
||||
def __init__(self, params):
|
||||
for k, v in params.items():
|
||||
if isinstance(v, SOAP.structType):
|
||||
v = v._asdict
|
||||
try:
|
||||
if isinstance(v[0], SOAP.structType):
|
||||
v = [node._asdict for node in v]
|
||||
except:
|
||||
pass
|
||||
self.__dict__[str(k)] = v
|
||||
def _makeFormatter(outputFormat):
|
||||
classname = "_%sOutputFormatter" % outputFormat.capitalize()
|
||||
return globals()[classname]()
|
||||
|
||||
class SearchResultsMetaData(_SearchBase):
|
||||
"""metadata of search query results
|
||||
def _output(results, params):
|
||||
formatter = _makeFormatter(params.get("outputFormat", "text"))
|
||||
outputmethod = getattr(formatter, params["func"])
|
||||
outputmethod(results, params)
|
||||
|
||||
Available attributes:
|
||||
documentFiltering - flag indicates whether duplicate page filtering was perfomed in this search
|
||||
searchComments - human-readable informational message (example: "'the' is a very common word
|
||||
and was not included in your search")
|
||||
estimatedTotalResultsCount - estimated total number of results for this query
|
||||
estimateIsExact - flag indicates whether estimatedTotalResultsCount is an exact value
|
||||
searchQuery - search string that initiated this search
|
||||
startIndex - index of first result returned (zero-based)
|
||||
endIndex - index of last result returned (zero-based)
|
||||
searchTips - human-readable informational message on how to use Google bette
|
||||
directoryCategories - list of dictionaries like this:
|
||||
{'fullViewableName': Open Directory category,
|
||||
'specialEncoding': encoding scheme of this directory category}
|
||||
searchTime - total search time, in seconds
|
||||
"""
|
||||
pass
|
||||
|
||||
class SearchResult(_SearchBase):
|
||||
"""search result
|
||||
|
||||
Available attributes:
|
||||
URL - URL
|
||||
title - title (HTML)
|
||||
snippet - snippet showing query context (HTML)
|
||||
cachedSize - size of cached version of this result, (KB)
|
||||
relatedInformationPresent - flag indicates that the "related:" keyword is supported for this URL
|
||||
hostName: When filtering occurs, a maximum of two results from any given host is returned.
|
||||
When this occurs, the second resultElement that comes from that host contains
|
||||
the host name in this parameter.
|
||||
directoryCategory: dictionary like this:
|
||||
{'fullViewableName': Open Directory category,
|
||||
'specialEncoding': encoding scheme of this directory category}
|
||||
directoryTitle: Open Directory title of this result (or blank)
|
||||
summary - Open Directory summary for this result (or blank)
|
||||
"""
|
||||
pass
|
||||
|
||||
class SearchReturnValue:
|
||||
"""complete search results for a single query
|
||||
|
||||
Available attributes:
|
||||
meta - SearchResultsMetaData
|
||||
results - list of SearchResult
|
||||
"""
|
||||
def __init__(self, metadata, results):
|
||||
self.meta = metadata
|
||||
self.results = results
|
||||
|
||||
## main functions
|
||||
def doGoogleSearch(q, start=0, maxResults=10, filter=1, restrict='',
|
||||
safeSearch=0, language='', inputencoding='', outputencoding='',
|
||||
license_key = None, http_proxy = None):
|
||||
"""search Google
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
q - search string. Anything you could type at google.com, you can pass here.
|
||||
See http://www.google.com/help/features.html for examples of advanced features.
|
||||
start (optional) - zero-based index of first desired result (for paging through
|
||||
multiple pages of results)
|
||||
maxResults (optional) - maximum number of results, currently capped at 10
|
||||
filter (optional) - set to 1 to filter out similar results, set to 0 to see everything
|
||||
restrict (optional) - restrict results by country or topic. Examples:
|
||||
Ukraine - search only sites located in Ukraine
|
||||
linux - search Linux sites only
|
||||
mac - search Mac sites only
|
||||
bsd - search FreeBSD sites only
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for more advanced examples and a full list of country codes and topics.
|
||||
safeSearch (optional) - set to 1 to filter results with SafeSearch (no adult material)
|
||||
language (optional) - restricts search to documents in one or more languages. Example:
|
||||
lang_en - only return pages in English
|
||||
lang_fr - only return pages in French
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for more advanced examples and a full list of language codes.
|
||||
inputencoding (optional) - sets the character encoding of q parameter
|
||||
outputencoding (optional) - sets the character encoding of the returned results
|
||||
See the APIs_reference.html file in the SDK (http://www.google.com/apis/download.html)
|
||||
for a full list of encodings.
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: SearchReturnValue
|
||||
.meta - SearchMetaData
|
||||
.results - list of SearchResult
|
||||
See documentation of these individual classes for list of available attributes
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
filter = _marshalBoolean(filter)
|
||||
safeSearch = _marshalBoolean(safeSearch)
|
||||
data = remoteserver.doGoogleSearch(license_key, q, start, maxResults, filter, restrict,
|
||||
safeSearch, language, inputencoding, outputencoding)
|
||||
metadata = data._asdict
|
||||
del metadata["resultElements"]
|
||||
metadata = SearchResultsMetaData(metadata)
|
||||
results = [SearchResult(node._asdict) for node in data.resultElements]
|
||||
return SearchReturnValue(metadata, results)
|
||||
|
||||
def doGetCachedPage(url, license_key = None, http_proxy = None):
|
||||
"""get page from Google cache
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
url - address of page to get
|
||||
license_key (optional) - Google license key
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: string, text of cached page
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
return remoteserver.doGetCachedPage(license_key, url)
|
||||
|
||||
def doSpellingSuggestion(phrase, license_key = None, http_proxy = None):
|
||||
"""get spelling suggestions from Google
|
||||
|
||||
You need a license key to call this function; see
|
||||
http://www.google.com/apis/ to get one. Then you can either pass it to
|
||||
this function every time, or set it globally; see the module docs for details.
|
||||
|
||||
Parameters:
|
||||
phrase - word or phrase to spell-check
|
||||
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
|
||||
|
||||
Returns: text of suggested replacement, or None
|
||||
"""
|
||||
http_proxy = getProxy(http_proxy)
|
||||
remoteserver = SOAP.SOAPProxy(_url, namespace=_namespace, http_proxy=http_proxy)
|
||||
license_key = getLicense(license_key)
|
||||
return remoteserver.doSpellingSuggestion(license_key, phrase)
|
||||
|
||||
## functional test suite (see googletest.py for unit test suite)
|
||||
def test():
|
||||
try:
|
||||
getLicense(None)
|
||||
except NoLicenseKey:
|
||||
return
|
||||
print "Searching for Python at google.com..."
|
||||
data = doGoogleSearch("Python")
|
||||
output(data, {"func": "doGoogleSearch"})
|
||||
|
||||
print "\nSearching for 5 _French_ pages about Python, encoded in ISO-8859-1..."
|
||||
data = doGoogleSearch("Python", language='lang_fr', outputencoding='ISO-8859-1', maxResults=5)
|
||||
output(data, {"func": "doGoogleSearch"})
|
||||
|
||||
phrase = "Pyhton programming languager"
|
||||
print "\nTesting spelling suggetions for '%s'..." % phrase
|
||||
data = doSpellingSuggestion(phrase)
|
||||
output(data, {"func": "doSpellingSuggestion"})
|
||||
|
||||
## main driver for command-line use
|
||||
def main(argv):
|
||||
"""
|
||||
Command-line interface.
|
||||
"""
|
||||
if not argv:
|
||||
usage()
|
||||
_usage()
|
||||
return
|
||||
q = None
|
||||
func = None
|
||||
@ -387,9 +591,10 @@ def main(argv):
|
||||
outputFormat = "text"
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, "s:c:p:k:lmrx:hvt1",
|
||||
["search=", "cache=", "spelling=", "key=", "lucky", "meta", "reverse", "proxy=", "help", "version", "test"])
|
||||
["search=", "cache=", "spelling=", "key=", "lucky", "meta",
|
||||
"reverse", "proxy=", "help", "version", "test"])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
_usage()
|
||||
sys.exit(2)
|
||||
for opt, arg in opts:
|
||||
if opt in ("-s", "--search"):
|
||||
@ -412,22 +617,22 @@ def main(argv):
|
||||
elif opt in ("-x", "--proxy"):
|
||||
http_proxy = arg
|
||||
elif opt in ("-h", "--help"):
|
||||
usage()
|
||||
_usage()
|
||||
elif opt in ("-v", "--version"):
|
||||
version()
|
||||
_version()
|
||||
elif opt in ("-t", "--test"):
|
||||
runTest = 1
|
||||
if runTest:
|
||||
setLicense(license_key)
|
||||
setProxy(http_proxy)
|
||||
test()
|
||||
_test()
|
||||
if args and not q:
|
||||
q = args[0]
|
||||
func = "doGoogleSearch"
|
||||
if func:
|
||||
results = globals()[func](q, http_proxy=http_proxy, license_key=license_key)
|
||||
output(results, locals())
|
||||
results = globals()[func]( q, http_proxy=http_proxy,
|
||||
license_key=license_key )
|
||||
_output(results, locals())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||
|
Loading…
Reference in New Issue
Block a user