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
|
709
others/google.py
709
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,
|
This module allows you to access Google's web APIs through SOAP,
|
||||||
to do things like search Google and get the results programmatically.
|
to do things like search Google and get the results programmatically.
|
||||||
Described here:
|
Described U{here <http://www.google.com/apis/>}
|
||||||
http://www.google.com/apis/
|
|
||||||
|
|
||||||
You need a Google-provided license key to use these services.
|
You need a Google-provided license key to use these services.
|
||||||
Follow the link above to get one. These functions will look in
|
Follow the link above to get one. These functions will look in
|
||||||
several places (in this order) for the license key:
|
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:
|
- the "license_key" argument of each function
|
||||||
>>> import google
|
- the module-level LICENSE_KEY variable (call setLicense once to set it)
|
||||||
>>> google.setLicense('...') # must get your own key!
|
- an environment variable called GOOGLE_LICENSE_KEY
|
||||||
>>> data = google.doGoogleSearch('python')
|
- a file called ".googlekey" in the current directory
|
||||||
>>> data.meta.searchTime
|
- a file called "googlekey.txt" in the current directory
|
||||||
0.043221000000000002
|
- a file called ".googlekey" in your home directory
|
||||||
>>> data.results[0].URL
|
- a file called "googlekey.txt" in your home directory
|
||||||
'http://www.python.org/'
|
- a file called ".googlekey" in the same directory as google.py
|
||||||
>>> data.results[0].title
|
- a file called "googlekey.txt" in the same directory as google.py
|
||||||
'<b>Python</b> Language Website'
|
|
||||||
|
|
||||||
See documentation of SearchResultsMetaData and SearchResult classes
|
Sample usage::
|
||||||
for other available attributes.
|
|
||||||
|
>>> 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)"
|
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
|
||||||
__version__ = "0.5.2"
|
__version__ = "0.6"
|
||||||
__cvsversion__ = "$Revision$"[11:-2]
|
__cvsversion__ = "$Revision$"[11:-2]
|
||||||
__date__ = "$Date$"[7:-2]
|
__date__ = "$Date$"[7:-2]
|
||||||
__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
|
__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
|
Erik Max Francis, for the command line interface
|
||||||
Michael Twomey, for HTTP proxy support"""
|
Michael Twomey, for HTTP proxy support"""
|
||||||
|
|
||||||
import SOAP
|
|
||||||
import os, sys, getopt
|
import os, sys, getopt
|
||||||
|
import GoogleSOAPFacade
|
||||||
|
|
||||||
LICENSE_KEY = None
|
LICENSE_KEY = None
|
||||||
HTTP_PROXY = 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'
|
_url = 'http://api.google.com/search/beta2'
|
||||||
_false = SOAP.booleanType(0)
|
_namespace = 'urn:GoogleSearch'
|
||||||
_true = SOAP.booleanType(1)
|
|
||||||
_googlefile1 = ".googlekey"
|
_googlefile1 = ".googlekey"
|
||||||
_googlefile2 = "googlekey.txt"
|
_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
|
_false = GoogleSOAPFacade.false
|
||||||
def version():
|
_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
|
print """PyGoogle %(__version__)s
|
||||||
%(__copyright__)s
|
%(__copyright__)s
|
||||||
released %(__date__)s
|
released %(__date__)s
|
||||||
@ -78,7 +117,11 @@ released %(__date__)s
|
|||||||
Thanks to:
|
Thanks to:
|
||||||
%(__credits__)s""" % globals()
|
%(__credits__)s""" % globals()
|
||||||
|
|
||||||
def usage():
|
|
||||||
|
def _usage():
|
||||||
|
"""
|
||||||
|
Display usage information for the command-line interface
|
||||||
|
"""
|
||||||
program = os.path.basename(sys.argv[0])
|
program = os.path.basename(sys.argv[0])
|
||||||
print """Usage: %(program)s [options] [querytype] query
|
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:]:
|
for get, location in _licenseLocations[2:]:
|
||||||
print " *", location
|
print " *", location
|
||||||
|
|
||||||
## utility functions
|
## ----------------------------------------------------------------------
|
||||||
|
## utility functions (API)
|
||||||
|
## ----------------------------------------------------------------------
|
||||||
|
|
||||||
def setLicense(license_key):
|
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
|
global LICENSE_KEY
|
||||||
LICENSE_KEY = license_key
|
LICENSE_KEY = license_key
|
||||||
|
|
||||||
def getLicense(license_key = None):
|
|
||||||
"""get license key
|
|
||||||
|
|
||||||
license key can come from any number of locations;
|
def getLicense(license_key = None):
|
||||||
see module docs for search order"""
|
"""
|
||||||
|
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:
|
for get, location in _licenseLocations:
|
||||||
rc = get(license_key)
|
rc = get(license_key)
|
||||||
if rc: return rc
|
if rc: return rc
|
||||||
#usage()
|
_usage()
|
||||||
raise NoLicenseKey, 'get a license key at http://www.google.com/apis/'
|
raise NoLicenseKey, 'get a license key at http://www.google.com/apis/'
|
||||||
|
|
||||||
|
|
||||||
def setProxy(http_proxy):
|
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
|
global HTTP_PROXY
|
||||||
HTTP_PROXY = http_proxy
|
HTTP_PROXY = http_proxy
|
||||||
|
|
||||||
|
|
||||||
def getProxy(http_proxy = None):
|
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
|
return http_proxy or HTTP_PROXY
|
||||||
|
|
||||||
|
|
||||||
def _contentsOf(dirname, filename):
|
def _contentsOf(dirname, filename):
|
||||||
filename = os.path.join(dirname, filename)
|
filename = os.path.join(dirname, filename)
|
||||||
if not os.path.exists(filename): return None
|
if not os.path.exists(filename): return None
|
||||||
@ -138,42 +211,335 @@ def _contentsOf(dirname, filename):
|
|||||||
fsock.close()
|
fsock.close()
|
||||||
return contents
|
return contents
|
||||||
|
|
||||||
|
|
||||||
def _getScriptDir():
|
def _getScriptDir():
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
return os.path.abspath(os.path.dirname(sys.argv[0]))
|
return os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||||
else:
|
else:
|
||||||
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
|
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
|
||||||
|
|
||||||
|
|
||||||
def _marshalBoolean(value):
|
def _marshalBoolean(value):
|
||||||
if value:
|
if value:
|
||||||
return _true
|
return _true
|
||||||
else:
|
else:
|
||||||
return _false
|
return _false
|
||||||
|
|
||||||
## output formatters
|
|
||||||
def makeFormatter(outputFormat):
|
|
||||||
classname = "%sOutputFormatter" % outputFormat.capitalize()
|
|
||||||
return globals()[classname]()
|
|
||||||
|
|
||||||
def output(results, params):
|
def _getRemoteServer( http_proxy ):
|
||||||
formatter = makeFormatter(params.get("outputFormat", "text"))
|
return GoogleSOAPFacade.getProxy( _url, _namespace, http_proxy )
|
||||||
outputmethod = getattr(formatter, params["func"])
|
|
||||||
outputmethod(results, params)
|
|
||||||
|
|
||||||
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):
|
def boil(self, data):
|
||||||
if type(data) == type(u""):
|
if type(data) == type(u""):
|
||||||
return data.encode("utf-8", "replace")
|
return data.encode("ISO-8859-1", "replace")
|
||||||
else:
|
else:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
class TextOutputFormatter(OutputFormatter):
|
class _TextOutputFormatter(_OutputFormatter):
|
||||||
def common(self, data, params):
|
def common(self, data, params):
|
||||||
if params.get("showMeta", 0):
|
if params.get("showMeta", 0):
|
||||||
meta = data.meta
|
meta = data.meta
|
||||||
for category in meta.directoryCategories:
|
for category in meta.directoryCategories:
|
||||||
print "directoryCategory: %s" % self.boil(category["fullViewableName"])
|
print "directoryCategory: %s" % \
|
||||||
for attr in [node for node in dir(meta) if node <> "directoryCategories" and node[:2] <> '__']:
|
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))
|
print "%s:" % attr, self.boil(getattr(meta, attr))
|
||||||
|
|
||||||
def doGoogleSearch(self, data, params):
|
def doGoogleSearch(self, data, params):
|
||||||
@ -185,7 +551,8 @@ class TextOutputFormatter(OutputFormatter):
|
|||||||
for result in results:
|
for result in results:
|
||||||
for attr in dir(result):
|
for attr in dir(result):
|
||||||
if attr == "directoryCategory":
|
if attr == "directoryCategory":
|
||||||
print "directoryCategory:", self.boil(result.directoryCategory["fullViewableName"])
|
print "directoryCategory:", \
|
||||||
|
self.boil(result.directoryCategory["fullViewableName"])
|
||||||
elif attr[:2] <> '__':
|
elif attr[:2] <> '__':
|
||||||
print "%s:" % attr, self.boil(getattr(result, attr))
|
print "%s:" % attr, self.boil(getattr(result, attr))
|
||||||
print
|
print
|
||||||
@ -197,184 +564,21 @@ class TextOutputFormatter(OutputFormatter):
|
|||||||
|
|
||||||
doSpellingSuggestion = doGetCachedPage
|
doSpellingSuggestion = doGetCachedPage
|
||||||
|
|
||||||
## search results classes
|
def _makeFormatter(outputFormat):
|
||||||
class _SearchBase:
|
classname = "_%sOutputFormatter" % outputFormat.capitalize()
|
||||||
def __init__(self, params):
|
return globals()[classname]()
|
||||||
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
|
|
||||||
|
|
||||||
class SearchResultsMetaData(_SearchBase):
|
def _output(results, params):
|
||||||
"""metadata of search query results
|
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):
|
def main(argv):
|
||||||
|
"""
|
||||||
|
Command-line interface.
|
||||||
|
"""
|
||||||
if not argv:
|
if not argv:
|
||||||
usage()
|
_usage()
|
||||||
return
|
return
|
||||||
q = None
|
q = None
|
||||||
func = None
|
func = None
|
||||||
@ -387,9 +591,10 @@ def main(argv):
|
|||||||
outputFormat = "text"
|
outputFormat = "text"
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(argv, "s:c:p:k:lmrx:hvt1",
|
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:
|
except getopt.GetoptError:
|
||||||
usage()
|
_usage()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
for opt, arg in opts:
|
for opt, arg in opts:
|
||||||
if opt in ("-s", "--search"):
|
if opt in ("-s", "--search"):
|
||||||
@ -412,22 +617,22 @@ def main(argv):
|
|||||||
elif opt in ("-x", "--proxy"):
|
elif opt in ("-x", "--proxy"):
|
||||||
http_proxy = arg
|
http_proxy = arg
|
||||||
elif opt in ("-h", "--help"):
|
elif opt in ("-h", "--help"):
|
||||||
usage()
|
_usage()
|
||||||
elif opt in ("-v", "--version"):
|
elif opt in ("-v", "--version"):
|
||||||
version()
|
_version()
|
||||||
elif opt in ("-t", "--test"):
|
elif opt in ("-t", "--test"):
|
||||||
runTest = 1
|
runTest = 1
|
||||||
if runTest:
|
if runTest:
|
||||||
setLicense(license_key)
|
setLicense(license_key)
|
||||||
setProxy(http_proxy)
|
setProxy(http_proxy)
|
||||||
test()
|
_test()
|
||||||
if args and not q:
|
if args and not q:
|
||||||
q = args[0]
|
q = args[0]
|
||||||
func = "doGoogleSearch"
|
func = "doGoogleSearch"
|
||||||
if func:
|
if func:
|
||||||
results = globals()[func](q, http_proxy=http_proxy, license_key=license_key)
|
results = globals()[func]( q, http_proxy=http_proxy,
|
||||||
output(results, locals())
|
license_key=license_key )
|
||||||
|
_output(results, locals())
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
|
||||||
|
Loading…
Reference in New Issue
Block a user