ZSI-2.1-a1/ 0000755 0001751 0001751 00000000000 10712455110 010512 5 ustar zsi zsi ZSI-2.1-a1/samples/ 0000755 0001751 0001751 00000000000 10712455110 012156 5 ustar zsi zsi ZSI-2.1-a1/samples/README 0000644 0001751 0001751 00000000143 07400741162 013041 0 ustar zsi zsi Sample code, no copyright; use as you see fit.
ZSI tips and techniques.
Self-commented, if at all.
ZSI-2.1-a1/samples/WSGI/ 0000755 0001751 0001751 00000000000 10712455110 012727 5 ustar zsi zsi ZSI-2.1-a1/samples/WSGI/echo_client.py 0000644 0001751 0001751 00000000753 10712205420 015557 0 ustar zsi zsi #
#
#
from EchoServer_client import *
import sys, time
TRACE=None
loc = EchoServerLocator()
port = loc.getEchoServer(url='http://localhost:8000/echo', tracefile=TRACE)
msg = EchoRequest()
msg.Value = 1
rsp = port.Echo(msg)
print "INTEGER: ", rsp.Value
msg.Value = "HI"
rsp = port.Echo(msg)
print "STRING: ", rsp.Value
msg.Value = 1.10000
rsp = port.Echo(msg)
print "FLOAT: ", rsp.Value
msg.Value = dict(milk=dict(cost=3.15, unit="gal"))
rsp = port.Echo(msg)
print "DICT: ", rsp.Value
ZSI-2.1-a1/samples/WSGI/README 0000644 0001751 0001751 00000001340 10712205420 013602 0 ustar zsi zsi ==================
WSGI Code is unstable, and currently server-side stubs are NOT generated for you.
==================
python wsgi example
run the SimpleEcho service out of python's wsgi
==================
% ./echo_setup.sh
% python echo_server.py >& server.log &
[1] 3455
% python echo_client.py
INTEGER: 1
STRING: HI
FLOAT: 1.1
DICT: {'milk': {'cost': 3.1499999999999999, 'unit': 'gal'}}
==================
twisted.web2.wsgi example
run the SimpleEcho service out of twisted's web2 wsgi
==================
% ./echo_setup.sh
% python echo_server.py twisted >& server.log &
[1] 3459
% python echo_client.py
INTEGER: 1
STRING: HI
FLOAT: 1.1
DICT: {'milk': {'cost': 3.1499999999999999, 'unit': 'gal'}}
ZSI-2.1-a1/samples/WSGI/echo_server.py 0000644 0001751 0001751 00000002720 10712205420 015603 0 ustar zsi zsi ############################################################################
# Joshua R. Boverhof, LBNL
# See Copyright for copyright notice!
# $Id: __init__.py 1132 2006-02-17 01:55:41Z boverhof $
###########################################################################
import sys
from EchoServer_client import *
from ZSI.twisted.wsgi import SOAPApplication, soapmethod, SOAPHandlerChainFactory
class EchoService(SOAPApplication):
factory = SOAPHandlerChainFactory
wsdl_content = dict(name='Echo', targetNamespace='urn:echo', imports=(), portType='')
@soapmethod(EchoRequest.typecode, EchoResponse.typecode, operation='Echo', soapaction='Echo')
def soap_Echo(self, request, response, **kw):
response = request
return request,response
def main():
from wsgiref.simple_server import make_server, demo_app
from ZSI.twisted.wsgi import WSGIApplication
application = WSGIApplication()
httpd = make_server('', 8000, application)
application['echo'] = EchoService()
httpd.serve_forever()
def main_twisted():
from ZSI.twisted.wsgi import test, WSGIApplication
app = WSGIApplication()
app['echo'] = EchoService()
test(app, port=8000)
if __name__ == '__main__':
if len(sys.argv) == 1:
main()
else:
var = sys.argv[1]
try:
getattr(sys.modules[__name__], 'main_%s' %var)(*sys.argv[2:])
except Exception, ex:
print>>sys.stderr, ex
sys.exit(1)
ZSI-2.1-a1/samples/WSGI/SimpleEcho.wsdl 0000644 0001751 0001751 00000003114 10712205420 015646 0 ustar zsi zsi
ZSI-2.1-a1/samples/WSGI/echo_setup.py 0000755 0001751 0001751 00000000045 10712205420 015436 0 ustar zsi zsi #!/bin/sh
wsdl2py -b SimpleEcho.wsdl
ZSI-2.1-a1/setup.cfg 0000644 0001751 0001751 00000000343 10712455110 012333 0 ustar zsi zsi [bdist_rpm]
release = 1
requires =
doc_files = README CHANGES doc/zsi.css doc/zsi.html
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
[version]
major = 2
candidate = 0
beta = 0
minor = 1
alpha = 1
patchlevel = 0
ZSI-2.1-a1/Copyright 0000644 0001751 0001751 00000000564 07730126512 012421 0 ustar zsi zsi Ugh. I hate paperwork. :)
Most of ZSI is covered by an MIT/X Consortium copyright, as found
in doc/zsi.tex.
The wsdl2python tools are covered by an LBNL BSD-style license, as found
in ZSI/LBNLCopyright.
Most of the code in wstools is covered by the Zope Public License,
which is a certified open source license that is GPL compatible.
See ZSI/wstools/ZPL for details.
ZSI-2.1-a1/CHANGES 0000644 0001751 0001751 00000023634 10712434035 011520 0 ustar zsi zsi Change for xxx released xxx:
- Make XMLSchema.py work in cases where threading isn't built in
- Add client-side Cookie Support (Jorgen Frojk Kjaersgaard)
- For cookies, getheaders() is Python 2.3; use getallmatchingheaders
- In SoapWriter, put nsdecls on body, not envelope
- Record facets (restrictions) in XMLSchema.py
- Remove Send()'s kwargs out of _args list
Change for 2.1.0_a1 released 31-Oct-2007:
- No PyXML Dependency, use minidom by default (much faster)
- samples/WSGI, server and client examples using python wsgi and twisted.web2.wsgi
Change for 2.0.0 released xxx:
- no more wsdl2dispatch, wsdl2py does it all
- simplified and consolidated various wsdl2py script options
- wsdl2py added some soapheader support to client code.
- wsdl2py changed Locator accessors names to match the "port.name"
rather than the "portType.name"
- wsdl2py changed generated Binding class names to match the "binding.name"
rather than the "portType.name"
Change for 2.0.0rc3 released xxx:
- Updated ZSI developers guide
- Added ZSI wsdl2py users guide
- Added support for setuptools in setup script. If setuptools is installed
use it, else revert to distutils.
- Removed "requestclass" keyword argument to Binding.Send
- simplified and retooled Binding/NamedParamBinding and dispatch, added
"typesmodule" back into Binding. Now it's mirror image of dispatch.
- Microseconds to TCtime
- BUG [ 1525567 ] Amazon ECommerce Issues: local element declarations
overriding global element declarations with the same name within the
same namespace.
- new module "schema", contains "all" the code for dealing with global
Schema instance.
Change for 2.0.0rc2 released 28-March-2006:
- Replace many/most id() with _get_idstr() to hide negative numbers
- Added ZSI.twisted package w/client and server, requires Python 2.4
- If Python >= 2.4, build/install ZSI.twisted package
- Add Typecode.typed to control xsi:type data system-wide
- Replace many/most id() with _get_idstr() to hide negative numbers
Changes for 1.7 released 16-Feb-2005:
- Add support for jonpy (http://jonpy.sourceforge.net) FastCGI
courtesy of Guan Yang
- Avoid FutureWarning with Python 2.3.x
- Make sure generated ID values are legal IDs under Python 2.3
and newer
- Don't need _textunprotect (via Grahame Bowland)
- Fix ZSI.wstools.XMLname.toXMLname() so namespace prefix isn't lost
Changes for 1.5, released 10-Mar-2004:
- TypeCode honoring for response parameters
- String adherence to wsdl for request/response params via ServiceProxy
- wsdl2py bug fixes
- Numerous bug fixes
Changes for 1.4.1 released 11-Nov-2003:
- Make "docstyle" work for returning data, too (Alexis Marrero-Narvaez)
- TC.Struct.typed will output xsi:type parameter now.
- Numerous bug fixes
Changes for 1.4, released 09-Sep-2003:
- Ouput XML prolog in SoapWriter
- Added nsdict parameter to dispatch.AsCGI and dispatch.AsServer
- Fixed bug where xmlns attribute was included in closing elements
- Added support for "wrapped" complexTypes in response messages
- TypeCode enabled classes now support parameters in the constructor
- Automatic parsing of ComplexTypes in response messages
- WSDL Parsing and operation invocation via ServiceProxy
- Tuple returned from dates and times (instead of a list)
- Arrays of ComplexTypes can now be deserialized
- User can specify which module contains complex type definitions
- Mod_Python support for dispatch to multiple functions within a module
- In client.py, try to get port from URL if available (Wichert Akkerman)
- Add ZSIException as parent for ZSI exception classes, FaultException
class, and raise that if we get unexpected fault in client (Wichert)
- Add auth_header keyword param to client Send method (Phillip Pearson)
- Added support for conversion between WSDL and Python classes
Changes for 1.3, released xx-May-2002:
- Fixed parsing bug evidenced by dW article
- Style: use defaulted parameters not kw.get()
- Style: avoid __dict__ and use standard attribute fetch
- Fix dispatch to actually dispatch (Laroche Denis)
- Fix some typo's (thanks adalke)
- In TCCompound, include class name in exception, not just object name
- ZSI homepage is at pywebsvcs.sf.net now, not www.zolera.com (sigh...)
- Add nsdict parameter to dispatch's AsServer()
Changes for 1.2, released 05-Mar-2002:
- Replace with X copyright; GNU compatible now
- newver writes date into version.tex
- Use "raise x(a)" always, never "raise x, a" (that's oldschool:)
- Don't delete tb in FaultFromException; add try/except for robustness
- Ignore -1 values for DST, etc., in Python time tuples
- Remove needless __init__ when just calling parent __init__
- Added 'undeclared' parameter to TC.Array
- Added 'repeatable' parameter to TC.TypeCode
- Add 'aname' parameter to TC.Typecode
- Move 'unique' keyword from TC.String up to TC.TypeCode
- Add 'wrapped' keyword to TC.XML
- Added _find_attr lambda
- Had path backwards in backtrace, add [1] to uniqify when needed
- Complain if extra elements in TC.Struct and hasextras=0
- Duration.lex_pattern was wrong (old schema)
- Newline after output gDateTime, not a space
- Newline before Base64string
- Incorrect test in RegisterType
- Add Boolean.serialize
- Anchor all TCtime lex_pattern's
- Allow class object (not just class name) in TC.seriallist
- TC.Void can serialize None (useful for TC.Any)
- RegisterType(TC.Void)
- Fix consistency and interop in dispatching
- Array interop fix
- SOAPAction header needs quotes
- Add Apache SOAPArray
- Properly use 'ns' in client to set default namespace
- Convert client.py to use "new" HTTP objects
- Sign isn't optional on numeric timezones in dates
- Document limits on date/time conversions.
- Add TC.XML.copyit and 'copyit' keyword to constructor
- Spelt EvaluateException wrong in dispatch.py
- xsi:nil not xsi:null in TC.Void
- Address issues with client/dispatch and None
- Use formatted output, not strftime
- TC.Any defaults to optional if not set, for None
- TC.Any tries to serialize its datatype as its tagname
- Add 'typed' support to TC.Any
- Allow keyword args in Fault.AsSOAP, passed to SoapWriter ctor
- SoapWriter's self.memo always uses id() (even for strings)
- Add SoapWriter.Forget()
- Add 'envelope' and 'encoding' keywords to SoapWriter
- Added 'mutable' parameter to TC.Struct
- TC.oname now properly defaults to TC.pname
- Remove "None" if it was second arg to dictionary get() method
- Add 'format' parameter to TC.Decimal and TC.Integer
- Fix TC.Decimal to work where float('INF') doesn't
- Fix TC.Decimal to handle NaN more portably
- Add samples directory
- Binding() omits typing from the outermost RPC wrapper
- Fix HTML docs to include the ZSI schema
- Add readerclass parameter to client Binding
- Ignore <> around Content-ID in resolver; fix test to have it
- Docfix for Placer.typecode (paul@prescod.net)
- TC.Any will call pyobj's typecode if attr exists (paul@prescod.net)
- Binding replytype is optional; standards replytype not replyclass
- Document other tests to-do in interop/README
- Document ZSI typecode naming better.
- Add 'docstyle' to AsServer
- Handle HTTP 100 responses (httplib should...) (aspinei@internal.metawings.com)
Changes for 1.1, released 14-Sep-2001:
- Works with PyXML0.6 now!
- Create this CHANGES file, include it in doc files
- Lots of editing and new material in the documentation
- Fix TC.String to handle empty strings
- Renamed NodeBacktrace to _backtrace
- Renamed HasValidEncoding to _valid_encoding
- Add 'textprotect' keyword argument to TC.String
- TC.Any() can now serialize dictionaries, lists, tuples
- TC.Any() can now parse arrays
- Add aslist to TC.Any()
- Add TC.Apache.Map typecode
- GetMyHeaderElements includes header with no actor attribute
- Fix formatting of error message when TC.Struct caught eval exception
- Fix TC.Struct for case when all kids are optional (could-be-zero-sized)
- Fix SimpleHREF calling sequence; boolean, Gregorian, duration now work
- Fix typo when generating backtrace on EvaluateException
- Exception backtraces are now in XPath syntax
- Fix zsi.xsd to conform to proper XSD-Rec style
- Fix zsi.xsd nits found by free IBM schema quality checker
- Added Z:BasicAuth to zsi.xsd
- CIDResolver now takes an optional "next" parameter, instead of creating
a NetworkResolver automatically; the "prefixes" parameter is gone
from the CIDResolver constructor
- Rename CIDResolver to MIMEResolver, and add Content-Location handling
- Changed resolver.seekable default from 1 to 0
- Resolvers raise EvaluateException, not TypeError
- Fix FindLocalHREF to search the serialization root, too
- Use and prefer Fault.AsSOAP, although Fault.AsSoap still exists
- Change FindLocalHREF to cache all id's as it finds them
- Add boolean, decimal, and hexbinary to interop server
- Add simple CGI dispatching
- Put version in setup.cfg and make newver use it for version.{py,tex}
- Add ZSI.Version() to retrieve version tuple
- Use len(_children(elt)) not elt.hasChildNodes()
ZSI-2.1-a1/setup.py 0000755 0001751 0001751 00000003604 10712434035 012235 0 ustar zsi zsi #! /usr/bin/env python
# $Header$
import sys
try:
from setuptools import setup
hasSetuptools = True
except ImportError:
from distutils.core import setup
hasSetuptools = False
_url = "http://pywebsvcs.sf.net/"
import ConfigParser
cf = ConfigParser.ConfigParser()
cf.read('setup.cfg')
major = cf.getint('version', 'major')
minor = cf.getint('version', 'minor')
patchlevel = cf.getint('version', 'patchlevel')
candidate = cf.getint('version', 'candidate')
alpha = cf.getint('version', 'alpha')
beta = cf.getint('version', 'beta')
_version = "%d.%d" % ( major, minor )
if patchlevel:
_version += '.%d' % patchlevel
if candidate:
_version += '_rc%d' % candidate
elif alpha:
_version += '_a%d' % alpha
elif beta:
_version += '_b%d' % beta
try:
open('ZSI/version.py', 'r').close()
except:
print 'ZSI/version.py not found; run "make"'
sys.exit(1)
_packages = [ "ZSI", "ZSI.generate", "ZSI.wstools"]
if sys.version_info[0:2] >= (2, 4):
_packages.append("ZSI.twisted")
# setuptools specific logic
additional_params = {}
if hasSetuptools:
additional_params['entry_points'] = {
'console_scripts': [
'wsdl2py = ZSI.generate.commands:wsdl2py',
],
}
additional_params['setup_requires'] = [ "setuptools >= 0.6c3", ]
additional_params['dependency_links'] = [
"http://sourceforge.net/project/showfiles.php?group_id=6473&package_id=6541&release_id=286213",
]
else:
additional_params['scripts'] = ["scripts/wsdl2py",]
setup(
name="ZSI",
version=_version,
license="Python",
packages=_packages,
description="Zolera SOAP Infrastructure",
author="Rich Salz, et al",
author_email="rsalz@datapower.com",
maintainer="Rich Salz, et al",
maintainer_email="pywebsvcs-talk@lists.sf.net",
url=_url,
long_description="For additional information, please see " + _url,
**additional_params
)
ZSI-2.1-a1/PKG-INFO 0000644 0001751 0001751 00000000452 10712455110 011610 0 ustar zsi zsi Metadata-Version: 1.0
Name: ZSI
Version: 2.1-a1
Summary: Zolera SOAP Infrastructure
Home-page: http://pywebsvcs.sf.net/
Author: Rich Salz, et al
Author-email: pywebsvcs-talk@lists.sf.net
License: Python
Description: For additional information, please see http://pywebsvcs.sf.net/
Platform: UNKNOWN
ZSI-2.1-a1/README 0000644 0001751 0001751 00000002744 10700756665 011421 0 ustar zsi zsi ==============================
The Zolera SOAP Infrastructure
==============================
ZSI, the Zolera SOAP Infrastructure, is a pure-Python module that
provides an implementation of SOAP messaging, as described in SOAP 1.1
Specification (see http://www.w3.org/TR/soap). It can also be used to
build applications using SOAP Messages with Attachments (see
http://www.w3.org/TR/SOAP-attachments). ZSI is intended to make it
easier to write web services in Python.
In particular, ZSI parses and generates SOAP messages, and converts
between native Python datatypes and SOAP syntax. Simple dispatch and
invocation methods are supported. There are no known bugs. It's only
known limitation is that it cannot handle multi-dimensional arrays.
ZSI is built on top of DOM. It requires Python 2.3 or later.
It is open source. We hope you find it useful.
The ZSI.twisted package will only be built if you're using Python >= 2.4,
and in order to use it you'll need twisted >= 2.0 and twistedWeb >= 0.5.0
The documentation (in PDF and HTML) is accurate. We should probably
restructure the document as a HOWTO. You probably can't usefully edit
the docs without having the Python2.0 sources and some other utilities
(TeX, pdfLaTeX, latex2html) on a Unix or Cygwin installation. If you
want to format or revise the docs, see "Documentation Tools" in the
file RELEASE.
/rich $alz
rsalz@datapower.com
Things To Do
------------
Any volunteers?
- Use isinstance() for types.
- Update to SOAPv1.2.
ZSI-2.1-a1/ZSI/ 0000755 0001751 0001751 00000000000 10712455110 011157 5 ustar zsi zsi ZSI-2.1-a1/ZSI/digest_auth.py 0000644 0001751 0001751 00000006347 10556234235 014054 0 ustar zsi zsi #! /usr/bin/env python
# $Header$
'''Utilities for HTTP Digest Authentication
'''
import re
from md5 import md5
import random
import time
import httplib
random.seed(int(time.time()*10))
def H(val):
return md5(val).hexdigest()
def KD(secret,data):
return H('%s:%s' % (secret,data))
def A1(username,realm,passwd,nonce=None,cnonce=None):
if nonce and cnonce:
return '%s:%s:%s:%s:%s' % (username,realm,passwd,nonce,cnonce)
else:
return '%s:%s:%s' % (username,realm,passwd)
def A2(method,uri):
return '%s:%s' % (method,uri)
def dict_fetch(d,k,defval=None):
if d.has_key(k):
return d[k]
return defval
def generate_response(chaldict,uri,username,passwd,method='GET',cnonce=None):
"""
Generate an authorization response dictionary. chaldict should contain the digest
challenge in dict form. Use fetch_challenge to create a chaldict from a HTTPResponse
object like this: fetch_challenge(res.getheaders()).
returns dict (the authdict)
Note. Use build_authorization_arg() to turn an authdict into the final Authorization
header value.
"""
authdict = {}
qop = dict_fetch(chaldict,'qop')
domain = dict_fetch(chaldict,'domain')
nonce = dict_fetch(chaldict,'nonce')
stale = dict_fetch(chaldict,'stale')
algorithm = dict_fetch(chaldict,'algorithm','MD5')
realm = dict_fetch(chaldict,'realm','MD5')
opaque = dict_fetch(chaldict,'opaque')
nc = "00000001"
if not cnonce:
cnonce = H(str(random.randint(0,10000000)))[:16]
if algorithm.lower()=='md5-sess':
a1 = A1(username,realm,passwd,nonce,cnonce)
else:
a1 = A1(username,realm,passwd)
a2 = A2(method,uri)
secret = H(a1)
data = '%s:%s:%s:%s:%s' % (nonce,nc,cnonce,qop,H(a2))
authdict['username'] = '"%s"' % username
authdict['realm'] = '"%s"' % realm
authdict['nonce'] = '"%s"' % nonce
authdict['uri'] = '"%s"' % uri
authdict['response'] = '"%s"' % KD(secret,data)
authdict['qop'] = '"%s"' % qop
authdict['nc'] = nc
authdict['cnonce'] = '"%s"' % cnonce
return authdict
def fetch_challenge(http_header):
""" apparently keywords Basic and Digest are not being checked
anywhere and decisions are being made based on authorization
configuration of client, so I guess you better know what you are
doing. Here I am requiring one or the other be specified.
challenge Basic auth_param
challenge Digest auth_param
"""
m = fetch_challenge.wwwauth_header_re.match(http_header)
if m is None:
raise RuntimeError, 'expecting "WWW-Authenticate header [Basic,Digest]"'
d = dict(challenge=m.groups()[0])
m = fetch_challenge.auth_param_re.search(http_header)
while m is not None:
k,v = http_header[m.start():m.end()].split('=')
d[k.lower()] = v[1:-1]
m = fetch_challenge.auth_param_re.search(http_header, m.end())
return d
fetch_challenge.wwwauth_header_re = re.compile(r'\s*([bB]asic|[dD]igest)\s+(?:[\w]+="[^"]+",?\s*)?')
fetch_challenge.auth_param_re = re.compile(r'[\w]+="[^"]+"')
def build_authorization_arg(authdict):
"""
Create an "Authorization" header value from an authdict (created by generate_response()).
"""
vallist = []
for k in authdict.keys():
vallist += ['%s=%s' % (k,authdict[k])]
return 'Digest '+', '.join(vallist)
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/TCnumbers.py 0000644 0001751 0001751 00000012521 10514021301 013423 0 ustar zsi zsi #! /usr/bin/env python
# $Header$
'''Typecodes for numbers.
'''
import types
from ZSI import _copyright, _inttypes, _floattypes, _seqtypes, \
EvaluateException
from ZSI.TC import TypeCode, Integer, Decimal
from ZSI.wstools.Namespaces import SCHEMA
class IunsignedByte(Integer):
'''Unsigned 8bit value.
'''
type = (SCHEMA.XSD3, "unsignedByte")
parselist = [ (None, "unsignedByte") ]
seriallist = [ ]
class IunsignedShort(Integer):
'''Unsigned 16bit value.
'''
type = (SCHEMA.XSD3, "unsignedShort")
parselist = [ (None, "unsignedShort") ]
seriallist = [ ]
class IunsignedInt(Integer):
'''Unsigned 32bit value.
'''
type = (SCHEMA.XSD3, "unsignedInt")
parselist = [ (None, "unsignedInt") ]
seriallist = [ ]
class IunsignedLong(Integer):
'''Unsigned 64bit value.
'''
type = (SCHEMA.XSD3, "unsignedLong")
parselist = [ (None, "unsignedLong") ]
seriallist = [ ]
class Ibyte(Integer):
'''Signed 8bit value.
'''
type = (SCHEMA.XSD3, "byte")
parselist = [ (None, "byte") ]
seriallist = [ ]
class Ishort(Integer):
'''Signed 16bit value.
'''
type = (SCHEMA.XSD3, "short")
parselist = [ (None, "short") ]
seriallist = [ ]
class Iint(Integer):
'''Signed 32bit value.
'''
type = (SCHEMA.XSD3, "int")
parselist = [ (None, "int") ]
seriallist = [ types.IntType ]
class Ilong(Integer):
'''Signed 64bit value.
'''
type = (SCHEMA.XSD3, "long")
parselist = [(None, "long")]
seriallist = [ types.LongType ]
class InegativeInteger(Integer):
'''Value less than zero.
'''
type = (SCHEMA.XSD3, "negativeInteger")
parselist = [ (None, "negativeInteger") ]
seriallist = [ ]
class InonPositiveInteger(Integer):
'''Value less than or equal to zero.
'''
type = (SCHEMA.XSD3, "nonPositiveInteger")
parselist = [ (None, "nonPositiveInteger") ]
seriallist = [ ]
class InonNegativeInteger(Integer):
'''Value greater than or equal to zero.
'''
type = (SCHEMA.XSD3, "nonNegativeInteger")
parselist = [ (None, "nonNegativeInteger") ]
seriallist = [ ]
class IpositiveInteger(Integer):
'''Value greater than zero.
'''
type = (SCHEMA.XSD3, "positiveInteger")
parselist = [ (None, "positiveInteger") ]
seriallist = [ ]
class Iinteger(Integer):
'''Integer value.
'''
type = (SCHEMA.XSD3, "integer")
parselist = [ (None, "integer") ]
seriallist = [ ]
class IEnumeration(Integer):
'''Integer value, limited to a specified set of values.
'''
def __init__(self, choices, pname=None, **kw):
Integer.__init__(self, pname, **kw)
self.choices = choices
t = type(choices)
if t in _seqtypes:
self.choices = tuple(choices)
elif TypeCode.typechecks:
raise TypeError(
'Enumeration choices must be list or sequence, not ' + str(t))
if TypeCode.typechecks:
for c in self.choices:
if type(c) not in _inttypes:
raise TypeError('Enumeration choice "' +
str(c) + '" is not an integer')
def parse(self, elt, ps):
val = Integer.parse(self, elt, ps)
if val not in self.choices:
raise EvaluateException('Value "' + str(val) + \
'" not in enumeration list',
ps.Backtrace(elt))
return val
def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
if pyobj not in self.choices:
raise EvaluateException('Value not in int enumeration list',
ps.Backtrace(elt))
Integer.serialize(self, elt, sw, pyobj, name=name, orig=orig, **kw)
class FPfloat(Decimal):
'''IEEE 32bit floating point value.
'''
type = (SCHEMA.XSD3, "float")
parselist = [ (None, "float") ]
seriallist = [ types.FloatType ]
class FPdouble(Decimal):
'''IEEE 64bit floating point value.
'''
type = (SCHEMA.XSD3, "double")
parselist = [ (None, "double") ]
seriallist = [ ]
class FPEnumeration(FPfloat):
'''Floating point value, limited to a specified set of values.
'''
def __init__(self, choices, pname=None, **kw):
FPfloat.__init__(self, pname, **kw)
self.choices = choices
t = type(choices)
if t in _seqtypes:
self.choices = tuple(choices)
elif TypeCode.typechecks:
raise TypeError(
'Enumeration choices must be list or sequence, not ' + str(t))
if TypeCode.typechecks:
for c in self.choices:
if type(c) not in _floattypes:
raise TypeError('Enumeration choice "' +
str(c) + '" is not floating point number')
def parse(self, elt, ps):
val = Decimal.parse(self, elt, ps)
if val not in self.choices:
raise EvaluateException('Value "' + str(val) + \
'" not in enumeration list',
ps.Backtrace(elt))
return val
def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
if pyobj not in self.choices:
raise EvaluateException('Value not in int enumeration list',
ps.Backtrace(elt))
Decimal.serialize(self, elt, sw, pyobj, name=name, orig=orig, **kw)
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/parse.py 0000644 0001751 0001751 00000035167 10700756665 012677 0 ustar zsi zsi #! /usr/bin/env python
# $Header$
'''SOAP messaging parsing.
'''
from xml.dom import expatbuilder
from ZSI import _copyright, _children, _attrs, _child_elements, _stringtypes, \
_backtrace, EvaluateException, ParseException, _valid_encoding, \
_Node, _find_attr, _resolve_prefix
from ZSI.TC import AnyElement
import types
from ZSI.wstools.Namespaces import SOAP, XMLNS
from ZSI.wstools.Utility import SplitQName
_find_actor = lambda E: E.getAttributeNS(SOAP.ENV, "actor") or None
_find_mu = lambda E: E.getAttributeNS(SOAP.ENV, "mustUnderstand")
_find_root = lambda E: E.getAttributeNS(SOAP.ENC, "root")
_find_id = lambda E: _find_attr(E, 'id')
class DefaultReader:
"""ExpatReaderClass"""
fromString = staticmethod(expatbuilder.parseString)
fromStream = staticmethod(expatbuilder.parse)
class ParsedSoap:
'''A Parsed SOAP object.
Convert the text to a DOM tree and parse SOAP elements.
Instance data:
reader -- the DOM reader
dom -- the DOM object
ns_cache -- dictionary (by id(node)) of namespace dictionaries
id_cache -- dictionary (by XML ID attr) of elements
envelope -- the node holding the SOAP Envelope
header -- the node holding the SOAP Header (or None)
body -- the node holding the SOAP Body
body_root -- the serialization root in the SOAP Body
data_elements -- list of non-root elements in the SOAP Body
trailer_elements -- list of elements following the SOAP body
'''
defaultReaderClass = DefaultReader
def __init__(self, input, readerclass=None, keepdom=False,
trailers=False, resolver=None, envelope=True, **kw):
'''Initialize.
Keyword arguments:
trailers -- allow trailer elments (default is zero)
resolver -- function (bound method) to resolve URI's
readerclass -- factory class to create a reader
keepdom -- do not release the DOM
envelope -- look for a SOAP envelope.
'''
self.readerclass = readerclass
self.keepdom = keepdom
if not self.readerclass:
self.readerclass = self.defaultReaderClass
try:
self.reader = self.readerclass()
if type(input) in _stringtypes:
self.dom = self.reader.fromString(input)
else:
self.dom = self.reader.fromStream(input)
except Exception, e:
# Is this in the header? Your guess is as good as mine.
#raise ParseException("Can't parse document (" + \
# str(e.__class__) + "): " + str(e), 0)
raise
self.ns_cache = {
id(self.dom): {
'xml': XMLNS.XML,
'xmlns': XMLNS.BASE,
'': ''
}
}
self.trailers, self.resolver, self.id_cache = trailers, resolver, {}
# Exactly one child element
c = [ E for E in _children(self.dom)
if E.nodeType == _Node.ELEMENT_NODE]
if len(c) == 0:
raise ParseException("Document has no Envelope", 0)
if len(c) != 1:
raise ParseException("Document has extra child elements", 0)
if envelope is False:
self.body_root = c[0]
return
# And that one child must be the Envelope
elt = c[0]
if elt.localName != "Envelope" \
or elt.namespaceURI != SOAP.ENV:
raise ParseException('Document has "' + elt.localName + \
'" element, not Envelope', 0)
self._check_for_legal_children("Envelope", elt)
for a in _attrs(elt):
name = a.nodeName
if name.find(":") == -1 and name not in [ "xmlns", "id" ]:
raise ParseException('Unqualified attribute "' + \
name + '" in Envelope', 0)
self.envelope = elt
if not _valid_encoding(self.envelope):
raise ParseException("Envelope has invalid encoding", 0)
# Get Envelope's child elements.
c = [ E for E in _children(self.envelope)
if E.nodeType == _Node.ELEMENT_NODE ]
if len(c) == 0:
raise ParseException("Envelope is empty (no Body)", 0)
# Envelope's first child might be the header; if so, nip it off.
elt = c[0]
if elt.localName == "Header" \
and elt.namespaceURI == SOAP.ENV:
self._check_for_legal_children("Header", elt)
self._check_for_pi_nodes(_children(elt), 1)
self.header = c.pop(0)
self.header_elements = _child_elements(self.header)
else:
self.header, self.header_elements = None, []
# Now the first child must be the body
if len(c) == 0:
raise ParseException("Envelope has header but no Body", 0)
elt = c.pop(0)
if elt.localName != "Body" \
or elt.namespaceURI != SOAP.ENV:
if self.header:
raise ParseException('Header followed by "' + \
elt.localName + \
'" element, not Body', 0, elt, self.dom)
else:
raise ParseException('Document has "' + \
elt.localName + \
'" element, not Body', 0, elt, self.dom)
self._check_for_legal_children("Body", elt, 0)
self._check_for_pi_nodes(_children(elt), 0)
self.body = elt
if not _valid_encoding(self.body):
raise ParseException("Body has invalid encoding", 0)
# Trailer elements.
if not self.trailers:
if len(c):
raise ParseException("Element found after Body",
0, elt, self.dom)
# Don't set self.trailer_elements = []; if user didn't ask
# for trailers we *want* to throw an exception.
else:
self.trailer_elements = c
for elt in self.trailer_elements:
if not elt.namespaceURI:
raise ParseException('Unqualified trailer element',
0, elt, self.dom)
# Find the serialization root. Divide the Body children into
# root (root=1), no (root=0), maybe (no root attribute).
self.body_root, no, maybe = None, [], []
for elt in _child_elements(self.body):
root = _find_root(elt)
if root == "1":
if self.body_root:
raise ParseException("Multiple seralization roots found",
0, elt, self.dom)
self.body_root = elt
elif root == "0":
no.append(elt)
elif not root:
maybe.append(elt)
else:
raise ParseException('Illegal value for root attribute',
0, elt, self.dom)
# If we didn't find a root, get the first one that didn't
# say "not me", unless they all said "not me."
if self.body_root is None:
if len(maybe):
self.body_root = maybe[0]
else:
raise ParseException('No serialization root found',
0, self.body, self.dom)
if not _valid_encoding(self.body_root):
raise ParseException("Invalid encoding", 0,
elt, self.dom)
# Now get all the non-roots (in order!).
rootid = id(self.body_root)
self.data_elements = [ E for E in _child_elements(self.body)
if id(E) != rootid ]
self._check_for_pi_nodes(self.data_elements, 0)
def __del__(self):
try:
if not self.keepdom:
self.reader.releaseNode(self.dom)
except:
pass
def _check_for_legal_children(self, name, elt, mustqualify=1):
'''Check if all children of this node are elements or whitespace-only
text nodes.
'''
inheader = name == "Header"
for n in _children(elt):
t = n.nodeType
if t == _Node.COMMENT_NODE: continue
if t != _Node.ELEMENT_NODE:
if t == _Node.TEXT_NODE and n.nodeValue.strip() == "":
continue
raise ParseException("Non-element child in " + name,
inheader, elt, self.dom)
if mustqualify and not n.namespaceURI:
raise ParseException('Unqualified element "' + \
n.nodeName + '" in ' + name, inheader, elt, self.dom)
def _check_for_pi_nodes(self, list, inheader):
'''Raise an exception if any of the list descendants are PI nodes.
'''
list = list[:]
while list:
elt = list.pop()
t = elt.nodeType
if t == _Node.PROCESSING_INSTRUCTION_NODE:
raise ParseException('Found processing instruction "' + \
elt.nodeName + '...>"',
inheader, elt.parentNode, self.dom)
elif t == _Node.DOCUMENT_TYPE_NODE:
raise ParseException('Found DTD', inheader,
elt.parentNode, self.dom)
list += _children(elt)
def Backtrace(self, elt):
'''Return a human-readable "backtrace" from the document root to
the specified element.
'''
return _backtrace(elt, self.dom)
def FindLocalHREF(self, href, elt, headers=1):
'''Find a local HREF in the data elements.
'''
if href[0] != '#':
raise EvaluateException(
'Absolute HREF ("%s") not implemented' % href,
self.Backtrace(elt))
frag = href[1:]
# Already found?
e = self.id_cache.get(frag)
if e: return e
# Do a breadth-first search, in the data first. Most likely
# to find multi-ref targets shallow in the data area.
list = self.data_elements[:] + [self.body_root]
if headers: list.extend(self.header_elements)
while list:
e = list.pop()
if e.nodeType == _Node.ELEMENT_NODE:
nodeid = _find_id(e)
if nodeid:
self.id_cache[nodeid] = e
if nodeid == frag: return e
list += _children(e)
raise EvaluateException('''Can't find node for HREF "%s"''' % href,
self.Backtrace(elt))
def ResolveHREF(self, uri, tc, **keywords):
r = getattr(tc, 'resolver', self.resolver)
if not r:
raise EvaluateException('No resolver for "' + uri + '"')
try:
if type(uri) == types.UnicodeType: uri = str(uri)
retval = r(uri, tc, self, **keywords)
except Exception, e:
raise EvaluateException('''Can't resolve "''' + uri + '" (' + \
str(e.__class__) + "): " + str(e))
return retval
def GetMyHeaderElements(self, actorlist=None):
'''Return a list of all elements intended for these actor(s).
'''
if actorlist is None:
actorlist = [None, SOAP.ACTOR_NEXT]
else:
actorlist = list(actorlist) + [None, SOAP.ACTOR_NEXT]
return [ E for E in self.header_elements
if _find_actor(E) in actorlist ]
def GetElementNSdict(self, elt):
'''Get a dictionary of all the namespace attributes for the indicated
element. The dictionaries are cached, and we recurse up the tree
as necessary.
'''
d = self.ns_cache.get(id(elt))
if not d:
if elt != self.dom: d = self.GetElementNSdict(elt.parentNode)
for a in _attrs(elt):
if a.namespaceURI == XMLNS.BASE:
if a.localName == "xmlns":
d[''] = a.nodeValue
else:
d[a.localName] = a.nodeValue
self.ns_cache[id(elt)] = d
return d.copy()
def GetDomAndReader(self):
'''Returns a tuple containing the dom and reader objects. (dom, reader)
Unless keepdom is true, the dom and reader objects will go out of scope
when the ParsedSoap instance is deleted. If keepdom is true, the reader
object is needed to properly clean up the dom tree with
reader.releaseNode(dom).
'''
return (self.dom, self.reader)
def IsAFault(self):
'''Is this a fault message?
'''
e = self.body_root
if not e: return 0
return e.namespaceURI == SOAP.ENV and e.localName == 'Fault'
def Parse(self, how):
'''Parse the message.
'''
if type(how) == types.ClassType: how = how.typecode
return how.parse(self.body_root, self)
def WhatMustIUnderstand(self):
'''Return a list of (uri,localname) tuples for all elements in the
header that have mustUnderstand set.
'''
return [ ( E.namespaceURI, E.localName )
for E in self.header_elements if _find_mu(E) == "1" ]
def WhatActorsArePresent(self):
'''Return a list of URI's of all the actor attributes found in
the header. The special actor "next" is ignored.
'''
results = []
for E in self.header_elements:
a = _find_actor(E)
if a not in [ None, SOAP.ACTOR_NEXT ]: results.append(a)
return results
def ParseHeaderElements(self, ofwhat):
'''Returns a dictionary of pyobjs.
ofhow -- list of typecodes w/matching nspname/pname to the header_elements.
'''
d = {}
lenofwhat = len(ofwhat)
c, crange = self.header_elements[:], range(len(self.header_elements))
for i,what in [ (i, ofwhat[i]) for i in range(lenofwhat) ]:
if isinstance(what, AnyElement):
raise EvaluateException, 'not supporting as child of SOAP-ENC:Header'
v = []
occurs = 0
namespaceURI,tagName = what.nspname,what.pname
for j,c_elt in [ (j, c[j]) for j in crange if c[j] ]:
prefix,name = SplitQName(c_elt.tagName)
nsuri = _resolve_prefix(c_elt, prefix)
if tagName == name and namespaceURI == nsuri:
pyobj = what.parse(c_elt, self)
else:
continue
v.append(pyobj)
c[j] = None
if what.minOccurs > len(v) > what.maxOccurs:
raise EvaluateException, 'number of occurances(%d) doesnt fit constraints (%d,%s)'\
%(len(v),what.minOccurs,what.maxOccurs)
if what.maxOccurs == 1:
if len(v) == 0: v = None
else: v = v[0]
d[(what.nspname,what.pname)] = v
return d
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/TC.py 0000644 0001751 0001751 00000200636 10647242563 012063 0 ustar zsi zsi #! /usr/bin/env python
# $Header$
'''General typecodes.
'''
from ZSI import _copyright, _children, _child_elements, \
_floattypes, _stringtypes, _seqtypes, _find_attr, _find_attrNS, _find_attrNodeNS, \
_find_arraytype, _find_default_namespace, _find_href, _find_encstyle, \
_resolve_prefix, _find_xsi_attr, _find_type, \
_find_xmlns_prefix, _get_element_nsuri_name, _get_idstr, \
_Node, EvaluateException, UNICODE_ENCODING, \
_valid_encoding, ParseException
from ZSI.wstools.Namespaces import SCHEMA, SOAP
from ZSI.wstools.Utility import SplitQName
from ZSI.wstools.c14n import Canonicalize
from ZSI.wstools.logging import getLogger as _GetLogger
import re, types, time, copy
from base64 import decodestring as b64decode, encodestring as b64encode
from urllib import unquote as urldecode, quote as urlencode
from binascii import unhexlify as hexdecode, hexlify as hexencode
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
_is_xsd_or_soap_ns = lambda ns: ns in [
SCHEMA.XSD3, SOAP.ENC, SCHEMA.XSD1, SCHEMA.XSD2, ]
_find_nil = lambda E: _find_xsi_attr(E, "null") or _find_xsi_attr(E, "nil")
def _get_xsitype(pyclass):
'''returns the xsi:type as a tuple, coupled with ZSI.schema
'''
if hasattr(pyclass,'type') and type(pyclass.type) in _seqtypes:
return pyclass.type
elif hasattr(pyclass,'type') and hasattr(pyclass, 'schema'):
return (pyclass.schema, pyclass.type)
return (None,None)
# value returned when xsi:nil="true"
Nilled = None
UNBOUNDED = 'unbounded'
class TypeCode:
'''The parent class for all parseable SOAP types.
Class data:
typechecks -- do init-time type checking if non-zero
Class data subclasses may define:
tag -- global element declaration
type -- global type definition
parselist -- list of valid SOAP types for this class, as
(uri,name) tuples, where a uri of None means "all the XML
Schema namespaces"
errorlist -- parselist in a human-readable form; will be
generated if/when needed
seriallist -- list of Python types or user-defined classes
that this typecode can serialize.
logger -- logger instance for this class.
'''
tag = None
type = (None,None)
typechecks = True
attribute_typecode_dict = None
logger = _GetLogger('ZSI.TC.TypeCode')
def __init__(self, pname=None, aname=None, minOccurs=1,
maxOccurs=1, nillable=False, typed=True, unique=True,
pyclass=None, attrs_aname='_attrs', **kw):
'''Baseclass initialization.
Instance data (and usually keyword arg)
pname -- the parameter name (localname).
nspname -- the namespace for the parameter;
None to ignore the namespace
typed -- output xsi:type attribute
unique -- data item is not aliased (no href/id needed)
minOccurs -- min occurances
maxOccurs -- max occurances
nillable -- is item nillable?
attrs_aname -- This is variable name to dictionary of attributes
encoded -- encoded namespaceURI (specify if use is encoded)
'''
if type(pname) in _seqtypes:
self.nspname, self.pname = pname
else:
self.nspname, self.pname = None, pname
if self.pname:
self.pname = str(self.pname).split(':')[-1]
self.aname = aname or self.pname
self.minOccurs = minOccurs
self.maxOccurs = maxOccurs
self.nillable = nillable
self.typed = typed
self.unique = unique
self.attrs_aname = attrs_aname
self.pyclass = pyclass
# Need this stuff for rpc/encoded.
encoded = kw.get('encoded')
if encoded is not None:
self.nspname = kw['encoded']
def parse(self, elt, ps):
'''
Parameters:
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
raise EvaluateException("Unimplemented evaluation", ps.Backtrace(elt))
def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
'''
Parameters:
elt -- the current DOMWrapper element
sw -- soapWriter object
pyobj -- python object to serialize
'''
raise EvaluateException("Unimplemented evaluation", sw.Backtrace(elt))
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
Parameters:
text -- text content
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
raise EvaluateException("Unimplemented evaluation", ps.Backtrace(elt))
def serialize_as_nil(self, elt):
'''
Parameters:
elt -- the current DOMWrapper element
'''
elt.setAttributeNS(SCHEMA.XSI3, 'nil', '1')
def SimpleHREF(self, elt, ps, tag):
'''Simple HREF for non-string and non-struct and non-array.
Parameters:
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
tag --
'''
if len(_children(elt)): return elt
href = _find_href(elt)
if not href:
if self.minOccurs is 0: return None
raise EvaluateException('Required' + tag + ' missing',
ps.Backtrace(elt))
return ps.FindLocalHREF(href, elt, 0)
def get_parse_and_errorlist(self):
"""Get the parselist and human-readable version, errorlist is returned,
because it is used in error messages.
"""
d = self.__class__.__dict__
parselist = d.get('parselist')
errorlist = d.get('errorlist')
if parselist and not errorlist:
errorlist = []
for t in parselist:
if t[1] not in errorlist: errorlist.append(t[1])
errorlist = ' or '.join(errorlist)
d['errorlist'] = errorlist
return (parselist, errorlist)
def checkname(self, elt, ps):
'''See if the name and type of the "elt" element is what we're
looking for. Return the element's type.
Parameters:
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
parselist,errorlist = self.get_parse_and_errorlist()
ns, name = _get_element_nsuri_name(elt)
if ns == SOAP.ENC:
# Element is in SOAP namespace, so the name is a type.
if parselist and \
(None, name) not in parselist and (ns, name) not in parselist:
raise EvaluateException(
'Element mismatch (got %s wanted %s) (SOAP encoding namespace)' % \
(name, errorlist), ps.Backtrace(elt))
return (ns, name)
# Not a type, check name matches.
if self.nspname and ns != self.nspname:
raise EvaluateException('Element NS mismatch (got %s wanted %s)' % \
(ns, self.nspname), ps.Backtrace(elt))
if self.pname and name != self.pname:
raise EvaluateException('Element Name mismatch (got %s wanted %s)' % \
(name, self.pname), ps.Backtrace(elt))
return self.checktype(elt, ps)
def checktype(self, elt, ps):
'''See if the type of the "elt" element is what we're looking for.
Return the element's type.
Parameters:
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
typeName = _find_type(elt)
if typeName is None or typeName == "":
return (None,None)
# Parse the QNAME.
prefix,typeName = SplitQName(typeName)
uri = ps.GetElementNSdict(elt).get(prefix)
if uri is None:
raise EvaluateException('Malformed type attribute (bad NS)',
ps.Backtrace(elt))
#typeName = list[1]
parselist,errorlist = self.get_parse_and_errorlist()
if not parselist or \
(uri,typeName) in parselist or \
(_is_xsd_or_soap_ns(uri) and (None,typeName) in parselist):
return (uri,typeName)
raise EvaluateException(
'Type mismatch (%s namespace) (got %s wanted %s)' % \
(uri, typeName, errorlist), ps.Backtrace(elt))
def name_match(self, elt):
'''Simple boolean test to see if we match the element name.
Parameters:
elt -- the DOM element being parsed
'''
return self.pname == elt.localName and \
self.nspname in [None, '', elt.namespaceURI]
def nilled(self, elt, ps):
'''Is the element NIL, and is that okay?
Parameters:
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
if _find_nil(elt) not in [ "true", "1"]: return False
if self.nillable is False:
raise EvaluateException('Non-nillable element is NIL',
ps.Backtrace(elt))
return True
def simple_value(self, elt, ps, mixed=False):
'''Get the value of the simple content of this element.
Parameters:
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
mixed -- ignore element content, optional text node
'''
if not _valid_encoding(elt):
raise EvaluateException('Invalid encoding', ps.Backtrace(elt))
c = _children(elt)
if mixed is False:
if len(c) == 0:
raise EvaluateException('Value missing', ps.Backtrace(elt))
for c_elt in c:
if c_elt.nodeType == _Node.ELEMENT_NODE:
raise EvaluateException('Sub-elements in value',
ps.Backtrace(c_elt))
# It *seems* to be consensus that ignoring comments and
# concatenating the text nodes is the right thing to do.
return ''.join([E.nodeValue for E in c
if E.nodeType
in [ _Node.TEXT_NODE, _Node.CDATA_SECTION_NODE ]])
def parse_attributes(self, elt, ps):
'''find all attributes specified in the attribute_typecode_dict in
current element tag, if an attribute is found set it in the
self.attributes dictionary. Default to putting in String.
Parameters:
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
if self.attribute_typecode_dict is None:
return
attributes = {}
for attr,what in self.attribute_typecode_dict.items():
namespaceURI,localName = None,attr
if type(attr) in _seqtypes:
namespaceURI,localName = attr
value = _find_attrNodeNS(elt, namespaceURI, localName)
self.logger.debug("Parsed Attribute (%s,%s) -- %s",
namespaceURI, localName, value)
# For Now just set it w/o any type interpretation.
if value is None: continue
attributes[attr] = what.text_to_data(value, elt, ps)
return attributes
def set_attributes(self, el, pyobj):
'''Instance data attributes contains a dictionary
of keys (namespaceURI,localName) and attribute values.
These values can be self-describing (typecode), or use
attribute_typecode_dict to determine serialization.
Paramters:
el -- MessageInterface representing the element
pyobj --
'''
if not hasattr(pyobj, self.attrs_aname):
return
if not isinstance(getattr(pyobj, self.attrs_aname), dict):
raise TypeError,\
'pyobj.%s must be a dictionary of names and values'\
% self.attrs_aname
for attr, value in getattr(pyobj, self.attrs_aname).items():
namespaceURI,localName = None, attr
if type(attr) in _seqtypes:
namespaceURI, localName = attr
what = None
if getattr(self, 'attribute_typecode_dict', None) is not None:
what = self.attribute_typecode_dict.get(attr)
if what is None and namespaceURI is None:
what = self.attribute_typecode_dict.get(localName)
# allow derived type
if hasattr(value, 'typecode') and not isinstance(what, AnyType):
if what is not None and not isinstance(value.typecode, what):
raise EvaluateException, \
'self-describing attribute must subclass %s'\
%what.__class__
what = value.typecode
self.logger.debug("attribute create -- %s", value)
if isinstance(what, QName):
what.set_prefix(el, value)
#format the data
if what is None:
value = str(value)
else:
value = what.get_formatted_content(value)
el.setAttributeNS(namespaceURI, localName, value)
def set_attribute_xsi_type(self, el, **kw):
'''if typed, set the xsi:type attribute
Paramters:
el -- MessageInterface representing the element
'''
if kw.get('typed', self.typed):
namespaceURI,typeName = kw.get('type', _get_xsitype(self))
if namespaceURI and typeName:
self.logger.debug("attribute: (%s, %s)", namespaceURI, typeName)
el.setAttributeType(namespaceURI, typeName)
def set_attribute_href(self, el, objid):
'''set href attribute
Paramters:
el -- MessageInterface representing the element
objid -- ID type, unique id
'''
el.setAttributeNS(None, 'href', "#%s" %objid)
def set_attribute_id(self, el, objid):
'''set id attribute
Paramters:
el -- MessageInterface representing the element
objid -- ID type, unique id
'''
if self.unique is False:
el.setAttributeNS(None, 'id', "%s" %objid)
def get_name(self, name, objid):
'''
Paramters:
name -- element tag
objid -- ID type, unique id
'''
if type(name) is tuple:
return name
ns = self.nspname
n = name or self.pname or ('E' + objid)
return ns,n
def has_attributes(self):
'''Return True if Attributes are declared outside
the scope of SOAP ('root', 'id', 'href'), and some
attributes automatically handled (xmlns, xsi:type).
'''
if self.attribute_typecode_dict is None: return False
return len(self.attribute_typecode_dict) > 0
class SimpleType(TypeCode):
'''SimpleType -- consist exclusively of a tag, attributes, and a value
class attributes:
empty_content -- value representing an empty element.
'''
empty_content = None
logger = _GetLogger('ZSI.TC.SimpleType')
def parse(self, elt, ps):
self.checkname(elt, ps)
if len(_children(elt)) == 0:
href = _find_href(elt)
if not href:
if self.nilled(elt, ps) is False:
# No content, no HREF, not NIL: empty string
return self.text_to_data(self.empty_content, elt, ps)
# No content, no HREF, and is NIL...
if self.nillable is True:
return Nilled
raise EvaluateException('Requiredstring missing',
ps.Backtrace(elt))
if href[0] != '#':
return ps.ResolveHREF(href, self)
elt = ps.FindLocalHREF(href, elt)
self.checktype(elt, ps)
if self.nilled(elt, ps): return Nilled
if len(_children(elt)) == 0:
v = self.empty_content
else:
v = self.simple_value(elt, ps)
else:
v = self.simple_value(elt, ps)
pyobj = self.text_to_data(v, elt, ps)
# parse all attributes contained in attribute_typecode_dict
# (user-defined attributes), the values (if not None) will
# be keyed in self.attributes dictionary.
if self.attribute_typecode_dict is not None:
attributes = self.parse_attributes(elt, ps)
if attributes:
setattr(pyobj, self.attrs_aname, attributes)
return pyobj
def get_formatted_content(self, pyobj):
raise NotImplementedError, 'method get_formatted_content is not implemented'
def serialize_text_node(self, elt, sw, pyobj):
'''Serialize without an element node.
'''
textNode = None
if pyobj is not None:
text = self.get_formatted_content(pyobj)
if type(text) not in _stringtypes:
raise TypeError, 'pyobj must be a formatted string'
textNode = elt.createAppendTextNode(text)
return textNode
def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
'''Handles the start and end tags, and attributes. callout
to get_formatted_content to get the textNode value.
Parameters:
elt -- ElementProxy/DOM element
sw -- SoapWriter instance
pyobj -- processed content
KeyWord Parameters:
name -- substitute name, (nspname,name) or name
orig --
'''
objid = _get_idstr(pyobj)
ns,n = self.get_name(name, objid)
# nillable
el = elt.createAppendElement(ns, n)
if self.nillable is True and pyobj is Nilled:
self.serialize_as_nil(el)
return None
# other attributes
self.set_attributes(el, pyobj)
# soap href attribute
unique = self.unique or kw.get('unique', False)
if unique is False and sw.Known(orig or pyobj):
self.set_attribute_href(el, objid)
return None
# xsi:type attribute
if kw.get('typed', self.typed) is True:
self.set_attribute_xsi_type(el, **kw)
# soap id attribute
if self.unique is False:
self.set_attribute_id(el, objid)
#Content, c
self.serialize_text_node(el, sw, pyobj)
return el
class Any(TypeCode):
'''When the type isn't defined in the schema, but must be specified
in the incoming operation.
parsemap -- a type to class mapping (updated by descendants), for
parsing
serialmap -- same, for (outgoing) serialization
'''
logger = _GetLogger('ZSI.TC.Any')
parsemap, serialmap = {}, {}
def __init__(self, pname=None, aslist=False, minOccurs=0, unique=False, **kw):
TypeCode.__init__(self, pname, minOccurs=minOccurs, unique=unique, **kw)
self.aslist = aslist
self.kwargs = dict(aslist=aslist, unique=unique)
self.kwargs.update(kw)
# input arg v should be a list of tuples (name, value).
def listify(self, v):
if self.aslist: return [ k for j,k in v ]
return dict(v)
def parse_into_dict_or_list(self, elt, ps):
c = _child_elements(elt)
count = len(c)
v = []
if count == 0:
href = _find_href(elt)
if not href: return v
elt = ps.FindLocalHREF(href, elt)
self.checktype(elt, ps)
c = _child_elements(elt)
count = len(c)
if count == 0: return self.listify(v)
if self.nilled(elt, ps): return Nilled
for c_elt in c:
v.append((str(c_elt.localName), self.__class__(**self.kwargs).parse(c_elt, ps)))
return self.listify(v)
def parse(self, elt, ps):
(ns,type) = self.checkname(elt, ps)
if not type and self.nilled(elt, ps): return Nilled
if len(_children(elt)) == 0:
href = _find_href(elt)
if not href:
if self.minOccurs < 1:
if _is_xsd_or_soap_ns(ns):
parser = Any.parsemap.get((None,type))
if parser: return parser.parse(elt, ps)
if ((ns,type) == (SOAP.ENC,'Array') or
(_find_arraytype(elt) or '').endswith('[0]')):
return []
return None
raise EvaluateException('Required Any missing',
ps.Backtrace(elt))
elt = ps.FindLocalHREF(href, elt)
(ns,type) = self.checktype(elt, ps)
if not type and elt.namespaceURI == SOAP.ENC:
ns,type = SOAP.ENC, elt.localName
if not type or (ns,type) == (SOAP.ENC,'Array'):
if self.aslist or _find_arraytype(elt):
return [ self.__class__(**self.kwargs).parse(e, ps)
for e in _child_elements(elt) ]
if len(_child_elements(elt)) == 0:
#raise EvaluateException("Any cannot parse untyped element",
# ps.Backtrace(elt))
return self.simple_value(elt, ps)
return self.parse_into_dict_or_list(elt, ps)
parser = Any.parsemap.get((ns,type))
if not parser and _is_xsd_or_soap_ns(ns):
parser = Any.parsemap.get((None,type))
if not parser:
raise EvaluateException('''Any can't parse element''',
ps.Backtrace(elt))
return parser.parse(elt, ps)
def get_formatted_content(self, pyobj):
tc = type(pyobj)
if tc == types.InstanceType:
tc = pyobj.__class__
if hasattr(pyobj, 'typecode'):
#serializer = pyobj.typecode.serialmap.get(tc)
serializer = pyobj.typecode
else:
serializer = Any.serialmap.get(tc)
if not serializer:
tc = (types.ClassType, pyobj.__class__.__name__)
serializer = Any.serialmap.get(tc)
else:
serializer = Any.serialmap.get(tc)
if not serializer and isinstance(pyobj, time.struct_time):
from ZSI.TCtimes import gDateTime
serializer = gDateTime()
if serializer:
return serializer.get_formatted_content(pyobj)
raise EvaluateException, 'Failed to find serializer for pyobj %s' %pyobj
def serialize(self, elt, sw, pyobj, name=None, **kw):
if hasattr(pyobj, 'typecode') and pyobj.typecode is not self:
pyobj.typecode.serialize(elt, sw, pyobj, **kw)
return
objid = _get_idstr(pyobj)
ns,n = self.get_name(name, objid)
kw.setdefault('typed', self.typed)
tc = type(pyobj)
self.logger.debug('Any serialize -- %s', tc)
if tc in _seqtypes:
if self.aslist:
array = elt.createAppendElement(ns, n)
array.setAttributeType(SOAP.ENC, "Array")
array.setAttributeNS(self.nspname, 'SOAP-ENC:arrayType',
"xsd:anyType[" + str(len(pyobj)) + "]" )
for o in pyobj:
#TODO maybe this should take **self.kwargs...
serializer = getattr(o, 'typecode', Any(**self.kwargs))
serializer.serialize(array, sw, o, name='element', **kw)
else:
struct = elt.createAppendElement(ns, n)
for o in pyobj:
#TODO maybe this should take **self.kwargs...
serializer = getattr(o, 'typecode', Any(**self.kwargs))
serializer.serialize(struct, sw, o, **kw)
return
kw['name'] = (ns,n)
if tc == types.DictType:
el = elt.createAppendElement(ns, n)
parentNspname = self.nspname # temporarily clear nspname for dict elements
self.nspname = None
for o,m in pyobj.items():
if type(o) != types.StringType and type(o) != types.UnicodeType:
raise Exception, 'Dictionary implementation requires keys to be of type string (or unicode).' %pyobj
kw['name'] = o
kw.setdefault('typed', True)
self.serialize(el, sw, m, **kw)
# restore nspname
self.nspname = parentNspname
return
if tc == types.InstanceType:
tc = pyobj.__class__
if hasattr(pyobj, 'typecode'):
#serializer = pyobj.typecode.serialmap.get(tc)
serializer = pyobj.typecode
else:
serializer = Any.serialmap.get(tc)
if not serializer:
tc = (types.ClassType, pyobj.__class__.__name__)
serializer = Any.serialmap.get(tc)
else:
serializer = Any.serialmap.get(tc)
if not serializer and isinstance(pyobj, time.struct_time):
from ZSI.TCtimes import gDateTime
serializer = gDateTime()
if not serializer:
# Last-chance; serialize instances as dictionary
if pyobj is None:
self.serialize_as_nil(elt.createAppendElement(ns, n))
elif type(pyobj) != types.InstanceType:
raise EvaluateException('''Any can't serialize ''' + \
repr(pyobj))
else:
self.serialize(elt, sw, pyobj.__dict__, **kw)
else:
# Try to make the element name self-describing
tag = getattr(serializer, 'tag', None)
if self.pname is not None:
#serializer.nspname = self.nspname
#serializer.pname = self.pname
if "typed" not in kw:
kw['typed'] = False
elif tag:
if tag.find(':') == -1: tag = 'SOAP-ENC:' + tag
kw['name'] = tag
kw['typed'] = False
serializer.unique = self.unique
serializer.serialize(elt, sw, pyobj, **kw)
# Reset TypeCode
#serializer.nspname = None
#serializer.pname = None
class String(SimpleType):
'''A string type.
'''
empty_content = ''
parselist = [ (None,'string') ]
seriallist = [ types.StringType, types.UnicodeType ]
type = (SCHEMA.XSD3, 'string')
logger = _GetLogger('ZSI.TC.String')
def __init__(self, pname=None, strip=True, **kw):
TypeCode.__init__(self, pname, **kw)
if kw.has_key('resolver'): self.resolver = kw['resolver']
self.strip = strip
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
Encode all strings as UTF-8, which will be type 'str'
not 'unicode'
'''
if self.strip: text = text.strip()
if self.pyclass is not None:
return self.pyclass(text.encode(UNICODE_ENCODING))
return text.encode(UNICODE_ENCODING)
def get_formatted_content(self, pyobj):
if type(pyobj) not in _stringtypes:
pyobj = str(pyobj)
if type(pyobj) == unicode:
return pyobj.encode(UNICODE_ENCODING)
return pyobj
class URI(String):
'''A URI.
Class data:
reserved -- urllib.quote will escape all reserved characters
regardless of whether they are used for the reserved purpose.
'''
parselist = [ (None,'anyURI'),(SCHEMA.XSD3, 'anyURI')]
type = (SCHEMA.XSD3, 'anyURI')
logger = _GetLogger('ZSI.TC.URI')
reserved = ";/?:@&=+$,"
def text_to_data(self, text, elt, ps):
'''text --> typecode specific data.
'''
return String.text_to_data(self, urldecode(text), elt, ps)
def get_formatted_content(self, pyobj):
'''typecode data --> text
'''
u = urlencode(pyobj, self.reserved)
return String.get_formatted_content(self,
u)
class QName(String):
'''A QName type
'''
parselist = [ (None,'QName') ]
type = (SCHEMA.XSD3, 'QName')
logger = _GetLogger('ZSI.TC.QName')
def __init__(self, pname=None, strip=1, **kw):
String.__init__(self, pname, strip, **kw)
self.prefix = None
def get_formatted_content(self, pyobj):
value = pyobj
if isinstance(pyobj, tuple):
namespaceURI,localName = pyobj
if self.prefix is not None:
value = "%s:%s" %(self.prefix,localName)
return String.get_formatted_content(self, value)
def set_prefix(self, elt, pyobj):
'''use this method to set the prefix of the QName,
method looks in DOM to find prefix or set new prefix.
This method must be called before get_formatted_content.
'''
if isinstance(pyobj, tuple):
namespaceURI,localName = pyobj
self.prefix = elt.getPrefix(namespaceURI)
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
'''
prefix,localName = SplitQName(text)
nsdict = ps.GetElementNSdict(elt)
prefix = prefix or ''
try:
namespaceURI = nsdict[prefix]
except KeyError, ex:
raise EvaluateException('cannot resolve prefix(%s)'%prefix,
ps.Backtrace(elt))
v = (namespaceURI,localName)
if self.pyclass is not None:
return self.pyclass(v)
return v
def serialize_text_node(self, elt, sw, pyobj):
'''Serialize without an element node.
'''
self.set_prefix(elt, pyobj)
return String.serialize_text_node(self, elt, sw, pyobj)
class Token(String):
'''an xsd:token type
'''
parselist = [ (None, 'token') ]
type = (SCHEMA.XSD3, 'token')
logger = _GetLogger('ZSI.TC.Token')
class Base64String(String):
'''A Base64 encoded string.
'''
parselist = [ (None,'base64Binary'), (SOAP.ENC, 'base64') ]
type = (SOAP.ENC, 'base64')
logger = _GetLogger('ZSI.TC.Base64String')
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
'''
val = b64decode(text.replace(' ', '').replace('\n','').replace('\r',''))
if self.pyclass is not None:
return self.pyclass(val)
return val
def get_formatted_content(self, pyobj):
pyobj = '\n' + b64encode(pyobj)
return String.get_formatted_content(self, pyobj)
class Base64Binary(String):
parselist = [ (None,'base64Binary'), ]
type = (SCHEMA.XSD3, 'base64Binary')
logger = _GetLogger('ZSI.TC.Base64Binary')
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
'''
val = b64decode(text)
if self.pyclass is not None:
return self.pyclass(val)
return val
def get_formatted_content(self, pyobj):
pyobj = b64encode(pyobj).strip()
return pyobj
class HexBinaryString(String):
'''Hex-encoded binary (yuk).
'''
parselist = [ (None,'hexBinary') ]
type = (SCHEMA.XSD3, 'hexBinary')
logger = _GetLogger('ZSI.TC.HexBinaryString')
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
'''
val = hexdecode(text)
if self.pyclass is not None:
return self.pyclass(val)
return val
def get_formatted_content(self, pyobj):
pyobj = hexencode(pyobj).upper()
return String.get_formatted_content(self, pyobj)
class XMLString(String):
'''A string that represents an XML document
'''
logger = _GetLogger('ZSI.TC.XMLString')
def __init__(self, pname=None, readerclass=None, **kw):
String.__init__(self, pname, **kw)
self.readerclass = readerclass
def parse(self, elt, ps):
if not self.readerclass:
from xml.dom.ext.reader import PyExpat
self.readerclass = PyExpat.Reader
v = String.parse(self, elt, ps)
return self.readerclass().fromString(v)
def get_formatted_content(self, pyobj):
#pyobj = Canonicalize(pyobj)
return String.get_formatted_content(self, pyobj)
class Enumeration(String):
'''A string type, limited to a set of choices.
'''
logger = _GetLogger('ZSI.TC.Enumeration')
def __init__(self, choices, pname=None, **kw):
String.__init__(self, pname, **kw)
t = type(choices)
if t in _seqtypes:
self.choices = tuple(choices)
elif TypeCode.typechecks:
raise TypeError(
'Enumeration choices must be list or sequence, not ' + str(t))
if TypeCode.typechecks:
for c in self.choices:
if type(c) not in _stringtypes:
raise TypeError(
'Enumeration choice ' + str(c) + ' is not a string')
def parse(self, elt, ps):
val = String.parse(self, elt, ps)
if val not in self.choices:
raise EvaluateException('Value not in enumeration list',
ps.Backtrace(elt))
return val
def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
if pyobj not in self.choices:
raise EvaluateException('Value not in enumeration list',
sw.Backtrace(elt))
String.serialize(self, elt, sw, pyobj, name=name, orig=orig, **kw)
# This is outside the Integer class purely for code esthetics.
_ignored = []
class Integer(SimpleType):
'''Common handling for all integers.
'''
ranges = {
'unsignedByte': (0, 255),
'unsignedShort': (0, 65535),
'unsignedInt': (0, 4294967295L),
'unsignedLong': (0, 18446744073709551615L),
'byte': (-128, 127),
'short': (-32768, 32767),
'int': (-2147483648L, 2147483647),
'long': (-9223372036854775808L, 9223372036854775807L),
'negativeInteger': (_ignored, -1),
'nonPositiveInteger': (_ignored, 0),
'nonNegativeInteger': (0, _ignored),
'positiveInteger': (1, _ignored),
'integer': (_ignored, _ignored)
}
parselist = [ (None,k) for k in ranges.keys() ]
seriallist = [ types.IntType, types.LongType ]
logger = _GetLogger('ZSI.TC.Integer')
def __init__(self, pname=None, format='%d', **kw):
TypeCode.__init__(self, pname, **kw)
self.format = format
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
'''
if self.pyclass is not None:
v = self.pyclass(text)
else:
try:
v = int(text)
except:
try:
v = long(text)
except:
raise EvaluateException('Unparseable integer',
ps.Backtrace(elt))
return v
def parse(self, elt, ps):
(ns,type) = self.checkname(elt, ps)
if self.nilled(elt, ps): return Nilled
elt = self.SimpleHREF(elt, ps, 'integer')
if not elt: return None
if type is None:
type = self.type[1]
elif self.type[1] is not None and type != self.type[1]:
raise EvaluateException('Integer type mismatch; ' \
'got %s wanted %s' % (type,self.type[1]), ps.Backtrace(elt))
v = self.simple_value(elt, ps)
v = self.text_to_data(v, elt, ps)
(rmin, rmax) = Integer.ranges.get(type, (_ignored, _ignored))
if rmin != _ignored and v < rmin:
raise EvaluateException('Underflow, less than ' + repr(rmin),
ps.Backtrace(elt))
if rmax != _ignored and v > rmax:
raise EvaluateException('Overflow, greater than ' + repr(rmax),
ps.Backtrace(elt))
return v
def get_formatted_content(self, pyobj):
return self.format %pyobj
# See credits, below.
def _make_inf():
x = 2.0
x2 = x * x
i = 0
while i < 100 and x != x2:
x = x2
x2 = x * x
i = i + 1
if x != x2:
raise ValueError("This machine's floats go on forever!")
return x
# This is outside the Decimal class purely for code esthetics.
_magicnums = { }
try:
_magicnums['INF'] = float('INF')
_magicnums['-INF'] = float('-INF')
except:
_magicnums['INF'] = _make_inf()
_magicnums['-INF'] = -_magicnums['INF']
# The following comment and code was written by Tim Peters in
# article <001401be92d2$09dcb800$5fa02299@tim> in comp.lang.python,
# also available at the following URL:
# http://groups.google.com/groups?selm=001401be92d2%2409dcb800%245fa02299%40tim
# Thanks, Tim!
# NaN-testing.
#
# The usual method (x != x) doesn't work.
# Python forces all comparisons thru a 3-outcome cmp protocol; unordered
# isn't a possible outcome. The float cmp outcome is essentially defined
# by this C expression (combining some cross-module implementation
# details, and where px and py are pointers to C double):
# px == py ? 0 : *px < *py ? -1 : *px > *py ? 1 : 0
# Comparing x to itself thus always yields 0 by the first clause, and so
# x != x is never true.
# If px and py point to distinct NaN objects, a strange thing happens:
# 1. On scrupulous 754 implementations, *px < *py returns false, and so
# does *px > *py. Python therefore returns 0, i.e. "equal"!
# 2. On Pentium HW, an unordered outcome sets an otherwise-impossible
# combination of condition codes, including both the "less than" and
# "equal to" flags. Microsoft C generates naive code that accepts
# the "less than" flag at face value, and so the *px < *py clause
# returns true, and Python returns -1, i.e. "not equal".
# So with a proper C 754 implementation Python returns the wrong result,
# and under MS's improper 754 implementation Python yields the right
# result -- both by accident. It's unclear who should be shot .
#
# Anyway, the point of all that was to convince you it's tricky getting
# the right answer in a portable way!
def isnan(x):
"""x -> true iff x is a NaN."""
# multiply by 1.0 to create a distinct object (x < x *always*
# false in Python, due to object identity forcing equality)
if x * 1.0 < x:
# it's a NaN and this is MS C on a Pentium
return 1
# Else it's non-NaN, or NaN on a non-MS+Pentium combo.
# If it's non-NaN, then x == 1.0 and x == 2.0 can't both be true,
# so we return false. If it is NaN, then assuming a good 754 C
# implementation Python maps both unordered outcomes to true.
return 1.0 == x and x == 2.0
class Decimal(SimpleType):
'''Parent class for floating-point numbers.
'''
parselist = [ (None,'decimal'), (None,'float'), (None,'double') ]
seriallist = _floattypes
type = None
ranges = {
'float': ( 7.0064923216240861E-46,
-3.4028234663852886E+38, 3.4028234663852886E+38 ),
'double': ( 2.4703282292062327E-324,
-1.7976931348623158E+308, 1.7976931348623157E+308),
}
zeropat = re.compile('[1-9]')
logger = _GetLogger('ZSI.TC.Decimal')
def __init__(self, pname=None, format='%f', **kw):
TypeCode.__init__(self, pname, **kw)
self.format = format
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
'''
v = text
if self.pyclass is not None:
return self.pyclass(v)
m = _magicnums.get(v)
if m: return m
try:
return float(v)
except:
raise EvaluateException('Unparseable floating point number',
ps.Backtrace(elt))
def parse(self, elt, ps):
(ns,type) = self.checkname(elt, ps)
elt = self.SimpleHREF(elt, ps, 'floating-point')
if not elt: return None
tag = getattr(self.__class__, 'type')
if tag:
if type is None:
type = tag
elif tag != (ns,type):
raise EvaluateException('Floating point type mismatch; ' \
'got (%s,%s) wanted %s' % (ns,type,tag), ps.Backtrace(elt))
# Special value?
if self.nilled(elt, ps): return Nilled
v = self.simple_value(elt, ps)
try:
fp = self.text_to_data(v, elt, ps)
except EvaluateException, ex:
ex.args.append(ps.Backtrace(elt))
raise ex
m = _magicnums.get(v)
if m:
return m
if str(fp).lower() in [ 'inf', '-inf', 'nan', '-nan' ]:
raise EvaluateException('Floating point number parsed as "' + \
str(fp) + '"', ps.Backtrace(elt))
if fp == 0 and Decimal.zeropat.search(v):
raise EvaluateException('Floating point number parsed as zero',
ps.Backtrace(elt))
(rtiny, rneg, rpos) = Decimal.ranges.get(type, (None, None, None))
if rneg and fp < 0 and fp < rneg:
raise EvaluateException('Negative underflow', ps.Backtrace(elt))
if rtiny and fp > 0 and fp < rtiny:
raise EvaluateException('Positive underflow', ps.Backtrace(elt))
if rpos and fp > 0 and fp > rpos:
raise EvaluateException('Overflow', ps.Backtrace(elt))
return fp
def get_formatted_content(self, pyobj):
if pyobj == _magicnums['INF']:
return 'INF'
elif pyobj == _magicnums['-INF']:
return '-INF'
elif isnan(pyobj):
return 'NaN'
else:
return self.format %pyobj
class Boolean(SimpleType):
'''A boolean.
'''
parselist = [ (None,'boolean') ]
seriallist = [ bool ]
type = (SCHEMA.XSD3, 'boolean')
logger = _GetLogger('ZSI.TC.Boolean')
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data.
'''
v = text
if v == 'false':
if self.pyclass is None:
return False
return self.pyclass(False)
if v == 'true':
if self.pyclass is None:
return True
return self.pyclass(True)
try:
v = int(v)
except:
try:
v = long(v)
except:
raise EvaluateException('Unparseable boolean',
ps.Backtrace(elt))
if v:
if self.pyclass is None:
return True
return self.pyclass(True)
if self.pyclass is None:
return False
return self.pyclass(False)
def parse(self, elt, ps):
self.checkname(elt, ps)
elt = self.SimpleHREF(elt, ps, 'boolean')
if not elt: return None
if self.nilled(elt, ps): return Nilled
v = self.simple_value(elt, ps).lower()
return self.text_to_data(v, elt, ps)
def get_formatted_content(self, pyobj):
if pyobj: return 'true'
return 'false'
#XXX NOT FIXED YET
class XML(TypeCode):
'''Opaque XML which shouldn't be parsed.
comments -- preserve comments
inline -- don't href/id when serializing
resolver -- object to resolve href's
wrapped -- put a wrapper element around it
'''
# Clone returned data?
copyit = 0
logger = _GetLogger('ZSI.TC.XML')
def __init__(self, pname=None, comments=0, inline=0, wrapped=True, **kw):
TypeCode.__init__(self, pname, **kw)
self.comments = comments
self.inline = inline
if kw.has_key('resolver'): self.resolver = kw['resolver']
self.wrapped = wrapped
self.copyit = kw.get('copyit', XML.copyit)
def parse(self, elt, ps):
if self.wrapped is False:
return elt
c = _child_elements(elt)
if not c:
href = _find_href(elt)
if not href:
if self.minOccurs == 0: return None
raise EvaluateException('Embedded XML document missing',
ps.Backtrace(elt))
if href[0] != '#':
return ps.ResolveHREF(href, self)
elt = ps.FindLocalHREF(href, elt)
c = _child_elements(elt)
if _find_encstyle(elt) != "":
#raise EvaluateException('Embedded XML has unknown encodingStyle',
# ps.Backtrace(elt)
pass
if len(c) != 1:
raise EvaluateException('Embedded XML has more than one child',
ps.Backtrace(elt))
if self.copyit: return c[0].cloneNode(1)
return c[0]
def serialize(self, elt, sw, pyobj, name=None, unsuppressedPrefixes=[], **kw):
objid = _get_idstr(pyobj)
ns,n = self.get_name(name, objid)
xmlelt = elt
if self.wrapped:
xmlelt = elt.createAppendElement(ns, n)
#if type(pyobj) in _stringtypes:
# self.set_attributes(xmlelt, pyobj)
# self.set_attribute_href(xmlelt, objid)
#elif kw.get('inline', self.inline):
# self.cb(xmlelt, sw, pyobj, unsuppressedPrefixes)
#else:
# self.set_attributes(xmlelt, pyobj)
# self.set_attribute_href(xmlelt, objid)
# sw.AddCallback(self.cb, elt, sw, pyobj, unsuppressedPrefixes)
self.cb(xmlelt, sw, pyobj, unsuppressedPrefixes)
def cb(self, elt, sw, pyobj, unsuppressedPrefixes=[]):
"""pyobj -- xml.dom.Node.ELEMENT_NODE
"""
#if sw.Known(pyobj):
# return
if type(pyobj) in _stringtypes:
elt.createAppendTextNode(pyobj)
return
## grab document and import node, and append it
doc = elt.getDocument()
node = doc.importNode(pyobj, deep=1)
child = elt.node.appendChild(node)
## copy xmlns: attributes into appended node
parent = pyobj.parentNode
while parent.nodeType == _Node.ELEMENT_NODE:
for attr in filter(lambda a: a.name.startswith('xmlns:') and a.name not in child.attributes.keys(), parent.attributes):
child.setAttributeNode(attr.cloneNode(1))
parent = parent.parentNode
class AnyType(TypeCode):
"""XML Schema xsi:anyType type definition wildCard.
class variables:
all -- specifies use of all namespaces.
other -- specifies use of other namespaces
type --
"""
all = '#all'
other = '#other'
type = (SCHEMA.XSD3, 'anyType')
logger = _GetLogger('ZSI.TC.AnyType')
def __init__(self, pname=None, namespaces=['#all'],
minOccurs=1, maxOccurs=1, strip=1, **kw):
TypeCode.__init__(self, pname=pname, minOccurs=minOccurs,
maxOccurs=maxOccurs, **kw)
self.namespaces = namespaces
def get_formatted_content(self, pyobj):
# TODO: not sure this makes sense,
# parse side will be clueless, but oh well..
what = getattr(pyobj, 'typecode', Any())
return what.get_formatted_content(pyobj)
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data. Used only with
attributes so will not know anything about this content so
why guess?
Parameters:
text -- text content
elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
return text
def serialize(self, elt, sw, pyobj, **kw):
nsuri,typeName = _get_xsitype(pyobj)
if self.all not in self.namespaces and nsuri not in self.namespaces:
raise EvaluateException(
' unsupported use of namespaces "%s"' %self.namespaces)
what = getattr(pyobj, 'typecode', None)
if what is None:
# TODO: resolve this, "strict" processing but no
# concrete schema makes little sense.
#what = _AnyStrict(pname=(self.nspname,self.pname))
what = Any(pname=(self.nspname,self.pname), unique=True,
aslist=False)
kw['typed'] = True
what.serialize(elt, sw, pyobj, **kw)
return
# Namespace if element AnyType was namespaced.
what.serialize(elt, sw, pyobj,
name=(self.nspname or what.nspname, self.pname or what.pname), **kw)
def parse(self, elt, ps):
#element name must be declared ..
nspname,pname = _get_element_nsuri_name(elt)
if nspname != self.nspname or pname != self.pname:
raise EvaluateException(' instance is (%s,%s) found (%s,%s)' %(
self.nspname,self.pname,nspname,pname), ps.Backtrace(elt))
#locate xsi:type
prefix, typeName = SplitQName(_find_type(elt))
namespaceURI = _resolve_prefix(elt, prefix)
pyclass = GTD(namespaceURI, typeName)
if not pyclass:
if _is_xsd_or_soap_ns(namespaceURI):
pyclass = Any
elif (str(namespaceURI).lower()==str(Apache.Map.type[0]).lower())\
and (str(typeName).lower() ==str(Apache.Map.type[1]).lower()):
pyclass = Apache.Map
else:
# Unknown type, so parse into a dictionary
pyobj = Any().parse_into_dict_or_list(elt, ps)
return pyobj
what = pyclass(pname=(self.nspname,self.pname))
pyobj = what.parse(elt, ps)
return pyobj
class AnyElement(AnyType):
"""XML Schema xsi:any element declaration wildCard.
class variables:
tag -- global element declaration
"""
tag = (SCHEMA.XSD3, 'any')
logger = _GetLogger('ZSI.TC.AnyElement')
def __init__(self, namespaces=['#all'],pname=None,
minOccurs=1, maxOccurs=1, strip=1, processContents='strict',
**kw):
if processContents not in ('lax', 'skip', 'strict'):
raise ValueError('processContents(%s) must be lax, skip, or strict')
self.processContents = processContents
AnyType.__init__(self, namespaces=namespaces,pname=pname,
minOccurs=minOccurs, maxOccurs=maxOccurs, strip=strip, **kw)
def serialize(self, elt, sw, pyobj, **kw):
'''Must provice typecode to AnyElement for serialization, else
try to use TC.Any to serialize instance which will serialize
based on the data type of pyobj w/o reference to XML schema
instance.
'''
if isinstance(pyobj, TypeCode):
raise TypeError, 'pyobj is a typecode instance.'
what = getattr(pyobj, 'typecode', None)
if what is not None and type(pyobj) is types.InstanceType:
tc = pyobj.__class__
what = Any.serialmap.get(tc)
if not what:
tc = (types.ClassType, pyobj.__class__.__name__)
what = Any.serialmap.get(tc)
self.logger.debug('processContents: %s', self.processContents)
# failed to find a registered type for class
if what is None:
#TODO: seems incomplete. what about facets.
#if self.processContents == 'strict':
what = Any(pname=(self.nspname,self.pname))
self.logger.debug('serialize with %s', what.__class__.__name__)
what.serialize(elt, sw, pyobj, **kw)
def parse(self, elt, ps):
'''
processContents -- 'lax' | 'skip' | 'strict', 'strict'
1) if 'skip' check namespaces, and return the DOM node.
2) if 'lax' look for declaration, or definition. If
not found return DOM node.
3) if 'strict' get declaration, or raise.
'''
skip = self.processContents == 'skip'
nspname,pname = _get_element_nsuri_name(elt)
what = GED(nspname, pname)
if not skip and what is not None:
pyobj = what.parse(elt, ps)
try:
pyobj.typecode = what
except AttributeError, ex:
# Assume this means builtin type.
pyobj = WrapImmutable(pyobj, what)
return pyobj
# Allow use of "" element declarations w/ local
# element declarations
prefix, typeName = SplitQName(_find_type(elt))
if not skip and typeName:
namespaceURI = _resolve_prefix(elt, prefix or 'xmlns')
# First look thru user defined namespaces, if don't find
# look for 'primitives'.
pyclass = GTD(namespaceURI, typeName) or Any
what = pyclass(pname=(nspname,pname))
pyobj = what.parse(elt, ps)
try:
pyobj.typecode = what
except AttributeError, ex:
# Assume this means builtin type.
pyobj = WrapImmutable(pyobj, what)
what.typed = True
return pyobj
if skip:
what = XML(pname=(nspname,pname), wrapped=False)
elif self.processContents == 'lax':
what = Any(pname=(nspname,pname), unique=True)
else:
what = Any(pname=(nspname,pname), unique=True)
try:
pyobj = what.parse(elt, ps)
except EvaluateException, ex:
self.logger.debug("error parsing: %s" %str(ex))
if len(_children(elt)) != 0:
self.logger.debug('parse , return as dict')
return Any(aslist=False).parse_into_dict_or_list(elt, ps)
self.logger.debug("Give up, parse (%s,%s) as a String",
what.nspname, what.pname)
what = String(pname=(nspname,pname), typed=False)
return WrapImmutable(what.parse(elt, ps), what)
if pyobj is None:
return
# dict is elementName:value pairs
if type(pyobj) is dict:
return pyobj
try:
pyobj.typecode = what
except AttributeError:
pyobj = WrapImmutable(pyobj, what)
return pyobj
class Union(SimpleType):
'''simpleType Union
class variables:
memberTypes -- list [(namespace,name),] tuples, each representing a type defintion.
'''
memberTypes = None
logger = _GetLogger('ZSI.TC.Union')
def __init__(self, pname=None, minOccurs=1, maxOccurs=1, **kw):
SimpleType.__init__(self, pname=pname, minOccurs=minOccurs, maxOccurs=maxOccurs, **kw)
self.memberTypeCodes = []
def setMemberTypeCodes(self):
if len(self.memberTypeCodes) > 0:
return
if self.__class__.memberTypes is None:
raise EvaluateException, 'uninitialized class variable memberTypes [(namespace,name),]'
for nsuri,name in self.__class__.memberTypes:
tcclass = GTD(nsuri,name)
if tcclass is None:
tc = Any.parsemap.get((nsuri,name)) or Any.parsemap.get((None, name))
typecode = tc.__class__(pname=(self.nspname,self.pname))
else:
typecode = tcclass(pname=(self.nspname,self.pname))
if typecode is None:
raise EvaluateException, \
'Typecode class for Union memberType (%s,%s) is missing' %(nsuri,name)
if isinstance(typecode, Struct):
raise EvaluateException, \
'Illegal: Union memberType (%s,%s) is complexType' %(nsuri,name)
self.memberTypeCodes.append(typecode)
def parse(self, elt, ps, **kw):
'''attempt to parse sequentially. No way to know ahead of time
what this instance represents. Must be simple type so it can
not have attributes nor children, so this isn't too bad.
'''
self.setMemberTypeCodes()
(nsuri,typeName) = self.checkname(elt, ps)
#if (nsuri,typeName) not in self.memberTypes:
# raise EvaluateException(
# 'Union Type mismatch got (%s,%s) not in %s' % \
# (nsuri, typeName, self.memberTypes), ps.Backtrace(elt))
for indx in range(len(self.memberTypeCodes)):
typecode = self.memberTypeCodes[indx]
try:
pyobj = typecode.parse(elt, ps)
except ParseException, ex:
continue
except Exception, ex:
continue
if indx > 0:
self.memberTypeCodes.remove(typecode)
self.memberTypeCodes.insert(0, typecode)
break
else:
raise
return pyobj
def get_formatted_content(self, pyobj, **kw):
self.setMemberTypeCodes()
for indx in range(len(self.memberTypeCodes)):
typecode = self.memberTypeCodes[indx]
try:
content = typecode.get_formatted_content(copy.copy(pyobj))
break
except (ParseException, TypeError):
pass
if indx > 0:
self.memberTypeCodes.remove(typecode)
self.memberTypeCodes.insert(0, typecode)
else:
raise
return content
class List(SimpleType):
'''simpleType List
Class data:
itemType -- sequence (namespaceURI,name) or a TypeCode instance
representing the type definition
'''
itemType = None
logger = _GetLogger('ZSI.TC.List')
def __init__(self, pname=None, itemType=None, **kw):
'''Currently need to require maxOccurs=1, so list
is interpreted as a single unit of data.
'''
assert kw.get('maxOccurs',1) == 1, \
'Currently only supporting SimpleType Lists with maxOccurs=1'
SimpleType.__init__(self, pname=pname, **kw)
self.itemType = itemType or self.itemType
self.itemTypeCode = self.itemType
itemTypeCode = None
if type(self.itemTypeCode) in _seqtypes:
namespaceURI,name = self.itemTypeCode
try:
itemTypeCode = GTD(*self.itemType)(None)
except:
if _is_xsd_or_soap_ns(namespaceURI) is False:
raise
for pyclass in TYPES:
if pyclass.type == self.itemTypeCode:
itemTypeCode = pyclass(None)
break
elif pyclass.type[1] == name:
itemTypeCode = pyclass(None)
if itemTypeCode is None:
raise EvaluateException('Failed to locate %s' %str(self.itemTypeCode))
if hasattr(itemTypeCode, 'text_to_data') is False:
raise EvaluateException('TypeCode class %s missing text_to_data method' %itemTypeCode)
self.itemTypeCode = itemTypeCode
def text_to_data(self, text, elt, ps):
'''convert text into typecode specific data. items in
list are space separated.
'''
v = []
items = text.split()
for item in items:
v.append(self.itemTypeCode.text_to_data(item, elt, ps))
if self.pyclass is not None:
return self.pyclass(v)
return v
def parse(self, elt, ps):
'''elt -- the DOM element being parsed
ps -- the ParsedSoap object.
'''
self.checkname(elt, ps)
if len(_children(elt)) == 0:
href = _find_href(elt)
if not href:
if self.nilled(elt, ps) is False:
return []
if self.nillable is True:
return Nilled
raise EvaluateException('Required string missing',
ps.Backtrace(elt))
if href[0] != '#':
return ps.ResolveHREF(href, self)
elt = ps.FindLocalHREF(href, elt)
self.checktype(elt, ps)
if self.nilled(elt, ps): return Nilled
if len(_children(elt)) == 0: return []
v = self.simple_value(elt, ps)
return self.text_to_data(v, elt, ps)
def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
'''elt -- the current DOMWrapper element
sw -- soapWriter object
pyobj -- python object to serialize
'''
if pyobj is not None and type(pyobj) not in _seqtypes:
raise EvaluateException, 'expecting a list or None'
objid = _get_idstr(pyobj)
ns,n = self.get_name(name, objid)
el = elt.createAppendElement(ns, n)
if self.nillable is True and pyobj is None:
self.serialize_as_nil(el)
return None
tc = self.itemTypeCode
s = StringIO(); sep = ' '
for item in pyobj:
s.write(tc.get_formatted_content(item))
s.write(sep)
el.createAppendTextNode(s.getvalue())
def RegisterType(C, clobber=0, *args, **keywords):
instance = apply(C, args, keywords)
for t in C.__dict__.get('parselist', []):
prev = Any.parsemap.get(t)
if prev:
if prev.__class__ == C: continue
if not clobber:
raise TypeError(
str(C) + ' duplicating parse registration for ' + str(t))
Any.parsemap[t] = instance
for t in C.__dict__.get('seriallist', []):
ti = type(t)
if ti in [ types.TypeType, types.ClassType]:
key = t
elif ti in _stringtypes:
key = (types.ClassType, t)
else:
raise TypeError(str(t) + ' is not a class name')
prev = Any.serialmap.get(key)
if prev:
if prev.__class__ == C: continue
if not clobber:
raise TypeError(
str(C) + ' duplicating serial registration for ' + str(t))
Any.serialmap[key] = instance
#def _DynamicImport(moduleName, className):
# '''
# Utility function for RegisterTypeWithSchemaAndClass
# '''
# mod = __import__(moduleName)
# components = moduleName.split('.')
# for comp in components[1:]:
# mod = getattr(mod, comp)
# return getattr(mod, className)
#
#def _RegisterTypeWithSchemaAndClass(importedSchemaTypes, schemaTypeName, classModuleName, className, generatedClassSuffix="_"):
# '''
# Used by RegisterGeneratedTypesWithMapping.
# Helps register classes so they can be serialized and parsed as "any".
# Register a type by providing its schema and class. This allows
# Any and AnyType to reconstruct objects made up of your own classes.
# Note: The class module should be able to be imported (by being in your
# pythonpath). Your classes __init__ functions shoud have default
# arguments for all extra parameters.
# Example of use:
# import SchemaToPyTypeMap # Mapping written by you. Also used with wsdl2py -m
# # mapping = {"SomeDescription":("Descriptions", "SomeDescription"),
# # schemaTypeName : moduleName , className
# # The module on the next line is generated by wsdl2py
# from EchoServer_services_types import urn_ZSI_examples as ExampleTypes
#
# for key,value in SchemaToPyTypeMap.mapping.items():
# ZSI.TC.RegisterTypeWithSchemaAndClass(importedSchemaTypes = ExampleTypes, schemaTypeName=key, classModuleName=value[0], className=value[1])
#
# '''
# # Doing this: (schemaTypeName="ExampleTypes", classModuleName="Description",
# # className="SomeDescription")
# # sd_instance = ExampleTypes.SomeDescription_(pname="SomeDescription")
# # Any.serialmap[Descriptions.SomeDescription] = sd_instance
# # Any.parsemap[(None,'SomeDescription')] = sd_instance
# classDef = _DynamicImport(classModuleName, className)
# interfaceDef = getattr(importedSchemaTypes, schemaTypeName + generatedClassSuffix)
#
# instance = interfaceDef(pname=className)
# Any.serialmap[classDef] = instance
# Any.parsemap[(None,schemaTypeName)] = instance
#
#def RegisterGeneratedTypesWithMapping(generatedTypes, mapping, generatedClassSuffix="_"):
# '''
# Registers python classes so they can be serialized and parsed as "any".
# generatedTypes is a class containing typecode classes generated by zsi.
# mapping is a dictionary that maps
# {schemaTypeName : moduleName, className}
# and is also used with wsdl2py -m
#
# Example of use:
# import SchemaToPyTypeMap # See RegisterTypeWithSchemaAndClass for description
# # The module on the next line is generated by wsdl2py and
# # contains generated typecodes.
# from EchoServer_services_types import urn_ZSI_examples as ExampleTypes
# RegisterGeneratedTypesWithMapping(generatedTypes = ExampleTypes, mapping=SchemaToPyTypeMap.mapping)
# '''
# for key,value in mapping.items():
# _RegisterTypeWithSchemaAndClass(importedSchemaTypes = generatedTypes, schemaTypeName=key, classModuleName=value[0], className=value[1], generatedClassSuffix=generatedClassSuffix)
from TCnumbers import *
from TCtimes import *
from schema import GTD, GED, WrapImmutable
from TCcompound import *
from TCapache import *
# aliases backwards compatiblity
_get_type_definition, _get_global_element_declaration, Wrap = GTD, GED, WrapImmutable
f = lambda x: type(x) == types.ClassType and issubclass(x, TypeCode) and getattr(x, 'type', None) is not None
TYPES = filter(f, map(lambda y:eval(y),dir()))
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/.cvsignore 0000644 0001751 0001751 00000000021 07365336046 013170 0 ustar zsi zsi *.pyc
version.py
ZSI-2.1-a1/ZSI/ServiceContainer.py 0000644 0001751 0001751 00000042056 10656174245 015021 0 ustar zsi zsi #! /usr/bin/env python
'''Simple Service Container
-- use with wsdl2py generated modules.
'''
import urlparse, types, os, sys, cStringIO as StringIO, thread,re
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from ZSI import ParseException, FaultFromException, FaultFromZSIException, Fault
from ZSI import _copyright, _seqtypes, _get_element_nsuri_name, resolvers
from ZSI import _get_idstr
from ZSI.address import Address
from ZSI.parse import ParsedSoap
from ZSI.writer import SoapWriter
from ZSI.dispatch import _ModPythonSendXML, _ModPythonSendFault, _CGISendXML, _CGISendFault
from ZSI.dispatch import SOAPRequestHandler as BaseSOAPRequestHandler
"""
Functions:
_Dispatch
AsServer
GetSOAPContext
Classes:
SOAPContext
NoSuchService
PostNotSpecified
SOAPActionNotSpecified
ServiceSOAPBinding
WSAResource
SimpleWSResource
SOAPRequestHandler
ServiceContainer
"""
class NoSuchService(Exception): pass
class UnknownRequestException(Exception): pass
class PostNotSpecified(Exception): pass
class SOAPActionNotSpecified(Exception): pass
class WSActionException(Exception): pass
class WSActionNotSpecified(WSActionException): pass
class NotAuthorized(Exception): pass
class ServiceAlreadyPresent(Exception): pass
class SOAPContext:
def __init__(self, container, xmldata, ps, connection, httpheaders,
soapaction):
self.container = container
self.xmldata = xmldata
self.parsedsoap = ps
self.connection = connection
self.httpheaders= httpheaders
self.soapaction = soapaction
_contexts = dict()
def GetSOAPContext():
global _contexts
return _contexts[thread.get_ident()]
def _Dispatch(ps, server, SendResponse, SendFault, post, action, nsdict={}, **kw):
'''Send ParsedSoap instance to ServiceContainer, which dispatches to
appropriate service via post, and method via action. Response is a
self-describing pyobj, which is passed to a SoapWriter.
Call SendResponse or SendFault to send the reply back, appropriately.
server -- ServiceContainer instance
'''
localURL = 'http://%s:%d%s' %(server.server_name,server.server_port,post)
address = action
service = server.getNode(post)
isWSResource = False
if isinstance(service, WSAResource):
isWSResource = True
service.setServiceURL(localURL)
address = Address()
try:
address.parse(ps)
except Exception, e:
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
if action and action != address.getAction():
e = WSActionException('SOAP Action("%s") must match WS-Action("%s") if specified.' \
%(action,address.getAction()))
return SendFault(FaultFromException(e, 0, None), **kw)
action = address.getAction()
if isinstance(service, ServiceInterface) is False:
e = NoSuchService('no service at POST(%s) in container: %s' %(post,server))
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
if not service.authorize(None, post, action):
return SendFault(Fault(Fault.Server, "Not authorized"), code=401)
#try:
# raise NotAuthorized()
#except Exception, e:
#return SendFault(FaultFromException(e, 0, None), code=401, **kw)
##return SendFault(FaultFromException(NotAuthorized(), 0, None), code=401, **kw)
try:
method = service.getOperation(ps, address)
except Exception, e:
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
try:
if isWSResource is True:
request,result = method(ps, address)
else:
request,result = method(ps)
except Exception, e:
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
# Verify if Signed
service.verify(ps)
# If No response just return.
if result is None:
return SendResponse('', **kw)
sw = SoapWriter(nsdict=nsdict)
try:
sw.serialize(result)
except Exception, e:
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
if isWSResource is True:
action = service.getResponseAction(ps, action)
addressRsp = Address(action=action)
try:
addressRsp.setResponseFromWSAddress(address, localURL)
addressRsp.serialize(sw)
except Exception, e:
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
# Create Signatures
service.sign(sw)
try:
soapdata = str(sw)
return SendResponse(soapdata, **kw)
except Exception, e:
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
def AsServer(port=80, services=()):
'''port --
services -- list of service instances
'''
address = ('', port)
sc = ServiceContainer(address, services)
sc.serve_forever()
class ServiceInterface:
'''Defines the interface for use with ServiceContainer Handlers.
class variables:
soapAction -- dictionary of soapAction keys, and operation name values.
These are specified in the WSDL soap bindings. There must be a
class method matching the operation name value. If WS-Action is
used the keys are WS-Action request values, according to the spec
if soapAction and WS-Action is specified they must be equal.
wsAction -- dictionary of operation name keys and WS-Action
response values. These values are specified by the portType.
root -- dictionary of root element keys, and operation name values.
'''
soapAction = {}
wsAction = {}
root = {}
def __init__(self, post):
self.post = post
def authorize(self, auth_info, post, action):
return 1
def __str__(self):
return '%s(%s) POST(%s)' %(self.__class__.__name__, _get_idstr(self), self.post)
def sign(self, sw):
return
def verify(self, ps):
return
def getPost(self):
return self.post
def getOperation(self, ps, action):
'''Returns a method of class.
action -- soapAction value
'''
opName = self.getOperationName(ps, action)
return getattr(self, opName)
def getOperationName(self, ps, action):
'''Returns operation name.
action -- soapAction value
'''
method = self.root.get(_get_element_nsuri_name(ps.body_root)) or \
self.soapAction.get(action)
if method is None:
raise UnknownRequestException, \
'failed to map request to a method: action(%s), root%s' %(action,_get_element_nsuri_name(ps.body_root))
return method
class ServiceSOAPBinding(ServiceInterface):
'''Binding defines the set of wsdl:binding operations, it takes as input a
ParsedSoap instance and parses it into a pyobj. It returns a response pyobj.
'''
def __init__(self, post):
ServiceInterface.__init__(self, post)
def __call___(self, action, ps):
return self.getOperation(ps, action)(ps)
class WSAResource(ServiceSOAPBinding):
'''Simple WSRF service, performs method resolutions based
on WS-Action values rather than SOAP Action.
class variables:
encoding
wsAction -- Must override to set output Action values.
soapAction -- Must override to set input Action values.
'''
encoding = "UTF-8"
def __init__(self, post):
'''
post -- POST value
'''
assert isinstance(self.soapAction, dict), "soapAction must be a dict"
assert isinstance(self.wsAction, dict), "wsAction must be a dict"
ServiceSOAPBinding.__init__(self, post)
def __call___(self, action, ps, address):
return self.getOperation(ps, action)(ps, address)
def getServiceURL(self):
return self._url
def setServiceURL(self, url):
self._url = url
def getOperation(self, ps, address):
'''Returns a method of class.
address -- ws-address
'''
action = address.getAction()
opName = self.getOperationName(ps, action)
return getattr(self, opName)
def getResponseAction(self, ps, action):
'''Returns response WS-Action if available
action -- request WS-Action value.
'''
opName = self.getOperationName(ps, action)
if self.wsAction.has_key(opName) is False:
raise WSActionNotSpecified, 'wsAction dictionary missing key(%s)' %opName
return self.wsAction[opName]
def do_POST(self):
'''The POST command. This is called by HTTPServer, not twisted.
action -- SOAPAction(HTTP header) or wsa:Action(SOAP:Header)
'''
global _contexts
soapAction = self.headers.getheader('SOAPAction')
post = self.path
if not post:
raise PostNotSpecified, 'HTTP POST not specified in request'
if soapAction:
soapAction = soapAction.strip('\'"')
post = post.strip('\'"')
try:
ct = self.headers['content-type']
if ct.startswith('multipart/'):
cid = resolvers.MIMEResolver(ct, self.rfile)
xml = cid.GetSOAPPart()
ps = ParsedSoap(xml, resolver=cid.Resolve, readerclass=DomletteReader)
else:
length = int(self.headers['content-length'])
ps = ParsedSoap(self.rfile.read(length), readerclass=DomletteReader)
except ParseException, e:
self.send_fault(FaultFromZSIException(e))
except Exception, e:
# Faulted while processing; assume it's in the header.
self.send_fault(FaultFromException(e, 1, sys.exc_info()[2]))
else:
# Keep track of calls
thread_id = thread.get_ident()
_contexts[thread_id] = SOAPContext(self.server, xml, ps,
self.connection,
self.headers, soapAction)
try:
_Dispatch(ps, self.server, self.send_xml, self.send_fault,
post=post, action=soapAction)
except Exception, e:
self.send_fault(FaultFromException(e, 0, sys.exc_info()[2]))
# Clean up after the call
if _contexts.has_key(thread_id):
del _contexts[thread_id]
class SOAPRequestHandler(BaseSOAPRequestHandler):
'''SOAP handler.
'''
def do_POST(self):
'''The POST command.
action -- SOAPAction(HTTP header) or wsa:Action(SOAP:Header)
'''
soapAction = self.headers.getheader('SOAPAction')
post = self.path
if not post:
raise PostNotSpecified, 'HTTP POST not specified in request'
if soapAction:
soapAction = soapAction.strip('\'"')
post = post.strip('\'"')
try:
ct = self.headers['content-type']
if ct.startswith('multipart/'):
cid = resolvers.MIMEResolver(ct, self.rfile)
xml = cid.GetSOAPPart()
ps = ParsedSoap(xml, resolver=cid.Resolve)
else:
length = int(self.headers['content-length'])
xml = self.rfile.read(length)
ps = ParsedSoap(xml)
except ParseException, e:
self.send_fault(FaultFromZSIException(e))
except Exception, e:
# Faulted while processing; assume it's in the header.
self.send_fault(FaultFromException(e, 1, sys.exc_info()[2]))
else:
# Keep track of calls
thread_id = thread.get_ident()
_contexts[thread_id] = SOAPContext(self.server, xml, ps,
self.connection,
self.headers, soapAction)
try:
_Dispatch(ps, self.server, self.send_xml, self.send_fault,
post=post, action=soapAction)
except Exception, e:
self.send_fault(FaultFromException(e, 0, sys.exc_info()[2]))
# Clean up after the call
if _contexts.has_key(thread_id):
del _contexts[thread_id]
def do_GET(self):
'''The GET command.
'''
if self.path.lower().endswith("?wsdl"):
service_path = self.path[:-5]
service = self.server.getNode(service_path)
if hasattr(service, "_wsdl"):
wsdl = service._wsdl
# update the soap:location tag in the wsdl to the actual server
# location
# - default to 'http' as protocol, or use server-specified protocol
proto = 'http'
if hasattr(self.server,'proto'):
proto = self.server.proto
serviceUrl = '%s://%s:%d%s' % (proto,
self.server.server_name,
self.server.server_port,
service_path)
soapAddress = '' % serviceUrl
wsdlre = re.compile('\]*>',re.IGNORECASE)
wsdl = re.sub(wsdlre,soapAddress,wsdl)
self.send_xml(wsdl)
else:
self.send_error(404, "WSDL not available for that service [%s]." % self.path)
else:
self.send_error(404, "Service not found [%s]." % self.path)
class ServiceContainer(HTTPServer):
'''HTTPServer that stores service instances according
to POST values. An action value is instance specific,
and specifies an operation (function) of an instance.
'''
class NodeTree:
'''Simple dictionary implementation of a node tree
'''
def __init__(self):
self.__dict = {}
def __str__(self):
return str(self.__dict)
def listNodes(self):
print self.__dict.keys()
def getNode(self, url):
path = urlparse.urlsplit(url)[2]
if path.startswith("/"):
path = path[1:]
if self.__dict.has_key(path):
return self.__dict[path]
else:
raise NoSuchService, 'No service(%s) in ServiceContainer' %path
def setNode(self, service, url):
path = urlparse.urlsplit(url)[2]
if path.startswith("/"):
path = path[1:]
if not isinstance(service, ServiceSOAPBinding):
raise TypeError, 'A Service must implement class ServiceSOAPBinding'
if self.__dict.has_key(path):
raise ServiceAlreadyPresent, 'Service(%s) already in ServiceContainer' % path
else:
self.__dict[path] = service
def removeNode(self, url):
path = urlparse.urlsplit(url)[2]
if path.startswith("/"):
path = path[1:]
if self.__dict.has_key(path):
node = self.__dict[path]
del self.__dict[path]
return node
else:
raise NoSuchService, 'No service(%s) in ServiceContainer' %path
def __init__(self, server_address, services=[], RequestHandlerClass=SOAPRequestHandler):
'''server_address --
RequestHandlerClass --
'''
HTTPServer.__init__(self, server_address, RequestHandlerClass)
self._nodes = self.NodeTree()
map(lambda s: self.setNode(s), services)
def __str__(self):
return '%s(%s) nodes( %s )' %(self.__class__, _get_idstr(self), str(self._nodes))
def __call__(self, ps, post, action, address=None):
'''ps -- ParsedSoap representing the request
post -- HTTP POST --> instance
action -- Soap Action header --> method
address -- Address instance representing WS-Address
'''
method = self.getCallBack(ps, post, action)
if (isinstance(method.im_self, WSAResource) or
isinstance(method.im_self, SimpleWSResource)):
return method(ps, address)
return method(ps)
def setNode(self, service, url=None):
if url is None:
url = service.getPost()
self._nodes.setNode(service, url)
def getNode(self, url):
return self._nodes.getNode(url)
def removeNode(self, url):
self._nodes.removeNode(url)
class SimpleWSResource(ServiceSOAPBinding):
def getNode(self, post):
'''post -- POST HTTP value
'''
return self._nodes.getNode(post)
def setNode(self, service, post):
'''service -- service instance
post -- POST HTTP value
'''
self._nodes.setNode(service, post)
def getCallBack(self, ps, post, action):
'''post -- POST HTTP value
action -- SOAP Action value
'''
node = self.getNode(post)
if node is None:
raise NoSuchFunction
if node.authorize(None, post, action):
return node.getOperation(ps, action)
else:
raise NotAuthorized, "Authorization failed for method %s" % action
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/resolvers.py 0000644 0001751 0001751 00000011223 07466521042 013566 0 ustar zsi zsi #! /usr/bin/env python
# $Header$
'''SOAP messaging parsing.
'''
from ZSI import _copyright, _child_elements, EvaluateException, TC
import multifile, mimetools, urllib
from base64 import decodestring as b64decode
import cStringIO as StringIO
def Opaque(uri, tc, ps, **keywords):
'''Resolve a URI and return its content as a string.
'''
source = urllib.urlopen(uri, **keywords)
enc = source.info().getencoding()
if enc in ['7bit', '8bit', 'binary']: return source.read()
data = StringIO.StringIO()
mimetools.decode(source, data, enc)
return data.getvalue()
def XML(uri, tc, ps, **keywords):
'''Resolve a URI and return its content as an XML DOM.
'''
source = urllib.urlopen(uri, **keywords)
enc = source.info().getencoding()
if enc in ['7bit', '8bit', 'binary']:
data = source
else:
data = StringIO.StringIO()
mimetools.decode(source, data, enc)
data.seek(0)
dom = ps.readerclass().fromStream(data)
return _child_elements(dom)[0]
class NetworkResolver:
'''A resolver that support string and XML.
'''
def __init__(self, prefix=None):
self.allowed = prefix or []
def _check_allowed(self, uri):
for a in self.allowed:
if uri.startswith(a): return
raise EvaluateException("Disallowed URI prefix")
def Opaque(self, uri, tc, ps, **keywords):
self._check_allowed(uri)
return Opaque(uri, tc, ps, **keywords)
def XML(self, uri, tc, ps, **keywords):
self._check_allowed(uri)
return XML(uri, tc, ps, **keywords)
def Resolve(self, uri, tc, ps, **keywords):
if isinstance(tc, TC.XML):
return XML(uri, tc, ps, **keywords)
return Opaque(uri, tc, ps, **keywords)
class MIMEResolver:
'''Multi-part MIME resolver -- SOAP With Attachments, mostly.
'''
def __init__(self, ct, f, next=None, uribase='thismessage:/',
seekable=0, **kw):
# Get the boundary. It's too bad I have to write this myself,
# but no way am I going to import cgi for 10 lines of code!
for param in ct.split(';'):
a = param.strip()
if a.startswith('boundary='):
if a[9] in [ '"', "'" ]:
boundary = a[10:-1]
else:
boundary = a[9:]
break
else:
raise ValueError('boundary parameter not found')
self.id_dict, self.loc_dict, self.parts = {}, {}, []
self.next = next
self.base = uribase
mf = multifile.MultiFile(f, seekable)
mf.push(boundary)
while mf.next():
head = mimetools.Message(mf)
body = StringIO.StringIO()
mimetools.decode(mf, body, head.getencoding())
body.seek(0)
part = (head, body)
self.parts.append(part)
key = head.get('content-id')
if key:
if key[0] == '<' and key[-1] == '>': key = key[1:-1]
self.id_dict[key] = part
key = head.get('content-location')
if key: self.loc_dict[key] = part
mf.pop()
def GetSOAPPart(self):
'''Get the SOAP body part.
'''
head, part = self.parts[0]
return StringIO.StringIO(part.getvalue())
def get(self, uri):
'''Get the content for the bodypart identified by the uri.
'''
if uri.startswith('cid:'):
# Content-ID, so raise exception if not found.
head, part = self.id_dict[uri[4:]]
return StringIO.StringIO(part.getvalue())
if self.loc_dict.has_key(uri):
head, part = self.loc_dict[uri]
return StringIO.StringIO(part.getvalue())
return None
def Opaque(self, uri, tc, ps, **keywords):
content = self.get(uri)
if content: return content.getvalue()
if not self.next: raise EvaluateException("Unresolvable URI " + uri)
return self.next.Opaque(uri, tc, ps, **keywords)
def XML(self, uri, tc, ps, **keywords):
content = self.get(uri)
if content:
dom = ps.readerclass().fromStream(content)
return _child_elements(dom)[0]
if not self.next: raise EvaluateException("Unresolvable URI " + uri)
return self.next.XML(uri, tc, ps, **keywords)
def Resolve(self, uri, tc, ps, **keywords):
if isinstance(tc, TC.XML):
return self.XML(uri, tc, ps, **keywords)
return self.Opaque(uri, tc, ps, **keywords)
def __getitem__(self, cid):
head, body = self.id_dict[cid]
newio = StringIO.StringIO(body.getvalue())
return newio
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/client.py 0000755 0001751 0001751 00000052526 10641306321 013024 0 ustar zsi zsi #! /usr/bin/env python
# $Header$
#
# Copyright (c) 2001 Zolera Systems. All rights reserved.
from ZSI import _copyright, _seqtypes, ParsedSoap, SoapWriter, TC, ZSI_SCHEMA_URI,\
EvaluateException, FaultFromFaultMessage, _child_elements, _attrs, _find_arraytype,\
_find_type, _get_idstr, _get_postvalue_from_absoluteURI, FaultException, WSActionException,\
UNICODE_ENCODING
from ZSI.auth import AUTH
from ZSI.TC import AnyElement, AnyType, String, TypeCode, _get_global_element_declaration,\
_get_type_definition
from ZSI.TCcompound import Struct
import base64, httplib, Cookie, types, time, urlparse
from ZSI.address import Address
from ZSI.wstools.logging import getLogger as _GetLogger
_b64_encode = base64.encodestring
class _AuthHeader:
"""%s%s
"""
def __init__(self, name=None, password=None):
self.Name = name
self.Password = password
_AuthHeader.typecode = Struct(_AuthHeader, ofwhat=(String((ZSI_SCHEMA_URI,'Name'), typed=False),
String((ZSI_SCHEMA_URI,'Password'), typed=False)), pname=(ZSI_SCHEMA_URI,'BasicAuth'),
typed=False)
class _Caller:
'''Internal class used to give the user a callable object
that calls back to the Binding object to make an RPC call.
'''
def __init__(self, binding, name, namespace=None):
self.binding = binding
self.name = name
self.namespace = namespace
def __call__(self, *args):
nsuri = self.namespace
if nsuri is None:
return self.binding.RPC(None, self.name, args,
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
replytype=TC.Any(self.name+"Response"))
return self.binding.RPC(None, (nsuri,self.name), args,
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
replytype=TC.Any((nsuri,self.name+"Response")))
class _NamedParamCaller:
'''Similar to _Caller, expect that there are named parameters
not positional.
'''
def __init__(self, binding, name, namespace=None):
self.binding = binding
self.name = name
self.namespace = namespace
def __call__(self, **params):
# Pull out arguments that Send() uses
kw = {}
for key in [ 'auth_header', 'nsdict', 'requesttypecode', 'soapaction' ]:
if params.has_key(key):
kw[key] = params[key]
del params[key]
nsuri = self.namespace
if nsuri is None:
return self.binding.RPC(None, self.name, None,
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
_args=params,
replytype=TC.Any(self.name+"Response", aslist=False),
**kw)
return self.binding.RPC(None, (nsuri,self.name), None,
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
_args=params,
replytype=TC.Any((nsuri,self.name+"Response"), aslist=False),
**kw)
class _Binding:
'''Object that represents a binding (connection) to a SOAP server.
Once the binding is created, various ways of sending and
receiving SOAP messages are available.
'''
defaultHttpTransport = httplib.HTTPConnection
defaultHttpsTransport = httplib.HTTPSConnection
logger = _GetLogger('ZSI.client.Binding')
def __init__(self, nsdict=None, transport=None, url=None, tracefile=None,
readerclass=None, writerclass=None, soapaction='',
wsAddressURI=None, sig_handler=None, transdict=None, **kw):
'''Initialize.
Keyword arguments include:
transport -- default use HTTPConnection.
transdict -- dict of values to pass to transport.
url -- URL of resource, POST is path
soapaction -- value of SOAPAction header
auth -- (type, name, password) triplet; default is unauth
nsdict -- namespace entries to add
tracefile -- file to dump packet traces
cert_file, key_file -- SSL data (q.v.)
readerclass -- DOM reader class
writerclass -- DOM writer class, implements MessageInterface
wsAddressURI -- namespaceURI of WS-Address to use. By default
it's not used.
sig_handler -- XML Signature handler, must sign and verify.
endPointReference -- optional Endpoint Reference.
'''
self.data = None
self.ps = None
self.user_headers = []
self.nsdict = nsdict or {}
self.transport = transport
self.transdict = transdict or {}
self.url = url
self.trace = tracefile
self.readerclass = readerclass
self.writerclass = writerclass
self.soapaction = soapaction
self.wsAddressURI = wsAddressURI
self.sig_handler = sig_handler
self.address = None
self.endPointReference = kw.get('endPointReference', None)
self.cookies = Cookie.SimpleCookie()
self.http_callbacks = {}
if kw.has_key('auth'):
self.SetAuth(*kw['auth'])
else:
self.SetAuth(AUTH.none)
def SetAuth(self, style, user=None, password=None):
'''Change auth style, return object to user.
'''
self.auth_style, self.auth_user, self.auth_pass = \
style, user, password
return self
def SetURL(self, url):
'''Set the URL we post to.
'''
self.url = url
return self
def ResetHeaders(self):
'''Empty the list of additional headers.
'''
self.user_headers = []
return self
def ResetCookies(self):
'''Empty the list of cookies.
'''
self.cookies = Cookie.SimpleCookie()
def AddHeader(self, header, value):
'''Add a header to send.
'''
self.user_headers.append((header, value))
return self
def __addcookies(self):
'''Add cookies from self.cookies to request in self.h
'''
for cname, morsel in self.cookies.items():
attrs = []
value = morsel.get('version', '')
if value != '' and value != '0':
attrs.append('$Version=%s' % value)
attrs.append('%s=%s' % (cname, morsel.coded_value))
value = morsel.get('path')
if value:
attrs.append('$Path=%s' % value)
value = morsel.get('domain')
if value:
attrs.append('$Domain=%s' % value)
self.h.putheader('Cookie', "; ".join(attrs))
def RPC(self, url, opname, obj, replytype=None, **kw):
'''Send a request, return the reply. See Send() and Recieve()
docstrings for details.
'''
self.Send(url, opname, obj, **kw)
return self.Receive(replytype, **kw)
def Send(self, url, opname, obj, nsdict={}, soapaction=None, wsaction=None,
endPointReference=None, soapheaders=(), **kw):
'''Send a message. If url is None, use the value from the
constructor (else error). obj is the object (data) to send.
Data may be described with a requesttypecode keyword, the default
is the class's typecode (if there is one), else Any.
Try to serialize as a Struct, if this is not possible serialize an Array. If
data is a sequence of built-in python data types, it will be serialized as an
Array, unless requesttypecode is specified.
arguments:
url --
opname -- struct wrapper
obj -- python instance
key word arguments:
nsdict --
soapaction --
wsaction -- WS-Address Action, goes in SOAP Header.
endPointReference -- set by calling party, must be an
EndPointReference type instance.
soapheaders -- list of pyobj, typically w/typecode attribute.
serialized in the SOAP:Header.
requesttypecode --
'''
url = url or self.url
endPointReference = endPointReference or self.endPointReference
# Serialize the object.
d = {}
d.update(self.nsdict)
d.update(nsdict)
sw = SoapWriter(nsdict=d, header=True, outputclass=self.writerclass,
encodingStyle=kw.get('encodingStyle'),)
requesttypecode = kw.get('requesttypecode')
if kw.has_key('_args'): #NamedParamBinding
tc = requesttypecode or TC.Any(pname=opname, aslist=False)
sw.serialize(kw['_args'], tc)
elif not requesttypecode:
tc = getattr(obj, 'typecode', None) or TC.Any(pname=opname, aslist=False)
try:
if type(obj) in _seqtypes:
obj = dict(map(lambda i: (i.typecode.pname,i), obj))
except AttributeError:
# can't do anything but serialize this in a SOAP:Array
tc = TC.Any(pname=opname, aslist=True)
else:
tc = TC.Any(pname=opname, aslist=False)
sw.serialize(obj, tc)
else:
sw.serialize(obj, requesttypecode)
for i in soapheaders:
sw.serialize_header(i)
#
# Determine the SOAP auth element. SOAP:Header element
if self.auth_style & AUTH.zsibasic:
sw.serialize_header(_AuthHeader(self.auth_user, self.auth_pass),
_AuthHeader.typecode)
#
# Serialize WS-Address
if self.wsAddressURI is not None:
if self.soapaction and wsaction.strip('\'"') != self.soapaction:
raise WSActionException, 'soapAction(%s) and WS-Action(%s) must match'\
%(self.soapaction,wsaction)
self.address = Address(url, self.wsAddressURI)
self.address.setRequest(endPointReference, wsaction)
self.address.serialize(sw)
#
# WS-Security Signature Handler
if self.sig_handler is not None:
self.sig_handler.sign(sw)
scheme,netloc,path,nil,nil,nil = urlparse.urlparse(url)
transport = self.transport
if transport is None and url is not None:
if scheme == 'https':
transport = self.defaultHttpsTransport
elif scheme == 'http':
transport = self.defaultHttpTransport
else:
raise RuntimeError, 'must specify transport or url startswith https/http'
# Send the request.
if issubclass(transport, httplib.HTTPConnection) is False:
raise TypeError, 'transport must be a HTTPConnection'
soapdata = str(sw)
self.h = transport(netloc, None, **self.transdict)
self.h.connect()
self.SendSOAPData(soapdata, url, soapaction, **kw)
def SendSOAPData(self, soapdata, url, soapaction, headers={}, **kw):
# Tracing?
if self.trace:
print >>self.trace, "_" * 33, time.ctime(time.time()), "REQUEST:"
print >>self.trace, soapdata
url = url or self.url
request_uri = _get_postvalue_from_absoluteURI(url)
self.h.putrequest("POST", request_uri)
self.h.putheader("Content-Length", "%d" % len(soapdata))
self.h.putheader("Content-Type", 'text/xml; charset="%s"' %UNICODE_ENCODING)
self.__addcookies()
for header,value in headers.items():
self.h.putheader(header, value)
SOAPActionValue = '"%s"' % (soapaction or self.soapaction)
self.h.putheader("SOAPAction", SOAPActionValue)
if self.auth_style & AUTH.httpbasic:
val = _b64_encode(self.auth_user + ':' + self.auth_pass) \
.replace("\012", "")
self.h.putheader('Authorization', 'Basic ' + val)
elif self.auth_style == AUTH.httpdigest and not headers.has_key('Authorization') \
and not headers.has_key('Expect'):
def digest_auth_cb(response):
self.SendSOAPDataHTTPDigestAuth(response, soapdata, url, request_uri, soapaction, **kw)
self.http_callbacks[401] = None
self.http_callbacks[401] = digest_auth_cb
for header,value in self.user_headers:
self.h.putheader(header, value)
self.h.endheaders()
self.h.send(soapdata)
# Clear prior receive state.
self.data, self.ps = None, None
def SendSOAPDataHTTPDigestAuth(self, response, soapdata, url, request_uri, soapaction, **kw):
'''Resend the initial request w/http digest authorization headers.
The SOAP server has requested authorization. Fetch the challenge,
generate the authdict for building a response.
'''
if self.trace:
print >>self.trace, "------ Digest Auth Header"
url = url or self.url
if response.status != 401:
raise RuntimeError, 'Expecting HTTP 401 response.'
if self.auth_style != AUTH.httpdigest:
raise RuntimeError,\
'Auth style(%d) does not support requested digest authorization.' %self.auth_style
from ZSI.digest_auth import fetch_challenge,\
generate_response,\
build_authorization_arg,\
dict_fetch
chaldict = fetch_challenge( response.getheader('www-authenticate') )
if dict_fetch(chaldict,'challenge','').lower() == 'digest' and \
dict_fetch(chaldict,'nonce',None) and \
dict_fetch(chaldict,'realm',None) and \
dict_fetch(chaldict,'qop',None):
authdict = generate_response(chaldict,
request_uri, self.auth_user, self.auth_pass, method='POST')
headers = {\
'Authorization':build_authorization_arg(authdict),
'Expect':'100-continue',
}
self.SendSOAPData(soapdata, url, soapaction, headers, **kw)
return
raise RuntimeError,\
'Client expecting digest authorization challenge.'
def ReceiveRaw(self, **kw):
'''Read a server reply, unconverted to any format and return it.
'''
if self.data: return self.data
trace = self.trace
while 1:
response = self.h.getresponse()
self.reply_code, self.reply_msg, self.reply_headers, self.data = \
response.status, response.reason, response.msg, response.read()
if trace:
print >>trace, "_" * 33, time.ctime(time.time()), "RESPONSE:"
for i in (self.reply_code, self.reply_msg,):
print >>trace, str(i)
print >>trace, "-------"
print >>trace, str(self.reply_headers)
print >>trace, self.data
saved = None
for d in response.msg.getallmatchingheaders('set-cookie'):
if d[0] in [ ' ', '\t' ]:
saved += d.strip()
else:
if saved: self.cookies.load(saved)
saved = d.strip()
if saved: self.cookies.load(saved)
if response.status == 401:
if not callable(self.http_callbacks.get(response.status,None)):
raise RuntimeError, 'HTTP Digest Authorization Failed'
self.http_callbacks[response.status](response)
continue
if response.status != 100: break
# The httplib doesn't understand the HTTP continuation header.
# Horrible internals hack to patch things up.
self.h._HTTPConnection__state = httplib._CS_REQ_SENT
self.h._HTTPConnection__response = None
return self.data
def IsSOAP(self):
if self.ps: return 1
self.ReceiveRaw()
mimetype = self.reply_headers.type
return mimetype == 'text/xml'
def ReceiveSOAP(self, readerclass=None, **kw):
'''Get back a SOAP message.
'''
if self.ps: return self.ps
if not self.IsSOAP():
raise TypeError(
'Response is "%s", not "text/xml"' % self.reply_headers.type)
if len(self.data) == 0:
raise TypeError('Received empty response')
self.ps = ParsedSoap(self.data,
readerclass=readerclass or self.readerclass,
encodingStyle=kw.get('encodingStyle'))
if self.sig_handler is not None:
self.sig_handler.verify(self.ps)
return self.ps
def IsAFault(self):
'''Get a SOAP message, see if it has a fault.
'''
self.ReceiveSOAP()
return self.ps.IsAFault()
def ReceiveFault(self, **kw):
'''Parse incoming message as a fault. Raise TypeError if no
fault found.
'''
self.ReceiveSOAP(**kw)
if not self.ps.IsAFault():
raise TypeError("Expected SOAP Fault not found")
return FaultFromFaultMessage(self.ps)
def Receive(self, replytype, **kw):
'''Parse message, create Python object.
KeyWord data:
faults -- list of WSDL operation.fault typecodes
wsaction -- If using WS-Address, must specify Action value we expect to
receive.
'''
self.ReceiveSOAP(**kw)
if self.ps.IsAFault():
msg = FaultFromFaultMessage(self.ps)
raise FaultException(msg)
tc = replytype
if hasattr(replytype, 'typecode'):
tc = replytype.typecode
reply = self.ps.Parse(tc)
if self.address is not None:
self.address.checkResponse(self.ps, kw.get('wsaction'))
return reply
def __repr__(self):
return "<%s instance %s>" % (self.__class__.__name__, _get_idstr(self))
class Binding(_Binding):
'''Object that represents a binding (connection) to a SOAP server.
Can be used in the "name overloading" style.
class attr:
gettypecode -- funcion that returns typecode from typesmodule,
can be set so can use whatever mapping you desire.
'''
gettypecode = staticmethod(lambda mod,e: getattr(mod, str(e.localName)).typecode)
logger = _GetLogger('ZSI.client.Binding')
def __init__(self, url, namespace=None, typesmodule=None, **kw):
"""
Parameters:
url -- location of service
namespace -- optional root element namespace
typesmodule -- optional response only. dict(name=typecode),
lookup for all children of root element.
"""
self.typesmodule = typesmodule
self.namespace = namespace
_Binding.__init__(self, url=url, **kw)
def __getattr__(self, name):
'''Return a callable object that will invoke the RPC method
named by the attribute.
'''
if name[:2] == '__' and len(name) > 5 and name[-2:] == '__':
if hasattr(self, name): return getattr(self, name)
return getattr(self.__class__, name)
return _Caller(self, name, self.namespace)
def __parse_child(self, node):
'''for rpc-style map each message part to a class in typesmodule
'''
try:
tc = self.gettypecode(self.typesmodule, node)
except:
self.logger.debug('didnt find typecode for "%s" in typesmodule: %s',
node.localName, self.typesmodule)
tc = TC.Any(aslist=1)
return tc.parse(node, self.ps)
self.logger.debug('parse child with typecode : %s', tc)
try:
return tc.parse(node, self.ps)
except Exception:
self.logger.debug('parse failed try Any : %s', tc)
tc = TC.Any(aslist=1)
return tc.parse(node, self.ps)
def Receive(self, replytype, **kw):
'''Parse message, create Python object.
KeyWord data:
faults -- list of WSDL operation.fault typecodes
wsaction -- If using WS-Address, must specify Action value we expect to
receive.
'''
self.ReceiveSOAP(**kw)
ps = self.ps
tp = _find_type(ps.body_root)
isarray = ((type(tp) in (tuple,list) and tp[1] == 'Array') or _find_arraytype(ps.body_root))
if self.typesmodule is None or isarray:
return _Binding.Receive(self, replytype, **kw)
if ps.IsAFault():
msg = FaultFromFaultMessage(ps)
raise FaultException(msg)
tc = replytype
if hasattr(replytype, 'typecode'):
tc = replytype.typecode
#Ignore response wrapper
reply = {}
for elt in _child_elements(ps.body_root):
name = str(elt.localName)
reply[name] = self.__parse_child(elt)
if self.address is not None:
self.address.checkResponse(ps, kw.get('wsaction'))
return reply
class NamedParamBinding(Binding):
'''Like Binding, except the argument list for invocation is
named parameters.
'''
logger = _GetLogger('ZSI.client.Binding')
def __getattr__(self, name):
'''Return a callable object that will invoke the RPC method
named by the attribute.
'''
if name[:2] == '__' and len(name) > 5 and name[-2:] == '__':
if hasattr(self, name): return getattr(self, name)
return getattr(self.__class__, name)
return _NamedParamCaller(self, name, self.namespace)
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/address.py 0000644 0001751 0001751 00000021606 10712164103 013162 0 ustar zsi zsi ############################################################################
# Joshua R. Boverhof, LBNL
# See Copyright for copyright notice!
###########################################################################
import time, urlparse, socket
from ZSI import _seqtypes, EvaluateException, WSActionException
from TC import AnyElement, AnyType, TypeCode
from schema import GED, GTD, _has_type_definition
from ZSI.TCcompound import ComplexType
from ZSI.wstools.Namespaces import WSA_LIST
class Address(object):
'''WS-Address
Implemented is dependent on the default "wsdl2py" convention of generating aname,
so the attributes representing element declaration names should be prefixed with
an underscore.
'''
def __init__(self, addressTo=None, wsAddressURI=None, action=None):
self.wsAddressURI = wsAddressURI
self.anonymousURI = None
self._addressTo = addressTo
self._messageID = None
self._action = action
self._endPointReference = None
self._replyTo = None
self._relatesTo = None
self.setUp()
def setUp(self):
'''Look for WS-Address
'''
toplist = filter(lambda wsa: wsa.ADDRESS==self.wsAddressURI, WSA_LIST)
epr = 'EndpointReferenceType'
for WSA in toplist+WSA_LIST:
if (self.wsAddressURI is not None and self.wsAddressURI != WSA.ADDRESS) or \
_has_type_definition(WSA.ADDRESS, epr) is True:
break
else:
raise EvaluateException,\
'enabling wsAddressing requires the inclusion of that namespace'
self.wsAddressURI = WSA.ADDRESS
self.anonymousURI = WSA.ANONYMOUS
self._replyTo = WSA.ANONYMOUS
def _checkAction(self, action, value):
'''WS-Address Action
action -- Action value expecting.
value -- Action value server returned.
'''
if action is None:
raise WSActionException, 'Response missing WSAddress Action'
if not value:
raise WSActionException, 'missing WSAddress Action, expecting %s' %action
if value != action:
raise WSActionException, 'wrong WSAddress Action(%s), expecting %s'%(value,action)
def _checkFrom(self, pyobj):
'''WS-Address From,
XXX currently not checking the hostname, not forwarding messages.
pyobj -- From server returned.
'''
if pyobj is None: return
value = pyobj._Address
if value != self._addressTo:
scheme,netloc,path,query,fragment = urlparse.urlsplit(value)
hostport = netloc.split(':')
schemeF,netlocF,pathF,queryF,fragmentF = urlparse.urlsplit(self._addressTo)
if scheme==schemeF and path==pathF and query==queryF and fragment==fragmentF:
netloc = netloc.split(':') + ['80']
netlocF = netlocF.split(':') + ['80']
if netloc[1]==netlocF[1] and (socket.gethostbyname(netlocF[0]) in
('127.0.0.1', socket.gethostbyname(netloc[0]))):
return
raise WSActionException, 'wrong WS-Address From(%s), expecting %s'%(value,self._addressTo)
def _checkRelatesTo(self, value):
'''WS-Address From
value -- From server returned.
'''
if value != self._messageID:
raise WSActionException, 'wrong WS-Address RelatesTo(%s), expecting %s'%(value,self._messageID)
def _checkReplyTo(self, value):
'''WS-Address From
value -- From server returned in wsa:To
'''
if value != self._replyTo:
raise WSActionException, 'wrong WS-Address ReplyTo(%s), expecting %s'%(value,self._replyTo)
def setAction(self, action):
self._action = action
def getAction(self):
return self._action
def getRelatesTo(self):
return self._relatesTo
def getMessageID(self):
return self._messageID
def _getWSAddressTypeCodes(self, **kw):
'''kw -- namespaceURI keys with sequence of element names.
'''
typecodes = []
try:
for nsuri,elements in kw.items():
for el in elements:
typecode = GED(nsuri, el)
if typecode is None:
raise WSActionException, 'Missing namespace, import "%s"' %nsuri
typecodes.append(typecode)
else:
pass
except EvaluateException, ex:
raise EvaluateException, \
'To use ws-addressing register typecodes for namespace(%s)' %self.wsAddressURI
return typecodes
def checkResponse(self, ps, action):
'''
ps -- ParsedSoap
action -- ws-action for response
'''
namespaceURI = self.wsAddressURI
d = {namespaceURI:("MessageID","Action","To","From","RelatesTo")}
typecodes = self._getWSAddressTypeCodes(**d)
pyobjs = ps.ParseHeaderElements(typecodes)
got_action = pyobjs.get((namespaceURI,"Action"))
self._checkAction(action, got_action)
From = pyobjs.get((namespaceURI,"From"))
self._checkFrom(From)
RelatesTo = pyobjs.get((namespaceURI,"RelatesTo"))
self._checkRelatesTo(RelatesTo)
To = pyobjs.get((namespaceURI,"To"))
if To: self._checkReplyTo(To)
def setRequest(self, endPointReference, action):
'''Call For Request
'''
self._action = action
self.header_pyobjs = None
pyobjs = []
namespaceURI = self.wsAddressURI
addressTo = self._addressTo
messageID = self._messageID = "uuid:%s" %time.time()
# Set Message Information Headers
# MessageID
typecode = GED(namespaceURI, "MessageID")
pyobjs.append(typecode.pyclass(messageID))
# Action
typecode = GED(namespaceURI, "Action")
pyobjs.append(typecode.pyclass(action))
# To
typecode = GED(namespaceURI, "To")
pyobjs.append(typecode.pyclass(addressTo))
# From
typecode = GED(namespaceURI, "From")
mihFrom = typecode.pyclass()
mihFrom._Address = self.anonymousURI
pyobjs.append(mihFrom)
if endPointReference:
if hasattr(endPointReference, 'typecode') is False:
raise EvaluateException, 'endPointReference must have a typecode attribute'
if isinstance(endPointReference.typecode, \
GTD(namespaceURI ,'EndpointReferenceType')) is False:
raise EvaluateException, 'endPointReference must be of type %s' \
%GTD(namespaceURI ,'EndpointReferenceType')
ReferenceProperties = getattr(endPointReference, '_ReferenceProperties', None)
if ReferenceProperties is not None:
for v in getattr(ReferenceProperties, '_any', ()):
if not hasattr(v,'typecode'):
raise EvaluateException, ' element, instance missing typecode attribute'
pyobjs.append(v)
self.header_pyobjs = tuple(pyobjs)
def setResponseFromWSAddress(self, address, localURL):
'''Server-side has to set these fields in response.
address -- Address instance, representing a WS-Address
'''
self.From = localURL
self.header_pyobjs = None
pyobjs = []
namespaceURI = self.wsAddressURI
for nsuri,name,value in (\
(namespaceURI, "Action", self._action),
(namespaceURI, "MessageID","uuid:%s" %time.time()),
(namespaceURI, "RelatesTo", address.getMessageID()),
(namespaceURI, "To", self.anonymousURI),):
typecode = GED(nsuri, name)
pyobjs.append(typecode.pyclass(value))
typecode = GED(nsuri, "From")
pyobj = typecode.pyclass()
pyobj._Address = self.From
pyobjs.append(pyobj)
self.header_pyobjs = tuple(pyobjs)
def serialize(self, sw, **kw):
'''
sw -- SoapWriter instance, add WS-Address header.
'''
for pyobj in self.header_pyobjs:
if hasattr(pyobj, 'typecode') is False:
raise RuntimeError, 'all header pyobjs must have a typecode attribute'
sw.serialize_header(pyobj, **kw)
def parse(self, ps, **kw):
'''
ps -- ParsedSoap instance
'''
namespaceURI = self.wsAddressURI
elements = ("MessageID","Action","To","From","RelatesTo")
d = {namespaceURI:elements}
typecodes = self._getWSAddressTypeCodes(**d)
pyobjs = ps.ParseHeaderElements(typecodes)
self._messageID = pyobjs[(namespaceURI,elements[0])]
self._action = pyobjs[(namespaceURI,elements[1])]
self._addressTo = pyobjs[(namespaceURI,elements[2])]
self._from = pyobjs[(namespaceURI,elements[3])]
self._relatesTo = pyobjs[(namespaceURI,elements[4])]
if __name__ == '__main__': print _copyright
ZSI-2.1-a1/ZSI/LBNLCopyright 0000644 0001751 0001751 00000004524 07730117055 013540 0 ustar zsi zsi Copyright (c) 2003, The Regents of the University of California,
through Lawrence Berkeley National Laboratory (subject to receipt of
any required approvals from the U.S. Dept. of Energy). All rights
reserved. Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) 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.
(3) Neither the name of the University of California, Lawrence Berkeley
National Laboratory, U.S. Dept. of Energy 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 COPYRIGHT OWNER 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.
You are under no obligation whatsoever to provide any bug fixes,
patches, or upgrades to the features, functionality or performance of
the source code ("Enhancements") to anyone; however, if you choose to
make your Enhancements available either publicly, or directly to
Lawrence Berkeley National Laboratory, without imposing a separate
written license agreement for such Enhancements, then you hereby grant
the following license: a non-exclusive, royalty-free perpetual license
to install, use, modify, prepare derivative works, incorporate into
other computer software, distribute, and sublicense such Enhancements
or derivative works thereof, in binary and source code form.
ZSI-2.1-a1/ZSI/generate/ 0000755 0001751 0001751 00000000000 10712455110 012751 5 ustar zsi zsi ZSI-2.1-a1/ZSI/generate/containers.py 0000644 0001751 0001751 00000332655 10712156244 015514 0 ustar zsi zsi ############################################################################
# Monte M. Goode, LBNL
# See LBNLCopyright for copyright notice!
###########################################################################
# contains text container classes for new generation generator
# $Id: containers.py 1420 2007-10-31 19:51:00Z boverhof $
import types, warnings
from utility import StringWriter, TextProtect, TextProtectAttributeName,\
GetPartsSubNames
from utility import NamespaceAliasDict as NAD, NCName_to_ClassName as NC_to_CN
import ZSI
from ZSI.TC import _is_xsd_or_soap_ns
from ZSI.wstools import XMLSchema, WSDLTools
from ZSI.wstools.Namespaces import SCHEMA, SOAP, WSDL
from ZSI.wstools.logging import getLogger as _GetLogger
from ZSI.typeinterpreter import BaseTypeInterpreter
from ZSI.generate import WSISpec, WSInteropError, Wsdl2PythonError,\
WsdlGeneratorError, WSDLFormatError
ID1 = ' '
ID2 = 2*ID1
ID3 = 3*ID1
ID4 = 4*ID1
ID5 = 5*ID1
ID6 = 6*ID1
KW = {'ID1':ID1, 'ID2':ID2, 'ID3':ID3,'ID4':ID4, 'ID5':ID5, 'ID6':ID6,}
DEC = '_Dec'
DEF = '_Def'
"""
type_class_name -- function to return the name formatted as a type class.
element_class_name -- function to return the name formatted as an element class.
"""
type_class_name = lambda n: '%s%s' %(NC_to_CN(n), DEF)
element_class_name = lambda n: '%s%s' %(NC_to_CN(n), DEC)
def IsRPC(item):
"""item -- OperationBinding instance.
"""
if not isinstance(item, WSDLTools.OperationBinding):
raise TypeError, 'IsRPC takes 1 argument of type WSDLTools.OperationBinding'
soapbinding = item.getBinding().findBinding(WSDLTools.SoapBinding)
sob = item.findBinding(WSDLTools.SoapOperationBinding)
style = soapbinding.style
if sob is not None:
style = sob.style or soapbinding.style
return style == 'rpc'
def IsLiteral(item):
"""item -- MessageRoleBinding instance.
"""
if not isinstance(item, WSDLTools.MessageRoleBinding):
raise TypeError, 'IsLiteral takes 1 argument of type WSDLTools.MessageRoleBinding'
sbb = None
if item.type == 'input' or item.type == 'output':
sbb = item.findBinding(WSDLTools.SoapBodyBinding)
if sbb is None:
raise ValueError, 'Missing soap:body binding.'
return sbb.use == 'literal'
def SetTypeNameFunc(func):
global type_class_name
type_class_name = func
def SetElementNameFunc(func):
global element_class_name
element_class_name = func
def GetClassNameFromSchemaItem(item,do_extended=False):
'''
'''
assert isinstance(item, XMLSchema.XMLSchemaComponent), 'must be a schema item.'
alias = NAD.getAlias(item.getTargetNamespace())
if item.isDefinition() is True:
return '%s.%s' %(alias, NC_to_CN('%s' %type_class_name(item.getAttributeName())))
return None
def FromMessageGetSimpleElementDeclaration(message):
'''If message consists of one part with an element attribute,
and this element is a simpleType return a string representing
the python type, else return None.
'''
assert isinstance(message, WSDLTools.Message), 'expecting WSDLTools.Message'
if len(message.parts) == 1 and message.parts[0].element is not None:
part = message.parts[0]
nsuri,name = part.element
wsdl = message.getWSDL()
types = wsdl.types
if types.has_key(nsuri) and types[nsuri].elements.has_key(name):
e = types[nsuri].elements[name]
if isinstance(e, XMLSchema.ElementDeclaration) is True and e.getAttribute('type'):
typ = e.getAttribute('type')
bt = BaseTypeInterpreter()
ptype = bt.get_pythontype(typ[1], typ[0])
return ptype
return None
class AttributeMixIn:
'''for containers that can declare attributes.
Class Attributes:
attribute_typecode -- typecode attribute name typecode dict
built_in_refs -- attribute references that point to built-in
types. Skip resolving them into attribute declarations.
'''
attribute_typecode = 'self.attribute_typecode_dict'
built_in_refs = [(SOAP.ENC, 'arrayType'),]
def _setAttributes(self, attributes):
'''parameters
attributes -- a flat list of all attributes,
from this list all items in attribute_typecode_dict will
be generated into attrComponents.
returns a list of strings representing the attribute_typecode_dict.
'''
atd = self.attribute_typecode
atd_list = formatted_attribute_list = []
if not attributes:
return formatted_attribute_list
atd_list.append('# attribute handling code')
idx = 0
while(idx < len(attributes)):
a = attributes[idx]
idx += 1
if a.isWildCard() and a.isDeclaration():
atd_list.append(\
'%s[("%s","anyAttribute")] = ZSI.TC.AnyElement()'\
% (atd, SCHEMA.XSD3)
)
elif a.isDeclaration():
tdef = a.getTypeDefinition('type')
if tdef is not None:
tc = '%s.%s(None)' %(NAD.getAlias(tdef.getTargetNamespace()),
self.mangle(type_class_name(tdef.getAttributeName()))
)
else:
# built-in
t = a.getAttribute('type')
try:
tc = BTI.get_typeclass(t[1], t[0])
except:
# hand back a string by default.
tc = ZSI.TC.String
if tc is not None:
tc = '%s()' %tc
key = None
if a.getAttribute('form') == 'qualified':
key = '("%s","%s")' % ( a.getTargetNamespace(),
a.getAttribute('name') )
elif a.getAttribute('form') == 'unqualified':
key = '"%s"' % a.getAttribute('name')
else:
raise ContainerError, \
'attribute form must be un/qualified %s' \
% a.getAttribute('form')
atd_list.append(\
'%s[%s] = %s' % (atd, key, tc)
)
elif a.isReference() and a.isAttributeGroup():
# flatten 'em out....
for ga in a.getAttributeGroup().getAttributeContent():
attributes += (ga,)
elif a.isReference():
try:
ga = a.getAttributeDeclaration()
except XMLSchema.SchemaError:
key = a.getAttribute('ref')
self.logger.debug('No schema item for attribute ref (%s, %s)' %key)
if key in self.built_in_refs: continue
raise
tp = None
if ga is not None:
tp = ga.getTypeDefinition('type')
key = '("%s","%s")' %(ga.getTargetNamespace(),
ga.getAttribute('name'))
if ga is None:
# TODO: probably SOAPENC:arrayType
key = '("%s","%s")' %(
a.getAttribute('ref').getTargetNamespace(),
a.getAttribute('ref').getName())
atd_list.append(\
'%s[%s] = ZSI.TC.String()' %(atd, key)
)
elif tp is None:
# built in simple type
try:
namespace,typeName = ga.getAttribute('type')
except TypeError, ex:
# TODO: attribute declaration could be anonymous type
# hack in something to work
atd_list.append(\
'%s[%s] = ZSI.TC.String()' %(atd, key)
)
else:
atd_list.append(\
'%s[%s] = %s()' %(atd, key,
BTI.get_typeclass(typeName, namespace))
)
else:
typeName = tp.getAttribute('name')
namespace = tp.getTargetNamespace()
alias = NAD.getAlias(namespace)
key = '("%s","%s")' \
% (ga.getTargetNamespace(),ga.getAttribute('name'))
atd_list.append(\
'%s[%s] = %s.%s(None)' \
% (atd, key, alias, type_class_name(typeName))
)
else:
raise TypeError, 'expecting an attribute: %s' %a.getItemTrace()
return formatted_attribute_list
class ContainerError(Exception):
pass
class ContainerBase:
'''Base class for all Containers.
func_aname -- function that takes name, and returns aname.
'''
func_aname = staticmethod(TextProtectAttributeName)
logger = _GetLogger("ContainerBase")
def __init__(self):
self.content = StringWriter('\n')
self.__setup = False
self.ns = None
def __str__(self):
return self.getvalue()
# - string content methods
def mangle(self, s):
'''class/variable name illegalities
'''
return TextProtect(s)
def write(self, s):
self.content.write(s)
def writeArray(self, a):
self.content.write('\n'.join(a))
def _setContent(self):
'''override in subclasses. formats the content in the desired way.
'''
raise NotImplementedError, 'abstract method not implemented'
def getvalue(self):
if not self.__setup:
self._setContent()
self.__setup = True
return self.content.getvalue()
# - namespace utility methods
def getNSAlias(self):
if self.ns is not None:
return NAD.getAlias(self.ns)
raise ContainerError, 'no self.ns attr defined in %s' % self.__class__
def getNSModuleName(self):
if self.ns:
return NAD.getModuleName(self.ns)
raise ContainerError, 'no self.ns attr defined in %s' % self.__class__
def getAttributeName(self, name):
'''represents the aname
'''
if self.func_aname is None:
return name
assert callable(self.func_aname), \
'expecting callable method for attribute func_aname, not %s' %type(self.func_aname)
f = self.func_aname
return f(name)
# -- containers for services file components
class ServiceContainerBase(ContainerBase):
clientClassSuffix = "SOAP"
logger = _GetLogger("ServiceContainerBase")
class ServiceHeaderContainer(ServiceContainerBase):
imports = ['\nimport urlparse, types',
'from ZSI.TCcompound import ComplexType, Struct',
'from ZSI import client',
'from ZSI.schema import GED, GTD',
'import ZSI'
]
logger = _GetLogger("ServiceHeaderContainer")
def __init__(self, do_extended=False):
ServiceContainerBase.__init__(self)
self.basic = self.imports[:]
self.types = None
self.messages = None
self.extras = []
self.do_extended = do_extended
def setTypesModuleName(self, module):
self.types = module
def setMessagesModuleName(self, module):
self.messages = module
def appendImport(self, statement):
'''append additional import statement(s).
import_stament -- tuple or list or str
'''
if type(statement) in (list,tuple):
self.extras += statement
else:
self.extras.append(statement)
def _setContent(self):
if self.messages:
self.write('from %s import *' % self.messages)
if self.types:
self.write('from %s import *' % self.types)
imports = self.basic[:]
imports += self.extras
self.writeArray(imports)
class ServiceLocatorContainer(ServiceContainerBase):
logger = _GetLogger("ServiceLocatorContainer")
def __init__(self):
ServiceContainerBase.__init__(self)
self.serviceName = None
self.portInfo = []
self.locatorName = None
self.portMethods = []
def setUp(self, service):
assert isinstance(service, WSDLTools.Service), \
'expecting WDSLTools.Service instance.'
self.serviceName = service.name
for p in service.ports:
try:
ab = p.getAddressBinding()
except WSDLTools.WSDLError, ex:
self.logger.warning('Skip port(%s), missing address binding' %p.name)
continue
if isinstance(ab, WSDLTools.SoapAddressBinding) is False:
self.logger.warning('Skip port(%s), not a SOAP-1.1 address binding' %p.name)
continue
#info = (p.getBinding().getPortType().name, p.getBinding().name, ab.location)
self.portInfo.append( (NC_to_CN(p.name),
NC_to_CN(p.getBinding().name),
ab.location)
)
def getLocatorName(self):
'''return class name of generated locator.
'''
return self.locatorName
def getPortMethods(self):
'''list of get port accessor methods of generated locator class.
'''
return self.portMethods
def _setContent(self):
if not self.serviceName:
raise ContainerError, 'no service name defined!'
self.serviceName = self.mangle(self.serviceName)
self.locatorName = '%sLocator' %self.serviceName
locator = ['# Locator', 'class %s:' %self.locatorName, ]
self.portMethods = []
kwargs = KW.copy()
for port,bind,addr in self.portInfo:
# access method each port
method = 'get%s' %port
kwargs.update(dict(port=port, bind=bind, addr=addr,
service=self.serviceName, suffix=self.clientClassSuffix, method=method))
locator += [
'%(ID1)s%(port)s_address = "%(addr)s"' %kwargs,
'%(ID1)sdef get%(port)sAddress(self):' %kwargs,
'%(ID2)sreturn %(service)sLocator.%(port)s_address' %kwargs,
'%(ID1)sdef %(method)s(self, url=None, **kw):' %kwargs,
'%(ID2)sreturn %(bind)s%(suffix)s(url or %(service)sLocator.%(port)s_address, **kw)' %kwargs,
]
self.portMethods.append(method)
self.writeArray(locator)
class ServiceOperationContainer(ServiceContainerBase):
logger = _GetLogger("ServiceOperationContainer")
def __init__(self, useWSA=False, do_extended=False):
'''Parameters:
useWSA -- boolean, enable ws-addressing
do_extended -- boolean
'''
ServiceContainerBase.__init__(self)
self.useWSA = useWSA
self.do_extended = do_extended
def hasInput(self):
return self.inputName is not None
def hasOutput(self):
return self.outputName is not None
def isRPC(self):
return IsRPC(self.binding_operation)
def isLiteral(self, input=True):
msgrole = self.binding_operation.input
if input is False:
msgrole = self.binding_operation.output
return IsLiteral(msgrole)
def isSimpleType(self, input=True):
if input is False:
return self.outputSimpleType
return self.inputSimpleType
def getOperation(self):
return self.port.operations.get(self.name)
def getBOperation(self):
return self.port.get(self.name)
def getOperationName(self):
return self.name
def setUp(self, item):
'''
Parameters:
item -- WSDLTools BindingOperation instance.
'''
if not isinstance(item, WSDLTools.OperationBinding):
raise TypeError, 'Expecting WSDLTools Operation instance'
if not item.input:
raise WSDLFormatError('No in ' %(
item.getBinding().name, item.name))
self.name = None
self.port = None
self.soapaction = None
self.inputName = None
self.outputName = None
self.inputSimpleType = None
self.outputSimpleType = None
self.inputAction = None
self.outputAction = None
self.port = port = item.getBinding().getPortType()
self._wsdl = item.getWSDL()
self.name = name = item.name
self.binding_operation = bop = item
self.soap_input_headers = None
self.soap_output_headers = None
op = port.operations.get(name)
if op is None:
raise WSDLFormatError(
' no match for ' %(
port.name, item.getBinding().name, item.name))
soap_bop = bop.findBinding(WSDLTools.SoapOperationBinding)
if soap_bop is None:
raise SOAPBindingError, 'expecting SOAP Bindings'
self.soapaction = soap_bop.soapAction
sbody = bop.input.findBinding(WSDLTools.SoapBodyBinding)
if not sbody:
raise SOAPBindingError('Missing ' %(
port.binding.name, bop.name))
self.encodingStyle = None
if sbody.use == 'encoded':
assert sbody.encodingStyle == SOAP.ENC,\
'Supporting encodingStyle=%s, not %s'%(SOAP.ENC, sbody.encodingStyle)
self.encodingStyle = sbody.encodingStyle
self.inputName = op.getInputMessage().name
self.inputSimpleType = \
FromMessageGetSimpleElementDeclaration(op.getInputMessage())
self.inputAction = op.getInputAction()
self.soap_input_headers = bop.input.findBindings(WSDLTools.SoapHeaderBinding)
if bop.output is not None:
sbody = bop.output.findBinding(WSDLTools.SoapBodyBinding)
if not item.output:
raise WSDLFormatError, "Operation %s, no match for output binding" %name
self.outputName = op.getOutputMessage().name
self.outputSimpleType = \
FromMessageGetSimpleElementDeclaration(op.getOutputMessage())
self.outputAction = op.getOutputAction()
self.soap_output_headers = bop.output.findBindings(WSDLTools.SoapHeaderBinding)
def _setContent(self):
'''create string representation of operation.
'''
kwstring = 'kw = {}'
tCheck = 'if isinstance(request, %s) is False:' % self.inputName
bindArgs = ''
if self.encodingStyle is not None:
bindArgs = 'encodingStyle="%s", ' %self.encodingStyle
if self.useWSA:
wsactionIn = 'wsaction = "%s"' % self.inputAction
wsactionOut = 'wsaction = "%s"' % self.outputAction
bindArgs += 'wsaction=wsaction, endPointReference=self.endPointReference, '
responseArgs = ', wsaction=wsaction'
else:
wsactionIn = '# no input wsaction'
wsactionOut = '# no output wsaction'
responseArgs = ''
bindArgs += '**kw)'
if self.do_extended:
inputName = self.getOperation().getInputMessage().name
wrap_str = ""
partsList = self.getOperation().getInputMessage().parts.values()
try:
subNames = GetPartsSubNames(partsList, self._wsdl)
except TypeError, ex:
raise Wsdl2PythonError,\
"Extended generation failure: only supports doc/lit, "\
+"and all element attributes () must refer to single global "\
+"element declaration with complexType content. "\
+"\n\n**** TRY WITHOUT EXTENDED ****\n"
args = []
for pa in subNames:
args += pa
for arg in args:
wrap_str += "%srequest.%s = %s\n" % (ID2,
self.getAttributeName(arg),
self.mangle(arg))
#args = [pa.name for pa in self.getOperation().getInputMessage().parts.values()]
argsStr = ",".join(args)
if len(argsStr) > 1: # add inital comma if args exist
argsStr = ", " + argsStr
method = [
'%s# op: %s' % (ID1, self.getOperation().getInputMessage()),
'%sdef %s(self%s):' % (ID1, self.name, argsStr),
'\n%srequest = %s()' % (ID2, self.inputName),
'%s' % (wrap_str),
'%s%s' % (ID2, kwstring),
'%s%s' % (ID2, wsactionIn),
'%sself.binding.Send(None, None, request, soapaction="%s", %s'\
%(ID2, self.soapaction, bindArgs),
]
elif self.soap_input_headers:
method = [
'%s# op: %s' % (ID1, self.name),
'%sdef %s(self, request, soapheaders=(), **kw):' % (ID1, self.name),
'%s%s' % (ID2, tCheck),
'%sraise TypeError, "%%s incorrect request type" %% (%s)' %(ID3, 'request.__class__'),
'%s%s' % (ID2, wsactionIn),
'%s# TODO: Check soapheaders' % (ID2),
'%sself.binding.Send(None, None, request, soapaction="%s", soapheaders=soapheaders, %s'\
%(ID2, self.soapaction, bindArgs),
]
else:
method = [
'%s# op: %s' % (ID1, self.name),
'%sdef %s(self, request, **kw):' % (ID1, self.name),
'%s%s' % (ID2, tCheck),
'%sraise TypeError, "%%s incorrect request type" %% (%s)' %(ID3, 'request.__class__'),
'%s%s' % (ID2, wsactionIn),
'%sself.binding.Send(None, None, request, soapaction="%s", %s'\
%(ID2, self.soapaction, bindArgs),
]
#
# BP 1.0: rpc/literal
# WSDL 1.1 Section 3.5 could be interpreted to mean the RPC response
# wrapper element must be named identical to the name of the
# wsdl:operation.
# R2729
#
# SOAP-1.1 Note: rpc/encoded
# Each parameter accessor has a name corresponding to the name of the
# parameter and type corresponding to the type of the parameter. The name of
# the return value accessor is not significant. Likewise, the name of the struct is
# not significant. However, a convention is to name it after the method name
# with the string "Response" appended.
#
if not self.outputName:
method.append('%s#check for soap, assume soap:fault' %(ID2,))
method.append('%sif self.binding.IsSOAP(): self.binding.Receive(None, **kw)' % (ID2,))
self.writeArray(method)
return
response = ['%s%s' % (ID2, wsactionOut),]
if self.isRPC() and not self.isLiteral():
# rpc/encoded Replace wrapper name with None
response.append(\
'%stypecode = Struct(pname=None, ofwhat=%s.typecode.ofwhat, pyclass=%s.typecode.pyclass)' %(
ID2, self.outputName, self.outputName)
)
response.append(\
'%sresponse = self.binding.Receive(typecode%s)' %(
ID2, responseArgs)
)
else:
response.append(\
'%sresponse = self.binding.Receive(%s.typecode%s)' %(
ID2, self.outputName, responseArgs)
)
# only support lit
if self.soap_output_headers:
sh = '['
for shb in self.soap_output_headers:
#shb.encodingStyle, shb.use, shb.namespace
shb.message
shb.part
try:
msg = self._wsdl.messages[shb.message]
part = msg.parts[shb.part]
if part.element is not None:
sh += 'GED%s,' %str(part.element)
else:
warnings.warn('skipping soap output header in Message "%s"' %str(msg))
except:
raise WSDLFormatError(
'failure processing output header typecodes, ' +
'could not find message "%s" or its part "%s"' %(
shb.message, shb.part)
)
sh += ']'
if len(sh) > 2:
response.append(\
'%sself.soapheaders = self.binding.ps.ParseHeaderElements(%s)' %(ID2, sh)
)
if self.outputSimpleType:
response.append('%sreturn %s(response)' %(ID2, self.outputName))
else:
if self.do_extended:
partsList = self.getOperation().getOutputMessage().parts.values()
subNames = GetPartsSubNames(partsList, self._wsdl)
args = []
for pa in subNames:
args += pa
for arg in args:
response.append('%s%s = response.%s' % (ID2, self.mangle(arg), self.getAttributeName(arg)) )
margs = ",".join(args)
response.append("%sreturn %s" % (ID2, margs) )
else:
response.append('%sreturn response' %ID2)
method += response
self.writeArray(method)
class BindingDescription(ServiceContainerBase):
'''writes out SOAP Binding class
class variables:
readerclass --
writerclass --
operationclass -- representation of each operation.
'''
readerclass = None
writerclass = None
operationclass = ServiceOperationContainer
logger = _GetLogger("BindingDescription")
def __init__(self, useWSA=False, do_extended=False, wsdl=None):
'''Parameters:
name -- binding name
property -- resource properties
useWSA -- boolean, enable ws-addressing
name -- binding name
'''
ServiceContainerBase.__init__(self)
self.useWSA = useWSA
self.rProp = None
#self.bName = None
self.operations = None
self.do_extended = do_extended
self._wsdl = wsdl # None unless do_extended == True
def setReaderClass(cls, className):
'''specify a reader class name, this must be imported
in service module.
'''
cls.readerclass = className
setReaderClass = classmethod(setReaderClass)
def setWriterClass(cls, className):
'''specify a writer class name, this must be imported
in service module.
'''
cls.writerclass = className
setWriterClass = classmethod(setWriterClass)
def setOperationClass(cls, className):
'''specify an operation container class name.
'''
cls.operationclass = className
setOperationClass = classmethod(setOperationClass)
def setUp(self, item):
'''This method finds all SOAP Binding Operations, it will skip
all bindings that are not SOAP.
item -- WSDL.Binding instance
'''
assert isinstance(item, WSDLTools.Binding), \
'expecting WSDLTools Binding instance'
portType = item.getPortType()
self._kwargs = KW.copy()
self._kwargs['bind'] = NC_to_CN(item.name)
self.operations = []
self.rProp = portType.getResourceProperties()
soap_binding = item.findBinding(WSDLTools.SoapBinding)
if soap_binding is None:
raise Wsdl2PythonError,\
'Binding(%s) missing WSDLTools.SoapBinding' %item.name
for bop in item.operations:
soap_bop = bop.findBinding(WSDLTools.SoapOperationBinding)
if soap_bop is None:
self.logger.warning(\
'Skip Binding(%s) operation(%s) no SOAP Binding Operation'\
%(item.name, bop.name),
)
continue
#soapAction = soap_bop.soapAction
if bop.input is not None:
soapBodyBind = bop.input.findBinding(WSDLTools.SoapBodyBinding)
if soapBodyBind is None:
self.logger.warning(\
'Skip Binding(%s) operation(%s) Bindings(%s) not supported'\
%(item.name, bop.name, bop.extensions)
)
continue
op = portType.operations.get(bop.name)
if op is None:
raise Wsdl2PythonError,\
'no matching portType/Binding operation(%s)' % bop.name
c = self.operationclass(useWSA=self.useWSA,
do_extended=self.do_extended)
c.setUp(bop)
self.operations.append(c)
def _setContent(self):
if self.useWSA is True:
args = 'endPointReference=None, **kw'
epr = 'self.endPointReference = endPointReference'
else:
args = '**kw'
epr = '# no ws-addressing'
if self.rProp:
rp = 'kw.setdefault("ResourceProperties", ("%s","%s"))'\
%(self.rProp[0], self.rProp[1])
else:
rp = '# no resource properties'
kwargs = self._kwargs
kwargs.update(dict(suffix=self.clientClassSuffix,
args=args, epr=epr, rp=rp, readerclass=self.readerclass,
writerclass=self.writerclass,))
methods = [
'# Methods',
'class %(bind)s%(suffix)s:' %kwargs,
'%(ID1)sdef __init__(self, url, %(args)s):' %kwargs,
'%(ID2)skw.setdefault("readerclass", %(readerclass)s)' %kwargs,
'%(ID2)skw.setdefault("writerclass", %(writerclass)s)' %kwargs,
'%(ID2)s%(rp)s' % kwargs,
'%(ID2)sself.binding = client.Binding(url=url, **kw)' %kwargs,
'%(ID2)s%(epr)s' % kwargs,
]
for op in self.operations:
methods += [ op.getvalue() ]
self.writeArray(methods)
ServiceOperationsClassContainer = BindingDescription
class MessageContainerInterface:
logger = _GetLogger("MessageContainerInterface")
def setUp(self, port, soc, input):
'''sets the attribute _simple which represents a
primitive type message represents, or None if not primitive.
soc -- WSDLTools.ServiceOperationContainer instance
port -- WSDLTools.Port instance
input-- boolean, input messasge or output message of operation.
'''
raise NotImplementedError, 'Message container must implemented setUp.'
class ServiceDocumentLiteralMessageContainer(ServiceContainerBase,
MessageContainerInterface):
logger = _GetLogger("ServiceDocumentLiteralMessageContainer")
def __init__(self, do_extended=False):
ServiceContainerBase.__init__(self)
self.do_extended=do_extended
def setUp(self, port, soc, input):
content = self.content
# TODO: check soapbody for part name
simple = self._simple = soc.isSimpleType(soc.getOperationName())
name = soc.getOperationName()
# Document/literal
operation = port.getBinding().getPortType().operations.get(name)
bop = port.getBinding().operations.get(name)
soapBodyBind = None
if input is True:
soapBodyBind = bop.input.findBinding(WSDLTools.SoapBodyBinding)
message = operation.getInputMessage()
else:
soapBodyBind = bop.output.findBinding(WSDLTools.SoapBodyBinding)
message = operation.getOutputMessage()
# using underlying data structure to avoid phantom problem.
# with message.parts.data.values()
if len(message.parts) == 0:
raise Wsdl2PythonError, 'must specify part for doc/lit msg'
p = None
if soapBodyBind.parts is not None:
if len(soapBodyBind.parts) > 1:
raise Wsdl2PythonError,\
'not supporting multiple parts in soap body'
if len(soapBodyBind.parts) == 0:
return
p = message.parts.get(soapBodyBind.parts[0])
# XXX: Allow for some slop
p = p or message.parts[0]
if p.type:
raise Wsdl2PythonError, 'no doc/lit suport for '
if not p.element:
return
self.ns = p.element[0]
content.ns = p.element[0]
content.pName = p.element[1]
content.mName = message.name
def _setContent(self):
'''create string representation of doc/lit message container. If
message element is simple(primitive), use python type as base class.
'''
try:
simple = self._simple
except AttributeError:
raise RuntimeError, 'call setUp first'
# TODO: Hidden contract. Must set self.ns before getNSAlias...
# File "/usr/local/python/lib/python2.4/site-packages/ZSI/generate/containers.py", line 625, in _setContent
# kw['message'],kw['prefix'],kw['typecode'] = \
# File "/usr/local/python/lib/python2.4/site-packages/ZSI/generate/containers.py", line 128, in getNSAlias
# raise ContainerError, 'no self.ns attr defined in %s' % self.__class__
# ZSI.generate.containers.ContainerError: no self.ns attr defined in ZSI.generate.containers.ServiceDocumentLiteralMessageContainer
#
# self.ns = self.content.ns
kw = KW.copy()
kw.update(dict(message=self.content.mName, nsuri=self.content.ns,
name=self.content.pName))
# kw['message'],kw['prefix'],kw['typecode'] = \
# self.content.mName, self.getNSAlias(), element_class_name(self.content.pName)
#
# These messsages are just global element declarations
# self.writeArray(['%(message)s = %(prefix)s.%(typecode)s().pyclass' %kw])
self.writeArray(['%(message)s = GED("%(nsuri)s", "%(name)s").pyclass' %kw])
class ServiceRPCEncodedMessageContainer(ServiceContainerBase, MessageContainerInterface):
logger = _GetLogger("ServiceRPCEncodedMessageContainer")
def setUp(self, port, soc, input):
'''
Instance Data:
op -- WSDLTools Operation instance
bop -- WSDLTools BindingOperation instance
input -- boolean input/output
'''
name = soc.getOperationName()
bop = port.getBinding().operations.get(name)
op = port.getBinding().getPortType().operations.get(name)
assert op is not None, 'port has no operation %s' %name
assert bop is not None, 'port has no binding operation %s' %name
self.input = input
self.op = op
self.bop = bop
def _setContent(self):
try:
self.op
except AttributeError:
raise RuntimeError, 'call setUp first'
pname = self.op.name
msgRole = self.op.input
msgRoleB = self.bop.input
if self.input is False:
pname = '%sResponse' %self.op.name
msgRole = self.op.output
msgRoleB = self.bop.output
sbody = msgRoleB.findBinding(WSDLTools.SoapBodyBinding)
if not sbody or not sbody.namespace:
raise WSInteropError, WSISpec.R2717
assert sbody.use == 'encoded', 'Expecting use=="encoded"'
encodingStyle = sbody.encodingStyle
assert encodingStyle == SOAP.ENC,\
'Supporting encodingStyle=%s, not %s' %(SOAP.ENC, encodingStyle)
namespace = sbody.namespace
tcb = MessageTypecodeContainer(\
tuple(msgRole.getMessage().parts.list),
)
ofwhat = '[%s]' %tcb.getTypecodeList()
pyclass = msgRole.getMessage().name
fdict = KW.copy()
fdict['nspname'] = sbody.namespace
fdict['pname'] = pname
fdict['pyclass'] = None
fdict['ofwhat'] = ofwhat
fdict['encoded'] = namespace
#if self.input is False:
# fdict['typecode'] = \
# 'Struct(pname=None, ofwhat=%(ofwhat)s, pyclass=%(pyclass)s, encoded="%(encoded)s")'
#else:
fdict['typecode'] = \
'Struct(pname=("%(nspname)s","%(pname)s"), ofwhat=%(ofwhat)s, pyclass=%(pyclass)s, encoded="%(encoded)s")'
message = ['class %(pyclass)s:',
'%(ID1)sdef __init__(self, **kw):',
'%(ID2)s"""Keyword parameters:',
]
idx = len(message)
for a,p in zip(tcb.getAttributeNames(), tcb.getParameterNames()):
message.insert(idx, '%(ID2)s' + p + ' -- part ' + p)
message.append('%(ID2)sself.' + a + ' = kw.get("%s")' %p)
idx += 1
message.insert(idx, '%(ID2)s"""')
# TODO: This isn't a TypecodeContainerBase instance but it
# certaintly generates a pyclass and typecode.
#if self.metaclass is None:
if TypecodeContainerBase.metaclass is None:
fdict['pyclass'] = pyclass
fdict['typecode'] = fdict['typecode'] %fdict
message.append('%(pyclass)s.typecode = %(typecode)s')
else:
# Need typecode to be available when class is constructed.
fdict['typecode'] = fdict['typecode'] %fdict
fdict['pyclass'] = pyclass
fdict['metaclass'] = TypecodeContainerBase.metaclass
message.insert(0, '_%(pyclass)sTypecode = %(typecode)s')
message.insert(2, '%(ID1)stypecode = _%(pyclass)sTypecode')
message.insert(3, '%(ID1)s__metaclass__ = %(metaclass)s')
message.append('%(pyclass)s.typecode.pyclass = %(pyclass)s')
self.writeArray(map(lambda l: l %fdict, message))
class ServiceRPCLiteralMessageContainer(ServiceContainerBase, MessageContainerInterface):
logger = _GetLogger("ServiceRPCLiteralMessageContainer")
def setUp(self, port, soc, input):
'''
Instance Data:
op -- WSDLTools Operation instance
bop -- WSDLTools BindingOperation instance
input -- boolean input/output
'''
name = soc.getOperationName()
bop = port.getBinding().operations.get(name)
op = port.getBinding().getPortType().operations.get(name)
assert op is not None, 'port has no operation %s' %name
assert bop is not None, 'port has no binding operation %s' %name
self.op = op
self.bop = bop
self.input = input
def _setContent(self):
try:
self.op
except AttributeError:
raise RuntimeError, 'call setUp first'
operation = self.op
input = self.input
pname = operation.name
msgRole = operation.input
msgRoleB = self.bop.input
if input is False:
pname = '%sResponse' %operation.name
msgRole = operation.output
msgRoleB = self.bop.output
sbody = msgRoleB.findBinding(WSDLTools.SoapBodyBinding)
if not sbody or not sbody.namespace:
raise WSInteropError, WSISpec.R2717
namespace = sbody.namespace
tcb = MessageTypecodeContainer(\
tuple(msgRole.getMessage().parts.list),
)
ofwhat = '[%s]' %tcb.getTypecodeList()
pyclass = msgRole.getMessage().name
fdict = KW.copy()
fdict['nspname'] = sbody.namespace
fdict['pname'] = pname
fdict['pyclass'] = None
fdict['ofwhat'] = ofwhat
fdict['encoded'] = namespace
fdict['typecode'] = \
'Struct(pname=("%(nspname)s","%(pname)s"), ofwhat=%(ofwhat)s, pyclass=%(pyclass)s, encoded="%(encoded)s")'
message = ['class %(pyclass)s:',
'%(ID1)sdef __init__(self, **kw):',
'%(ID2)s"""Keyword parameters:',
]
idx = len(message)
for a,p in zip(tcb.getAttributeNames(), tcb.getParameterNames()):
message.insert(idx, '%(ID2)s' + p + ' -- part ' + p)
message.append('%(ID2)sself.' + a + ' = kw.get("%s")' %p)
idx += 1
message.insert(idx, '%(ID2)s"""')
# TODO: This isn't a TypecodeContainerBase instance but it
# certaintly generates a pyclass and typecode.
#if self.metaclass is None:
if TypecodeContainerBase.metaclass is None:
fdict['pyclass'] = pyclass
fdict['typecode'] = fdict['typecode'] %fdict
message.append('%(pyclass)s.typecode = %(typecode)s')
else:
# Need typecode to be available when class is constructed.
fdict['typecode'] = fdict['typecode'] %fdict
fdict['pyclass'] = pyclass
fdict['metaclass'] = TypecodeContainerBase.metaclass
message.insert(0, '_%(pyclass)sTypecode = %(typecode)s')
message.insert(2, '%(ID1)stypecode = _%(pyclass)sTypecode')
message.insert(3, '%(ID1)s__metaclass__ = %(metaclass)s')
message.append('%(pyclass)s.typecode.pyclass = %(pyclass)s')
self.writeArray(map(lambda l: l %fdict, message))
TypesContainerBase = ContainerBase
class TypesHeaderContainer(TypesContainerBase):
'''imports for all generated types modules.
'''
imports = [
'import ZSI',
'import ZSI.TCcompound',
'from ZSI.schema import LocalElementDeclaration, ElementDeclaration, TypeDefinition, GTD, GED',
]
logger = _GetLogger("TypesHeaderContainer")
def _setContent(self):
self.writeArray(TypesHeaderContainer.imports)
NamespaceClassContainerBase = TypesContainerBase
class NamespaceClassHeaderContainer(NamespaceClassContainerBase):
logger = _GetLogger("NamespaceClassHeaderContainer")
def _setContent(self):
head = [
'#' * 30,
'# targetNamespace',
'# %s' % self.ns,
'#' * 30 + '\n',
'class %s:' % self.getNSAlias(),
'%stargetNamespace = "%s"' % (ID1, self.ns)
]
self.writeArray(head)
class NamespaceClassFooterContainer(NamespaceClassContainerBase):
logger = _GetLogger("NamespaceClassFooterContainer")
def _setContent(self):
foot = [
'# end class %s (tns: %s)' % (self.getNSAlias(), self.ns),
]
self.writeArray(foot)
BTI = BaseTypeInterpreter()
class TypecodeContainerBase(TypesContainerBase):
'''Base class for all classes representing anything
with element content.
class variables:
mixed_content_aname -- text content will be placed in this attribute.
attributes_aname -- attributes will be placed in this attribute.
metaclass -- set this attribute to specify a pyclass __metaclass__
'''
mixed_content_aname = 'text'
attributes_aname = 'attrs'
metaclass = None
lazy = False
logger = _GetLogger("TypecodeContainerBase")
def __init__(self, do_extended=False, extPyClasses=None):
TypesContainerBase.__init__(self)
self.name = None
# attrs for model groups and others with elements, tclists, etc...
self.allOptional = False
self.mgContent = None
self.contentFlattened = False
self.elementAttrs = []
self.tcListElements = []
self.tcListSet = False
self.localTypes = []
# used when processing nested anonymous types
self.parentClass = None
# used when processing attribute content
self.mixed = False
self.extraFlags = ''
self.attrComponents = None
# --> EXTENDED
# Used if an external pyclass was specified for this type.
self.do_extended = do_extended
if extPyClasses is None:
self.extPyClasses = {}
else:
self.extPyClasses = extPyClasses
# <--
def getvalue(self):
out = ContainerBase.getvalue(self)
for item in self.localTypes:
content = None
assert True is item.isElement() is item.isLocal(), 'expecting local elements only'
etp = item.content
qName = item.getAttribute('type')
if not qName:
etp = item.content
local = True
else:
etp = item.getTypeDefinition('type')
if etp is None:
if local is True:
content = ElementLocalComplexTypeContainer(do_extended=self.do_extended)
else:
content = ElementSimpleTypeContainer()
elif etp.isLocal() is False:
content = ElementGlobalDefContainer()
elif etp.isSimple() is True:
content = ElementLocalSimpleTypeContainer()
elif etp.isComplex():
content = ElementLocalComplexTypeContainer(do_extended=self.do_extended)
else:
raise Wsdl2PythonError, "Unknown element declaration: %s" %item.getItemTrace()
content.setUp(item)
out += '\n\n'
if self.parentClass:
content.parentClass = \
'%s.%s' %(self.parentClass, self.getClassName())
else:
content.parentClass = '%s.%s' %(self.getNSAlias(), self.getClassName())
for l in content.getvalue().split('\n'):
if l: out += '%s%s\n' % (ID1, l)
else: out += '\n'
out += '\n\n'
return out
def getAttributeName(self, name):
'''represents the aname
'''
if self.func_aname is None:
return name
assert callable(self.func_aname), \
'expecting callable method for attribute func_aname, not %s' %type(self.func_aname)
f = self.func_aname
return f(name)
def getMixedTextAName(self):
'''returns an aname representing mixed text content.
'''
return self.getAttributeName(self.mixed_content_aname)
def getClassName(self):
if not self.name:
raise ContainerError, 'self.name not defined!'
if not hasattr(self.__class__, 'type'):
raise ContainerError, 'container type not defined!'
#suffix = self.__class__.type
if self.__class__.type == DEF:
classname = type_class_name(self.name)
elif self.__class__.type == DEC:
classname = element_class_name(self.name)
return self.mangle( classname )
# --> EXTENDED
def hasExtPyClass(self):
if self.name in self.extPyClasses:
return True
else:
return False
# <--
def getPyClass(self):
'''Name of generated inner class that will be specified as pyclass.
'''
# --> EXTENDED
if self.hasExtPyClass():
classInfo = self.extPyClasses[self.name]
return ".".join(classInfo)
# <--
return 'Holder'
def getPyClassDefinition(self):
'''Return a list containing pyclass definition.
'''
kw = KW.copy()
# --> EXTENDED
if self.hasExtPyClass():
classInfo = self.extPyClasses[self.name]
kw['classInfo'] = classInfo[0]
return ["%(ID3)simport %(classInfo)s" %kw ]
# <--
kw['pyclass'] = self.getPyClass()
definition = []
definition.append('%(ID3)sclass %(pyclass)s:' %kw)
if self.metaclass is not None:
kw['type'] = self.metaclass
definition.append('%(ID4)s__metaclass__ = %(type)s' %kw)
definition.append('%(ID4)stypecode = self' %kw)
#TODO: Remove pyclass holder __init__ -->
definition.append('%(ID4)sdef __init__(self):' %kw)
definition.append('%(ID5)s# pyclass' %kw)
# JRB HACK need to call _setElements via getElements
self._setUpElements()
# JRB HACK need to indent additional one level
for el in self.elementAttrs:
kw['element'] = el
definition.append('%(ID2)s%(element)s' %kw)
definition.append('%(ID5)sreturn' %kw)
# <--
# pyclass descriptive name
if self.name is not None:
kw['name'] = self.name
definition.append(\
'%(ID3)s%(pyclass)s.__name__ = "%(name)s_Holder"' %kw
)
return definition
def nsuriLogic(self):
'''set a variable "ns" that represents the targetNamespace in
which this item is defined. Used for namespacing local elements.
'''
if self.parentClass:
return 'ns = %s.%s.schema' %(self.parentClass, self.getClassName())
return 'ns = %s.%s.schema' %(self.getNSAlias(), self.getClassName())
def schemaTag(self):
if self.ns is not None:
return 'schema = "%s"' % self.ns
raise ContainerError, 'failed to set schema targetNamespace(%s)' %(self.__class__)
def typeTag(self):
if self.name is not None:
return 'type = (schema, "%s")' % self.name
raise ContainerError, 'failed to set type name(%s)' %(self.__class__)
def literalTag(self):
if self.name is not None:
return 'literal = "%s"' % self.name
raise ContainerError, 'failed to set element name(%s)' %(self.__class__)
def getExtraFlags(self):
if self.mixed:
self.extraFlags += 'mixed=True, mixed_aname="%s", ' %self.getMixedTextAName()
return self.extraFlags
def simpleConstructor(self, superclass=None):
if superclass:
return '%s.__init__(self, **kw)' % superclass
else:
return 'def __init__(self, **kw):'
def pnameConstructor(self, superclass=None):
if superclass:
return '%s.__init__(self, pname, **kw)' % superclass
else:
return 'def __init__(self, pname, **kw):'
def _setUpElements(self):
"""TODO: Remove this method
This method ONLY sets up the instance attributes.
Dependency instance attribute:
mgContent -- expected to be either a complex definition
with model group content, a model group, or model group
content. TODO: should only support the first two.
"""
self.logger.debug("_setUpElements: %s" %self._item.getItemTrace())
if hasattr(self, '_done'):
#return '\n'.join(self.elementAttrs)
return
self._done = True
flat = []
content = self.mgContent
if type(self.mgContent) is not tuple:
mg = self.mgContent
if not mg.isModelGroup():
mg = mg.content
content = mg.content
if mg.isAll():
flat = content
content = []
elif mg.isModelGroup() and mg.isDefinition():
mg = mg.content
content = mg.content
idx = 0
content = list(content)
while idx < len(content):
c = orig = content[idx]
if c.isElement():
flat.append(c)
idx += 1
continue
if c.isReference() and c.isModelGroup():
c = c.getModelGroupReference()
if c.isDefinition() and c.isModelGroup():
c = c.content
if c.isSequence() or c.isChoice():
begIdx = idx
endIdx = begIdx + len(c.content)
for i in range(begIdx, endIdx):
content.insert(i, c.content[i-begIdx])
content.remove(orig)
continue
raise ContainerError, 'unexpected schema item: %s' %c.getItemTrace()
for c in flat:
if c.isDeclaration() and c.isElement():
defaultValue = "None"
parent = c
defs = []
# stop recursion via global ModelGroupDefinition
while defs.count(parent) <= 1:
maxOccurs = parent.getAttribute('maxOccurs')
if maxOccurs == 'unbounded' or int(maxOccurs) > 1:
defaultValue = "[]"
break
parent = parent._parent()
if not parent.isModelGroup():
break
if parent.isReference():
parent = parent.getModelGroupReference()
if parent.isDefinition():
parent = parent.content
defs.append(parent)
if None == c.getAttribute('name') and c.isWildCard():
e = '%sself.%s = %s' %(ID3,
self.getAttributeName('any'), defaultValue)
else:
e = '%sself.%s = %s' %(ID3,
self.getAttributeName(c.getAttribute('name')), defaultValue)
self.elementAttrs.append(e)
continue
# TODO: This seems wrong
if c.isReference():
e = '%sself._%s = None' %(ID3,
self.mangle(c.getAttribute('ref')[1]))
self.elementAttrs.append(e)
continue
raise ContainerError, 'unexpected item: %s' % c.getItemTrace()
#return '\n'.join(self.elementAttrs)
return
def _setTypecodeList(self):
"""generates ofwhat content, minOccurs/maxOccurs facet generation.
Dependency instance attribute:
mgContent -- expected to be either a complex definition
with model group content, a model group, or model group
content. TODO: should only support the first two.
localTypes -- produce local class definitions later
tcListElements -- elements, local/global
"""
self.logger.debug("_setTypecodeList(%r): %s" %
(self.mgContent, self._item.getItemTrace()))
flat = []
content = self.mgContent
#TODO: too much slop permitted here, impossible
# to tell what is going on.
if type(content) is not tuple:
mg = content
if not mg.isModelGroup():
raise Wsdl2PythonErr("Expecting ModelGroup: %s" %
mg.getItemTrace())
self.logger.debug("ModelGroup(%r) contents(%r): %s" %
(mg, mg.content, mg.getItemTrace()))
#
if mg.isReference():
raise RuntimeError("Unexpected modelGroup reference: %s" %
mg.getItemTrace())
#
if mg.isDefinition():
mg = mg.content
if mg.isAll():
flat = mg.content
content = []
elif mg.isSequence():
content = mg.content
elif mg.isChoice():
content = mg.content
else:
raise RuntimeError("Unknown schema item")
idx = 0
content = list(content)
self.logger.debug("content: %r" %content)
while idx < len(content):
c = orig = content[idx]
if c.isElement():
flat.append(c)
idx += 1
continue
if c.isReference() and c.isModelGroup():
c = c.getModelGroupReference()
if c.isDefinition() and c.isModelGroup():
c = c.content
if c.isSequence() or c.isChoice():
begIdx = idx
endIdx = begIdx + len(c.content)
for i in range(begIdx, endIdx):
content.insert(i, c.content[i-begIdx])
content.remove(orig)
continue
raise ContainerError, 'unexpected schema item: %s' %c.getItemTrace()
# TODO: Need to store "parents" in a dict[id] = list(),
# because cannot follow references, but not currently
# a big concern.
self.logger.debug("flat: %r" %list(flat))
for c in flat:
tc = TcListComponentContainer()
# TODO: Remove _getOccurs
min,max,nil = self._getOccurs(c)
min = max = None
maxOccurs = 1
parent = c
defs = []
# stop recursion via global ModelGroupDefinition
while defs.count(parent) <= 1:
max = parent.getAttribute('maxOccurs')
if max == 'unbounded':
maxOccurs = '"%s"' %max
break
maxOccurs = int(max) * maxOccurs
parent = parent._parent()
if not parent.isModelGroup():
break
if parent.isReference():
parent = parent.getModelGroupReference()
if parent.isDefinition():
parent = parent.content
defs.append(parent)
del defs
parent = c
while 1:
minOccurs = int(parent.getAttribute('minOccurs'))
if minOccurs == 0 or parent.isChoice():
minOccurs = 0
break
parent = parent._parent()
if not parent.isModelGroup():
minOccurs = int(c.getAttribute('minOccurs'))
break
if parent.isReference():
parent = parent.getModelGroupReference()
if parent.isDefinition():
parent = parent.content
tc.setOccurs(minOccurs, maxOccurs, nil)
processContents = self._getProcessContents(c)
tc.setProcessContents(processContents)
if c.isDeclaration() and c.isElement():
global_type = c.getAttribute('type')
content = getattr(c, 'content', None)
if c.isLocal() and c.isQualified() is False:
tc.unQualified()
if c.isWildCard():
tc.setStyleAnyElement()
elif global_type is not None:
tc.name = c.getAttribute('name')
ns = global_type[0]
if ns in SCHEMA.XSD_LIST:
tpc = BTI.get_typeclass(global_type[1],global_type[0])
tc.klass = tpc
# elif (self.ns,self.name) == global_type:
# # elif self._isRecursiveElement(c)
# # TODO: Remove this, it only works for 1 level.
# tc.setStyleRecursion()
else:
tc.setGlobalType(*global_type)
# tc.klass = '%s.%s' % (NAD.getAlias(ns),
# type_class_name(global_type[1]))
del ns
elif content is not None and content.isLocal() and content.isComplex():
tc.name = c.getAttribute('name')
tc.klass = 'self.__class__.%s' % (element_class_name(tc.name))
#TODO: Not an element reference, confusing nomenclature
tc.setStyleElementReference()
self.localTypes.append(c)
elif content is not None and content.isLocal() and content.isSimple():
# Local Simple Type
tc.name = c.getAttribute('name')
tc.klass = 'self.__class__.%s' % (element_class_name(tc.name))
#TODO: Not an element reference, confusing nomenclature
tc.setStyleElementReference()
self.localTypes.append(c)
else:
raise ContainerError, 'unexpected item: %s' % c.getItemTrace()
elif c.isReference():
# element references
ref = c.getAttribute('ref')
# tc.klass = '%s.%s' % (NAD.getAlias(ref[0]),
# element_class_name(ref[1]) )
tc.setStyleElementReference()
tc.setGlobalType(*ref)
else:
raise ContainerError, 'unexpected item: %s' % c.getItemTrace()
self.tcListElements.append(tc)
def getTypecodeList(self):
if not self.tcListSet:
# self._flattenContent()
self._setTypecodeList()
self.tcListSet = True
list = []
for e in self.tcListElements:
list.append(str(e))
return ', '.join(list)
# the following _methods() are utility methods used during
# TCList generation, et al.
def _getOccurs(self, e):
nillable = e.getAttribute('nillable')
if nillable == 'true':
nillable = True
else:
nillable = False
maxOccurs = e.getAttribute('maxOccurs')
if maxOccurs == 'unbounded':
maxOccurs = '"%s"' %maxOccurs
minOccurs = e.getAttribute('minOccurs')
if self.allOptional is True:
#JRB Hack
minOccurs = '0'
maxOccurs = '"unbounded"'
return minOccurs,maxOccurs,nillable
def _getProcessContents(self, e):
processContents = e.getAttribute('processContents')
return processContents
def getBasesLogic(self, indent):
try:
prefix = NAD.getAlias(self.sKlassNS)
except WsdlGeneratorError, ex:
# XSD or SOAP
raise
bases = []
bases.append(\
'if %s.%s not in %s.%s.__bases__:'\
%(NAD.getAlias(self.sKlassNS), type_class_name(self.sKlass), self.getNSAlias(), self.getClassName()),
)
bases.append(\
'%sbases = list(%s.%s.__bases__)'\
%(ID1,self.getNSAlias(),self.getClassName()),
)
bases.append(\
'%sbases.insert(0, %s.%s)'\
%(ID1,NAD.getAlias(self.sKlassNS), type_class_name(self.sKlass) ),
)
bases.append(\
'%s%s.%s.__bases__ = tuple(bases)'\
%(ID1, self.getNSAlias(), self.getClassName())
)
s = ''
for b in bases:
s += '%s%s\n' % (indent, b)
return s
class MessageTypecodeContainer(TypecodeContainerBase):
'''Used for RPC style messages, where we have
serveral parts serialized within a rpc wrapper name.
'''
logger = _GetLogger("MessageTypecodeContainer")
def __init__(self, parts=None):
TypecodeContainerBase.__init__(self)
self.mgContent = parts
def _getOccurs(self, e):
'''return a 3 item tuple
'''
minOccurs = maxOccurs = '1'
nillable = True
return minOccurs,maxOccurs,nillable
def _setTypecodeList(self):
self.logger.debug("_setTypecodeList: %s" %
str(self.mgContent))
assert type(self.mgContent) is tuple,\
'expecting tuple for mgContent not: %s' %type(self.mgContent)
for p in self.mgContent:
# JRB
# not sure what needs to be set for tc, this should be
# the job of the constructor or a setUp method.
min,max,nil = self._getOccurs(p)
if p.element:
raise WSInteropError, WSISpec.R2203
elif p.type:
nsuri,name = p.type
tc = RPCMessageTcListComponentContainer(qualified=False)
tc.setOccurs(min, max, nil)
tc.name = p.name
if nsuri in [SOAP.ENC] + SCHEMA.XSD_LIST:
tpc = BTI.get_typeclass(name, nsuri)
tc.klass = tpc
else:
tc.klass = '%s.%s' % (NAD.getAlias(nsuri), type_class_name(name) )
else:
raise ContainerError, 'part must define an element or type attribute'
self.tcListElements.append(tc)
def getTypecodeList(self):
if not self.tcListSet:
self._setTypecodeList()
self.tcListSet = True
list = []
for e in self.tcListElements:
list.append(str(e))
return ', '.join(list)
def getAttributeNames(self):
'''returns a list of anames representing the parts
of the message.
'''
return map(lambda e: self.getAttributeName(e.name), self.tcListElements)
def getParameterNames(self):
'''returns a list of pnames representing the parts
of the message.
'''
return map(lambda e: e.name, self.tcListElements)
def setParts(self, parts):
self.mgContent = parts
class TcListComponentContainer(ContainerBase):
'''Encapsulates a single value in the TClist list.
it inherits TypecodeContainerBase only to get the mangle() method,
it does not call the baseclass ctor.
TODO: Change this inheritance scheme.
'''
logger = _GetLogger("TcListComponentContainer")
def __init__(self, qualified=True):
'''
qualified -- qualify element. All GEDs should be qualified,
but local element declarations qualified if form attribute
is qualified, else they are unqualified. Only relevant for
standard style.
'''
#TypecodeContainerBase.__init__(self)
ContainerBase.__init__(self)
self.qualified = qualified
self.name = None
self.klass = None
self.global_type = None
self.min = None
self.max = None
self.nil = None
self.style = None
self.setStyleElementDeclaration()
def setOccurs(self, min, max, nil):
self.min = min
self.max = max
self.nil = nil
def setProcessContents(self, processContents):
self.processContents = processContents
def setGlobalType(self, namespace, name):
self.global_type = (namespace, name)
def setStyleElementDeclaration(self):
'''set the element style.
standard -- GED or local element
'''
self.style = 'standard'
def setStyleElementReference(self):
'''set the element style.
ref -- element reference
'''
self.style = 'ref'
def setStyleAnyElement(self):
'''set the element style.
anyElement -- element wildcard
'''
self.name = 'any'
self.style = 'anyElement'
# def setStyleRecursion(self):
# '''TODO: Remove. good for 1 level
# '''
# self.style = 'recursion'
def unQualified(self):
'''Do not qualify element.
'''
self.qualified = False
def _getOccurs(self):
return 'minOccurs=%s, maxOccurs=%s, nillable=%s' \
% (self.min, self.max, self.nil)
def _getProcessContents(self):
return 'processContents="%s"' \
% (self.processContents)
def _getvalue(self):
kw = {'occurs':self._getOccurs(),
'aname':self.getAttributeName(self.name),
'klass':self.klass,
'lazy':TypecodeContainerBase.lazy,
'typed':'typed=False',
'encoded':'encoded=kw.get("encoded")'}
gt = self.global_type
if gt is not None:
kw['nsuri'],kw['type'] = gt
if self.style == 'standard':
kw['pname'] = '"%s"' %self.name
if self.qualified is True:
kw['pname'] = '(ns,"%s")' %self.name
if gt is None:
return '%(klass)s(pname=%(pname)s, aname="%(aname)s", %(occurs)s, %(typed)s, %(encoded)s)' %kw
return 'GTD("%(nsuri)s","%(type)s",lazy=%(lazy)s)(pname=%(pname)s, aname="%(aname)s", %(occurs)s, %(typed)s, %(encoded)s)' %kw
if self.style == 'ref':
if gt is None:
return '%(klass)s(%(occurs)s, %(encoded)s)' %kw
return 'GED("%(nsuri)s","%(type)s",lazy=%(lazy)s, isref=True)(%(occurs)s, %(encoded)s)' %kw
kw['process'] = self._getProcessContents()
if self.style == 'anyElement':
return 'ZSI.TC.AnyElement(aname="%(aname)s", %(occurs)s, %(process)s)' %kw
# if self.style == 'recursion':
# return 'ZSI.TC.AnyElement(aname="%(aname)s", %(occurs)s, %(process)s)' %kw
raise RuntimeError, 'Must set style for typecode list generation'
def __str__(self):
return self._getvalue()
class RPCMessageTcListComponentContainer(TcListComponentContainer):
'''Container for rpc/literal rpc/encoded message typecode.
'''
logger = _GetLogger("RPCMessageTcListComponentContainer")
def __init__(self, qualified=True, encoded=None):
'''
encoded -- encoded namespaceURI, if None treat as rpc/literal.
'''
TcListComponentContainer.__init__(self, qualified=qualified)
self._encoded = encoded
def _getvalue(self):
encoded = self._encoded
if encoded is not None:
encoded = '"%s"' %self._encoded
if self.style == 'standard':
pname = '"%s"' %self.name
if self.qualified is True:
pname = '(ns,"%s")' %self.name
return '%s(pname=%s, aname="%s", typed=False, encoded=%s, %s)' \
%(self.klass, pname, self.getAttributeName(self.name),
encoded, self._getOccurs())
elif self.style == 'ref':
return '%s(encoded=%s, %s)' % (self.klass, encoded, self._getOccurs())
elif self.style == 'anyElement':
return 'ZSI.TC.AnyElement(aname="%s", %s, %s)' \
%(self.getAttributeName(self.name), self._getOccurs(), self._getProcessContents())
# elif self.style == 'recursion':
# return 'ZSI.TC.AnyElement(aname="%s", %s, %s)' \
# % (self.getAttributeName(self.name), self._getOccurs(), self._getProcessContents())
raise RuntimeError('Must set style(%s) for typecode list generation' %
self.style)
class ElementSimpleTypeContainer(TypecodeContainerBase):
type = DEC
logger = _GetLogger("ElementSimpleTypeContainer")
def _substitutionGroupTag(self):
value = self.substitutionGroup
if not value:
return 'substitutionGroup = None'
nsuri,ncname = value
return 'substitutionGroup = ("%s","%s")' %(nsuri, ncname)
def _setContent(self):
aname = self.getAttributeName(self.name)
pyclass = self.pyclass
# bool cannot be subclassed
if pyclass == 'bool': pyclass = 'int'
kw = KW.copy()
kw.update(dict(aname=aname, ns=self.ns, name=self.name,
substitutionGroup=self._substitutionGroupTag(),
subclass=self.sKlass,literal=self.literalTag(),
schema=self.schemaTag(), init=self.simpleConstructor(),
klass=self.getClassName(), element="ElementDeclaration"))
if self.local:
kw['element'] = 'LocalElementDeclaration'
element = map(lambda i: i %kw, [
'%(ID1)sclass %(klass)s(%(subclass)s, %(element)s):',
'%(ID2)s%(literal)s',
'%(ID2)s%(schema)s',
'%(ID2)s%(init)s',
'%(ID3)skw["pname"] = ("%(ns)s","%(name)s")',
'%(ID3)skw["aname"] = "%(aname)s"',
]
)
# TODO: What about getPyClass and getPyClassDefinition?
# I want to add pyclass metaclass here but this needs to be
# corrected first.
#
# anyType (?others) has no pyclass.
app = element.append
if pyclass is not None:
app('%sclass IHolder(%s): typecode=self' % (ID3, pyclass),)
app('%skw["pyclass"] = IHolder' %(ID3),)
app('%sIHolder.__name__ = "%s_immutable_holder"' %(ID3, aname),)
app('%s%s' % (ID3, self.simpleConstructor(self.sKlass)),)
self.writeArray(element)
def setUp(self, tp):
self._item = tp
self.local = tp.isLocal()
try:
self.name = tp.getAttribute('name')
self.substitutionGroup = tp.getAttribute('substitutionGroup')
self.ns = tp.getTargetNamespace()
qName = tp.getAttribute('type')
except Exception, ex:
raise Wsdl2PythonError('Error occured processing element: %s' %(
tp.getItemTrace()), *ex.args)
if qName is None:
raise Wsdl2PythonError('Missing QName for element type attribute: %s' %tp.getItemTrace())
tns,local = qName.getTargetNamespace(),qName.getName()
self.sKlass = BTI.get_typeclass(local, tns)
if self.sKlass is None:
raise Wsdl2PythonError('No built-in typecode for type definition("%s","%s"): %s' %(tns,local,tp.getItemTrace()))
try:
self.pyclass = BTI.get_pythontype(None, None, typeclass=self.sKlass)
except Exception, ex:
raise Wsdl2PythonError('Error occured processing element: %s' %(
tp.getItemTrace()), *ex.args)
class ElementLocalSimpleTypeContainer(TypecodeContainerBase):
'''local simpleType container
'''
type = DEC
logger = _GetLogger("ElementLocalSimpleTypeContainer")
def _setContent(self):
kw = KW.copy()
kw.update(dict(aname=self.getAttributeName(self.name), ns=self.ns, name=self.name,
subclass=self.sKlass,literal=self.literalTag(),
schema=self.schemaTag(), init=self.simpleConstructor(),
klass=self.getClassName(), element="ElementDeclaration",
baseinit=self.simpleConstructor(self.sKlass)))
if self.local:
kw['element'] = 'LocalElementDeclaration'
element = map(lambda i: i %kw, [
'%(ID1)sclass %(klass)s(%(subclass)s, %(element)s):',
'%(ID2)s%(literal)s',
'%(ID2)s%(schema)s',
'%(ID2)s%(init)s',
'%(ID3)skw["pname"] = ("%(ns)s","%(name)s")',
'%(ID3)skw["aname"] = "%(aname)s"',
'%(ID3)s%(baseinit)s',
]
)
app = element.append
pyclass = self.pyclass
if pyclass is not None:
# bool cannot be subclassed
if pyclass == 'bool': pyclass = 'int'
kw['pyclass'] = pyclass
app('%(ID3)sclass IHolder(%(pyclass)s): typecode=self' %kw)
app('%(ID3)sself.pyclass = IHolder' %kw)
app('%(ID3)sIHolder.__name__ = "%(aname)s_immutable_holder"' %kw)
self.writeArray(element)
def _setup_pyclass(self):
try:
self.pyclass = BTI.get_pythontype(None, None,
typeclass=self.sKlass)
except Exception, ex:
raise Wsdl2PythonError('Error occured processing element: %s' %(
self._item.getItemTrace()), *ex.args)
def setUp(self, tp):
self._item = tp
assert tp.isElement() is True and tp.content is not None and \
tp.content.isLocal() is True and tp.content.isSimple() is True ,\
'expecting local simple type: %s' %tp.getItemTrace()
self.local = tp.isLocal()
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
content = tp.content.content
if content.isRestriction():
try:
base = content.getTypeDefinition()
except XMLSchema.SchemaError, ex:
base = None
qName = content.getAttributeBase()
if base is None:
self.sKlass = BTI.get_typeclass(qName[1], qName[0])
self._setup_pyclass()
return
raise Wsdl2PythonError, 'unsupported local simpleType restriction: %s' \
%tp.content.getItemTrace()
if content.isList():
try:
base = content.getTypeDefinition()
except XMLSchema.SchemaError, ex:
base = None
if base is None:
qName = content.getItemType()
self.sKlass = BTI.get_typeclass(qName[1], qName[0])
self._setup_pyclass()
return
raise Wsdl2PythonError, 'unsupported local simpleType List: %s' \
%tp.content.getItemTrace()
if content.isUnion():
raise Wsdl2PythonError, 'unsupported local simpleType Union: %s' \
%tp.content.getItemTrace()
raise Wsdl2PythonError, 'unexpected schema item: %s' \
%tp.content.getItemTrace()
class ElementLocalComplexTypeContainer(TypecodeContainerBase, AttributeMixIn):
type = DEC
logger = _GetLogger("ElementLocalComplexTypeContainer")
def _setContent(self):
kw = KW.copy()
try:
kw.update(dict(klass=self.getClassName(),
subclass='ZSI.TCcompound.ComplexType',
element='ElementDeclaration',
literal=self.literalTag(),
schema=self.schemaTag(),
init=self.simpleConstructor(),
ns=self.ns, name=self.name,
aname=self.getAttributeName(self.name),
nsurilogic=self.nsuriLogic(),
ofwhat=self.getTypecodeList(),
atypecode=self.attribute_typecode,
pyclass=self.getPyClass(),
))
except Exception, ex:
args = ['Failure processing an element w/local complexType: %s' %(
self._item.getItemTrace())]
args += ex.args
ex.args = tuple(args)
raise
if self.local:
kw['element'] = 'LocalElementDeclaration'
element = [
'%(ID1)sclass %(klass)s(%(subclass)s, %(element)s):',
'%(ID2)s%(literal)s',
'%(ID2)s%(schema)s',
'%(ID2)s%(init)s',
'%(ID3)s%(nsurilogic)s',
'%(ID3)sTClist = [%(ofwhat)s]',
'%(ID3)skw["pname"] = ("%(ns)s","%(name)s")',
'%(ID3)skw["aname"] = "%(aname)s"',
'%(ID3)s%(atypecode)s = {}',
'%(ID3)sZSI.TCcompound.ComplexType.__init__(self,None,TClist,inorder=0,**kw)',
]
for l in self.attrComponents: element.append('%(ID3)s'+str(l))
element += self.getPyClassDefinition()
element.append('%(ID3)sself.pyclass = %(pyclass)s' %kw)
self.writeArray(map(lambda l: l %kw, element))
def setUp(self, tp):
'''
{'xsd':['annotation', 'simpleContent', 'complexContent',\
'group', 'all', 'choice', 'sequence', 'attribute', 'attributeGroup',\
'anyAttribute', 'any']}
'''
#
# TODO: Need a Recursive solution, this is incomplete will ignore many
# extensions, restrictions, etc.
#
self._item = tp
# JRB HACK SUPPORTING element/no content.
assert tp.isElement() is True and \
(tp.content is None or (tp.content.isComplex() is True and tp.content.isLocal() is True)),\
'expecting element w/local complexType not: %s' %tp.content.getItemTrace()
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
self.local = tp.isLocal()
complex = tp.content
# JRB HACK SUPPORTING element/no content.
if complex is None:
self.mgContent = ()
return
#attributeContent = complex.getAttributeContent()
#self.mgContent = None
if complex.content is None:
self.mgContent = ()
self.attrComponents = self._setAttributes(complex.getAttributeContent())
return
is_simple = complex.content.isSimple()
if is_simple and complex.content.content.isExtension():
# TODO: Not really supported just passing thru
self.mgContent = ()
self.attrComponents = self._setAttributes(complex.getAttributeContent())
return
if is_simple and complex.content.content.isRestriction():
# TODO: Not really supported just passing thru
self.mgContent = ()
self.attrComponents = self._setAttributes(complex.getAttributeContent())
return
if is_simple:
raise ContainerError, 'not implemented local complexType/simpleContent: %s'\
%tp.getItemTrace()
is_complex = complex.content.isComplex()
if is_complex and complex.content.content is None:
# TODO: Recursion...
self.mgContent = ()
self.attrComponents = self._setAttributes(complex.getAttributeContent())
return
if (is_complex and complex.content.content.isExtension() and
complex.content.content.content is not None and
complex.content.content.content.isModelGroup()):
self.mgContent = complex.content.content.content.content
self.attrComponents = self._setAttributes(
complex.content.content.getAttributeContent()
)
return
if (is_complex and complex.content.content.isRestriction() and
complex.content.content.content is not None and
complex.content.content.content.isModelGroup()):
self.mgContent = complex.content.content.content.content
self.attrComponents = self._setAttributes(
complex.content.content.getAttributeContent()
)
return
if is_complex:
self.mgContent = ()
self.attrComponents = self._setAttributes(complex.getAttributeContent())
return
if complex.content.isModelGroup():
self.mgContent = complex.content.content
self.attrComponents = self._setAttributes(complex.getAttributeContent())
return
# TODO: Scary Fallthru
self.mgContent = ()
self.attrComponents = self._setAttributes(complex.getAttributeContent())
class ElementGlobalDefContainer(TypecodeContainerBase):
type = DEC
logger = _GetLogger("ElementGlobalDefContainer")
def _substitutionGroupTag(self):
value = self.substitutionGroup
if not value:
return 'substitutionGroup = None'
nsuri,ncname = value
return 'substitutionGroup = ("%s","%s")' %(nsuri, ncname)
def _setContent(self):
'''GED defines element name, so also define typecode aname
'''
kw = KW.copy()
try:
kw.update(dict(klass=self.getClassName(),
element='ElementDeclaration',
literal=self.literalTag(),
substitutionGroup=self._substitutionGroupTag(),
schema=self.schemaTag(),
init=self.simpleConstructor(),
ns=self.ns, name=self.name,
aname=self.getAttributeName(self.name),
baseslogic=self.getBasesLogic(ID3),
#ofwhat=self.getTypecodeList(),
#atypecode=self.attribute_typecode,
#pyclass=self.getPyClass(),
alias=NAD.getAlias(self.sKlassNS),
subclass=type_class_name(self.sKlass),
))
except Exception, ex:
args = ['Failure processing an element w/local complexType: %s' %(
self._item.getItemTrace())]
args += ex.args
ex.args = tuple(args)
raise
if self.local:
kw['element'] = 'LocalElementDeclaration'
element = [
'%(ID1)sclass %(klass)s(%(element)s):',
'%(ID2)s%(literal)s',
'%(ID2)s%(schema)s',
'%(ID2)s%(substitutionGroup)s',
'%(ID2)s%(init)s',
'%(ID3)skw["pname"] = ("%(ns)s","%(name)s")',
'%(ID3)skw["aname"] = "%(aname)s"',
'%(baseslogic)s',
'%(ID3)s%(alias)s.%(subclass)s.__init__(self, **kw)',
'%(ID3)sif self.pyclass is not None: self.pyclass.__name__ = "%(klass)s_Holder"',
]
self.writeArray(map(lambda l: l %kw, element))
def setUp(self, element):
# Save for debugging
self._item = element
self.local = element.isLocal()
self.name = element.getAttribute('name')
self.substitutionGroup = element.getAttribute('substitutionGroup')
self.ns = element.getTargetNamespace()
tp = element.getTypeDefinition('type')
self.sKlass = tp.getAttribute('name')
self.sKlassNS = tp.getTargetNamespace()
class ComplexTypeComplexContentContainer(TypecodeContainerBase, AttributeMixIn):
'''Represents ComplexType with ComplexContent.
'''
type = DEF
logger = _GetLogger("ComplexTypeComplexContentContainer")
def __init__(self, do_extended=False):
TypecodeContainerBase.__init__(self, do_extended=do_extended)
def setUp(self, tp):
'''complexContent/[extension,restriction]
restriction
extension
extType -- used in figuring attrs for extensions
'''
self._item = tp
assert tp.content.isComplex() is True and \
(tp.content.content.isRestriction() or tp.content.content.isExtension() is True),\
'expecting complexContent/[extension,restriction]'
self.extType = None
self.restriction = False
self.extension = False
self._kw_array = None
self._is_array = False
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
# xxx: what is this for?
#self.attribute_typecode = 'attributes'
derivation = tp.content.content
# Defined in Schema instance?
try:
base = derivation.getTypeDefinition('base')
except XMLSchema.SchemaError, ex:
base = None
# anyType, arrayType, etc...
if base is None:
base = derivation.getAttributeQName('base')
if base is None:
raise ContainerError, 'Unsupported derivation: %s'\
%derivation.getItemTrace()
if base != (SOAP.ENC,'Array') and base != (SCHEMA.XSD3,'anyType'):
raise ContainerError, 'Unsupported base(%s): %s' %(
base, derivation.getItemTrace()
)
if base == (SOAP.ENC,'Array'):
# SOAP-ENC:Array expecting arrayType attribute reference
self.logger.debug("Derivation of soapenc:Array")
self._is_array = True
self._kw_array = {'atype':None, 'id3':ID3, 'ofwhat':None}
self.sKlass = BTI.get_typeclass(base[1], base[0])
self.sKlassNS = base[0]
for a in derivation.getAttributeContent():
assert a.isAttribute() is True,\
'only attribute content expected: %s' %a.getItemTrace()
if a.isReference() is False:
continue
if a.getAttribute('ref') != (SOAP.ENC,'arrayType'):
continue
attr = a.getAttributeQName((WSDL.BASE, 'arrayType'))
if attr is None:
warnings.warn('soapenc:array derivation declares attribute reference ("%s","%s"), does not define attribute ("%s","%s")' %(
SOAP.ENC,'arrayType',WSDL.BASE, 'arrayType'))
break
self._kw_array['atype'] = attr
qname = self._kw_array.get('atype')
if a is not None:
ncname = qname[1].strip('[]')
namespace = qname[0]
try:
ofwhat = a.getSchemaItem(XMLSchema.TYPES, namespace, ncname)
except XMLSchema.SchemaError, ex:
ofwhat = None
if ofwhat is None:
self._kw_array['ofwhat'] = BTI.get_typeclass(ncname, namespace)
else:
self._kw_array['ofwhat'] = GetClassNameFromSchemaItem(ofwhat, do_extended=self.do_extended)
if self._kw_array['ofwhat'] is None:
raise ContainerError, 'For Array could not resolve ofwhat typecode(%s,%s): %s'\
%(namespace, ncname, derivation.getItemTrace())
self.logger.debug('Attribute soapenc:arrayType="%s"' %
str(self._kw_array['ofwhat']))
break
#else:
# raise Wsdl2PythonError, \
# 'derivation of soapenc:array must declare attribute reference ("%s","%s")' %(
# SOAP.ENC,'arrayType')
elif isinstance(base, XMLSchema.XMLSchemaComponent):
self.sKlass = base.getAttribute('name')
self.sKlassNS = base.getTargetNamespace()
else:
# TypeDescriptionComponent
self.sKlass = base.getName()
self.sKlassNS = base.getTargetNamespace()
attrs = []
if derivation.isRestriction():
self.restriction = True
self.extension = False
# derivation.getAttributeContent subset of tp.getAttributeContent
attrs += derivation.getAttributeContent() or ()
else:
self.restriction = False
self.extension = True
attrs += tp.getAttributeContent() or ()
if isinstance(derivation, XMLSchema.XMLSchemaComponent):
attrs += derivation.getAttributeContent() or ()
# XXX: not sure what this is doing
if attrs:
self.extType = derivation
if derivation.content is not None \
and derivation.content.isModelGroup():
group = derivation.content
if group.isReference():
group = group.getModelGroupReference()
self.mgContent = group.content
elif derivation.content:
raise Wsdl2PythonError, \
'expecting model group, not: %s' %derivation.content.getItemTrace()
else:
self.mgContent = ()
self.attrComponents = self._setAttributes(tuple(attrs))
def _setContent(self):
'''JRB What is the difference between instance data
ns, name, -- type definition?
sKlass, sKlassNS? -- element declaration?
'''
kw = KW.copy()
definition = []
if self._is_array:
# SOAP-ENC:Array
if _is_xsd_or_soap_ns(self.sKlassNS) is False and self.sKlass == 'Array':
raise ContainerError, 'unknown type: (%s,%s)'\
%(self.sKlass, self.sKlassNS)
# No need to xsi:type array items since specify with
# SOAP-ENC:arrayType attribute.
definition += [\
'%sclass %s(ZSI.TC.Array, TypeDefinition):' % (ID1, self.getClassName()),
'%s#complexType/complexContent base="SOAP-ENC:Array"' %(ID2),
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
]
append = definition.append
if self._kw_array.get('ofwhat') is None:
append('%s%s.__init__(self, None, None, pname=pname, childnames=\'item\', undeclared=True, **kw)' %(ID3, self.sKlass))
else:
append('%(id3)sofwhat = %(ofwhat)s(None, typed=False)' %self._kw_array)
append('%(id3)satype = %(atype)s' %self._kw_array)
append('%s%s.__init__(self, atype, ofwhat, pname=pname, childnames=\'item\', **kw)' %(ID3, self.sKlass))
self.writeArray(definition)
return
definition += [\
'%sclass %s(TypeDefinition):' % (ID1, self.getClassName()),
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
'%s%s' % (ID3, self.nsuriLogic()),
'%sTClist = [%s]' % (ID3, self.getTypecodeList()),
]
definition.append(
'%(ID3)sattributes = %(atc)s = attributes or {}' %{
'ID3':ID3, 'atc':self.attribute_typecode}
)
#
# Special case: anyType restriction
isAnyType = (self.sKlassNS, self.sKlass) == (SCHEMA.XSD3, 'anyType')
if isAnyType:
del definition[0]
definition.insert(0,
'%sclass %s(ZSI.TC.ComplexType, TypeDefinition):' % (
ID1, self.getClassName())
)
definition.insert(1,
'%s#complexType/complexContent restrict anyType' %(
ID2)
)
# derived type support
definition.append('%sif extend: TClist += ofwhat'%(ID3))
definition.append('%sif restrict: TClist = ofwhat' %(ID3))
if len(self.attrComponents) > 0:
definition.append('%selse:' %(ID3))
for l in self.attrComponents:
definition.append('%s%s'%(ID4, l))
if isAnyType:
definition.append(\
'%sZSI.TC.ComplexType.__init__(self, None, TClist, pname=pname, **kw)' %(
ID3),
)
# pyclass class definition
definition += self.getPyClassDefinition()
kw['pyclass'] = self.getPyClass()
definition.append('%(ID3)sself.pyclass = %(pyclass)s' %kw)
self.writeArray(definition)
return
definition.append('%s' % self.getBasesLogic(ID3))
prefix = NAD.getAlias(self.sKlassNS)
typeClassName = type_class_name(self.sKlass)
if self.restriction:
definition.append(\
'%s%s.%s.__init__(self, pname, ofwhat=TClist, restrict=True, **kw)' %(
ID3, prefix, typeClassName),
)
definition.insert(1, '%s#complexType/complexContent restriction' %ID2)
self.writeArray(definition)
return
if self.extension:
definition.append(\
'%s%s.%s.__init__(self, pname, ofwhat=TClist, extend=True, attributes=attributes, **kw)'%(
ID3, prefix, typeClassName),
)
definition.insert(1, '%s#complexType/complexContent extension' %(ID2))
self.writeArray(definition)
return
raise Wsdl2PythonError,\
'ComplexContent must be a restriction or extension'
def pnameConstructor(self, superclass=None):
if superclass:
return '%s.__init__(self, pname, ofwhat=(), extend=False, restrict=False, attributes=None, **kw)' % superclass
return 'def __init__(self, pname, ofwhat=(), extend=False, restrict=False, attributes=None, **kw):'
class ComplexTypeContainer(TypecodeContainerBase, AttributeMixIn):
'''Represents a global complexType definition.
'''
type = DEF
logger = _GetLogger("ComplexTypeContainer")
def setUp(self, tp, empty=False):
'''Problematic, loose all model group information.
, , ..
tp -- type definition
empty -- no model group, just use as a dummy holder.
'''
self._item = tp
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
self.mixed = tp.isMixed()
self.mgContent = ()
self.attrComponents = self._setAttributes(tp.getAttributeContent())
# Save reference to type for debugging
self._item = tp
if empty:
return
model = tp.content
if model.isReference():
model = model.getModelGroupReference()
if model is None:
return
if model.content is None:
return
# sequence, all or choice
#self.mgContent = model.content
self.mgContent = model
def _setContent(self):
try:
definition = [
'%sclass %s(ZSI.TCcompound.ComplexType, TypeDefinition):'
% (ID1, self.getClassName()),
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
#'%s' % self.getElements(),
'%s%s' % (ID3, self.nsuriLogic()),
'%sTClist = [%s]' % (ID3, self.getTypecodeList()),
]
except Exception, ex:
args = ["Failure processing %s" %self._item.getItemTrace()]
args += ex.args
ex.args = tuple(args)
raise
definition.append('%s%s = attributes or {}' %(ID3,
self.attribute_typecode))
# IF EXTEND
definition.append('%sif extend: TClist += ofwhat'%(ID3))
# IF RESTRICT
definition.append('%sif restrict: TClist = ofwhat' %(ID3))
# ELSE
if len(self.attrComponents) > 0:
definition.append('%selse:' %(ID3))
for l in self.attrComponents: definition.append('%s%s'%(ID4, l))
definition.append(\
'%sZSI.TCcompound.ComplexType.__init__(self, None, TClist, pname=pname, inorder=0, %s**kw)' \
%(ID3, self.getExtraFlags())
)
# pyclass class definition
definition += self.getPyClassDefinition()
# set pyclass
kw = KW.copy()
kw['pyclass'] = self.getPyClass()
definition.append('%(ID3)sself.pyclass = %(pyclass)s' %kw)
self.writeArray(definition)
def pnameConstructor(self, superclass=None):
''' TODO: Logic is a little tricky. If superclass is ComplexType this is not used.
'''
if superclass:
return '%s.__init__(self, pname, ofwhat=(), attributes=None, extend=False, restrict=False, **kw)' % superclass
return 'def __init__(self, pname, ofwhat=(), attributes=None, extend=False, restrict=False, **kw):'
class SimpleTypeContainer(TypecodeContainerBase):
type = DEF
logger = _GetLogger("SimpleTypeContainer")
def __init__(self):
'''
Instance Data From TypecodeContainerBase NOT USED...
mgContent
'''
TypecodeContainerBase.__init__(self)
def setUp(self, tp):
raise NotImplementedError, 'abstract method not implemented'
def _setContent(self, tp):
raise NotImplementedError, 'abstract method not implemented'
def getPythonType(self):
pyclass = eval(str(self.sKlass))
if issubclass(pyclass, ZSI.TC.String):
return 'str'
if issubclass(pyclass, ZSI.TC.Ilong) or issubclass(pyclass, ZSI.TC.IunsignedLong):
return 'long'
if issubclass(pyclass, ZSI.TC.Boolean) or issubclass(pyclass, ZSI.TC.Integer):
return 'int'
if issubclass(pyclass, ZSI.TC.Decimal):
return 'float'
if issubclass(pyclass, ZSI.TC.Gregorian) or issubclass(pyclass, ZSI.TC.Duration):
return 'tuple'
return None
def getPyClassDefinition(self):
definition = []
pt = self.getPythonType()
if pt is not None:
definition.append('%sclass %s(%s):' %(ID3,self.getPyClass(),pt))
definition.append('%stypecode = self' %ID4)
return definition
class RestrictionContainer(SimpleTypeContainer):
'''
simpleType/restriction
'''
logger = _GetLogger("RestrictionContainer")
def setUp(self, tp):
self._item = tp
assert tp.isSimple() is True and tp.isDefinition() is True and \
tp.content.isRestriction() is True,\
'expecting simpleType restriction, not: %s' %tp.getItemTrace()
if tp.content is None:
raise Wsdl2PythonError, \
'empty simpleType defintion: %s' %tp.getItemTrace()
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
self.sKlass = None
base = tp.content.getAttribute('base')
if base is not None:
try:
item = tp.content.getTypeDefinition('base')
except XMLSchema.SchemaError, ex:
item = None
if item is None:
self.sKlass = BTI.get_typeclass(base.getName(), base.getTargetNamespace())
if self.sKlass is not None:
return
raise Wsdl2PythonError('no built-in type nor schema instance type for base attribute("%s","%s"): %s' %(
base.getTargetNamespace(), base.getName(), tp.getItemTrace()))
raise Wsdl2PythonError, \
'Not Supporting simpleType/Restriction w/User-Defined Base: %s %s' %(tp.getItemTrace(),item.getItemTrace())
sc = tp.content.getSimpleTypeContent()
if sc is not None and True is sc.isSimple() is sc.isLocal() is sc.isDefinition():
base = None
if sc.content.isRestriction() is True:
try:
item = tp.content.getTypeDefinition('base')
except XMLSchema.SchemaError, ex:
pass
if item is None:
base = sc.content.getAttribute('base')
if base is not None:
self.sKlass = BTI.get_typeclass(base.getTargetNamespace(), base.getName())
return
raise Wsdl2PythonError, \
'Not Supporting simpleType/Restriction w/User-Defined Base: '\
%item.getItemTrace()
raise Wsdl2PythonError, \
'Not Supporting simpleType/Restriction w/User-Defined Base: '\
%item.getItemTrace()
if sc.content.isList() is True:
raise Wsdl2PythonError, \
'iction base in subtypes: %s'\
%sc.getItemTrace()
if sc.content.isUnion() is True:
raise Wsdl2PythonError, \
'could not get restriction base in subtypes: %s'\
%sc.getItemTrace()
return
raise Wsdl2PythonError, 'No Restriction @base/simpleType: %s' %tp.getItemTrace()
def _setContent(self):
definition = [
'%sclass %s(%s, TypeDefinition):' %(ID1, self.getClassName(),
self.sKlass),
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
]
if self.getPythonType() is None:
definition.append('%s%s.__init__(self, pname, **kw)' %(ID3,
self.sKlass))
else:
definition.append('%s%s.__init__(self, pname, pyclass=None, **kw)' \
%(ID3, self.sKlass,))
# pyclass class definition
definition += self.getPyClassDefinition()
# set pyclass
kw = KW.copy()
kw['pyclass'] = self.getPyClass()
definition.append('%(ID3)sself.pyclass = %(pyclass)s' %kw)
self.writeArray(definition)
class ComplexTypeSimpleContentContainer(SimpleTypeContainer, AttributeMixIn):
'''Represents a ComplexType with simpleContent.
'''
type = DEF
logger = _GetLogger("ComplexTypeSimpleContentContainer")
def setUp(self, tp):
'''tp -- complexType/simpleContent/[Exention,Restriction]
'''
self._item = tp
assert tp.isComplex() is True and tp.content.isSimple() is True,\
'expecting complexType/simpleContent not: %s' %tp.content.getItemTrace()
simple = tp.content
dv = simple.content
assert dv.isExtension() is True or dv.isRestriction() is True,\
'expecting complexType/simpleContent/[Extension,Restriction] not: %s' \
%tp.content.getItemTrace()
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
# TODO: Why is this being set?
self.content.attributeContent = dv.getAttributeContent()
base = dv.getAttribute('base')
if base is not None:
self.sKlass = BTI.get_typeclass( base[1], base[0] )
if not self.sKlass:
self.sKlass,self.sKlassNS = base[1], base[0]
self.attrComponents = self._setAttributes(
self.content.attributeContent
)
return
raise Wsdl2PythonError,\
'simple content derivation bad base attribute: ' %tp.getItemTrace()
def _setContent(self):
# TODO: Add derivation logic to constructors.
if type(self.sKlass) in (types.ClassType, type):
definition = [
'%sclass %s(%s, TypeDefinition):' \
% (ID1, self.getClassName(), self.sKlass),
'%s# ComplexType/SimpleContent derivation of built-in type' %ID2,
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
'%sif getattr(self, "attribute_typecode_dict", None) is None: %s = {}' %(
ID3, self.attribute_typecode),
]
for l in self.attrComponents:
definition.append('%s%s'%(ID3, l))
definition.append('%s%s.__init__(self, pname, **kw)' %(ID3, self.sKlass))
if self.getPythonType() is not None:
definition += self.getPyClassDefinition()
kw = KW.copy()
kw['pyclass'] = self.getPyClass()
definition.append('%(ID3)sself.pyclass = %(pyclass)s' %kw)
self.writeArray(definition)
return
definition = [
'%sclass %s(TypeDefinition):' % (ID1, self.getClassName()),
'%s# ComplexType/SimpleContent derivation of user-defined type' %ID2,
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
'%s%s' % (ID3, self.nsuriLogic()),
'%s' % self.getBasesLogic(ID3),
'%sif getattr(self, "attribute_typecode_dict", None) is None: %s = {}' %(
ID3, self.attribute_typecode),
]
for l in self.attrComponents:
definition.append('%s%s'%(ID3, l))
definition.append('%s%s.%s.__init__(self, pname, **kw)' %(
ID3, NAD.getAlias(self.sKlassNS), type_class_name(self.sKlass)))
self.writeArray(definition)
def getPyClassDefinition(self):
definition = []
pt = self.getPythonType()
if pt is not None:
definition.append('%sclass %s(%s):' %(ID3,self.getPyClass(),pt))
if self.metaclass is not None:
definition.append('%s__metaclass__ = %s' %(ID4, self.metaclass))
definition.append('%stypecode = self' %ID4)
return definition
class UnionContainer(SimpleTypeContainer):
'''SimpleType Union
'''
type = DEF
logger = _GetLogger("UnionContainer")
def __init__(self):
SimpleTypeContainer.__init__(self)
self.memberTypes = None
def setUp(self, tp):
self._item = tp
if tp.content.isUnion() is False:
raise ContainerError, 'content must be a Union: %s' %tp.getItemTrace()
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
self.sKlass = 'ZSI.TC.Union'
self.memberTypes = tp.content.getAttribute('memberTypes')
def _setContent(self):
definition = [
'%sclass %s(%s, TypeDefinition):' \
% (ID1, self.getClassName(), self.sKlass),
'%smemberTypes = %s' % (ID2, self.memberTypes),
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
'%s%s' % (ID3, self.pnameConstructor(self.sKlass)),
]
# TODO: Union pyclass is None
self.writeArray(definition)
class ListContainer(SimpleTypeContainer):
'''SimpleType List
'''
type = DEF
logger = _GetLogger("ListContainer")
def setUp(self, tp):
self._item = tp
if tp.content.isList() is False:
raise ContainerError, 'content must be a List: %s' %tp.getItemTrace()
self.name = tp.getAttribute('name')
self.ns = tp.getTargetNamespace()
self.sKlass = 'ZSI.TC.List'
self.itemType = tp.content.getAttribute('itemType')
def _setContent(self):
definition = [
'%sclass %s(%s, TypeDefinition):' \
% (ID1, self.getClassName(), self.sKlass),
'%sitemType = %s' % (ID2, self.itemType),
'%s%s' % (ID2, self.schemaTag()),
'%s%s' % (ID2, self.typeTag()),
'%s%s' % (ID2, self.pnameConstructor()),
'%s%s' % (ID3, self.pnameConstructor(self.sKlass)),
]
self.writeArray(definition)
ZSI-2.1-a1/ZSI/generate/commands.py 0000644 0001751 0001751 00000046600 10656174245 015150 0 ustar zsi zsi ############################################################################
# Joshua Boverhof, LBNL
# Monte Goode , LBNL
# See Copyright for copyright notice!
############################################################################
import exceptions, sys, optparse, os, warnings, traceback
from os.path import isfile, join, split
#from operator import xor
import ZSI
from ConfigParser import ConfigParser
from ZSI.generate.wsdl2python import WriteServiceModule, ServiceDescription as wsdl2pyServiceDescription
from ZSI.wstools import WSDLTools, XMLSchema
from ZSI.wstools.logging import setBasicLoggerDEBUG
from ZSI.generate import containers, utility
from ZSI.generate.utility import NCName_to_ClassName as NC_to_CN, TextProtect
from ZSI.generate.wsdl2dispatch import ServiceModuleWriter as ServiceDescription
from ZSI.generate.wsdl2dispatch import WSAServiceModuleWriter as ServiceDescriptionWSA
warnings.filterwarnings('ignore', '', exceptions.UserWarning)
def SetDebugCallback(option, opt, value, parser, *args, **kwargs):
setBasicLoggerDEBUG()
warnings.resetwarnings()
def SetPyclassMetaclass(option, opt, value, parser, *args, **kwargs):
"""set up pyclass metaclass for complexTypes"""
from ZSI.generate.containers import ServiceHeaderContainer,\
TypecodeContainerBase, TypesHeaderContainer
TypecodeContainerBase.metaclass = kwargs['metaclass']
TypesHeaderContainer.imports.append(\
'from %(module)s import %(metaclass)s' %kwargs
)
ServiceHeaderContainer.imports.append(\
'from %(module)s import %(metaclass)s' %kwargs
)
def SetUpLazyEvaluation(option, opt, value, parser, *args, **kwargs):
from ZSI.generate.containers import TypecodeContainerBase
TypecodeContainerBase.lazy = True
def wsdl2py(args=None):
"""Utility for automatically generating client/service interface code from
a wsdl definition, and a set of classes representing element declarations
and type definitions. By default invoking this script produces three files,
each named after the wsdl definition name, in the current working directory.
Generated Modules Suffix:
_client.py -- client locator, rpc proxy port, messages
_types.py -- typecodes representing
_server.py -- server-side bindings
Parameters:
args -- optional can provide arguments, rather than parsing
command-line.
return:
Default behavior is to return None, if args are provided then
return names of the generated files.
"""
op = optparse.OptionParser(usage="USAGE: %wsdl2py [options] WSDL",
description=wsdl2py.__doc__)
# Basic options
op.add_option("-x", "--schema",
action="store_true", dest="schema", default=False,
help="process just the schema from an xsd file [no services]")
op.add_option("-d", "--debug",
action="callback", callback=SetDebugCallback,
help="debug output")
# WS Options
op.add_option("-a", "--address",
action="store_true", dest="address", default=False,
help="ws-addressing support, must include WS-Addressing schema.")
# pyclass Metaclass
op.add_option("-b", "--complexType",
action="callback", callback=SetPyclassMetaclass,
callback_kwargs={'module':'ZSI.generate.pyclass',
'metaclass':'pyclass_type'},
help="add convenience functions for complexTypes, including Getters, Setters, factory methods, and properties (via metaclass). *** DONT USE WITH --simple-naming ***")
# Lazy Evaluation of Typecodes (done at serialization/parsing when needed).
op.add_option("-l", "--lazy",
action="callback", callback=SetUpLazyEvaluation,
callback_kwargs={},
help="EXPERIMENTAL: recursion error solution, lazy evalution of typecodes")
# Use Twisted
op.add_option("-w", "--twisted",
action="store_true", dest='twisted', default=False,
help="generate a twisted.web client/server, dependencies python>=2.4, Twisted>=2.0.0, TwistedWeb>=0.5.0")
op.add_option("-o", "--output-dir",
action="store", dest="output_dir", default=".", type="string",
help="save files in directory")
op.add_option("-s", "--simple-naming",
action="store_true", dest="simple_naming", default=False,
help="map element names directly to python attributes")
op.add_option("-p", "--pydoc",
action="store_true", dest="pydoc", default=False,
help="top-level directory for pydoc documentation.")
is_cmdline = args is None
if is_cmdline:
(options, args) = op.parse_args()
else:
(options, args) = op.parse_args(args)
if len(args) != 1:
print>>sys.stderr, 'Expecting a file/url as argument (WSDL).'
sys.exit(os.EX_USAGE)
location = args[0]
if options.schema is True:
reader = XMLSchema.SchemaReader(base_url=location)
else:
reader = WSDLTools.WSDLReader()
load = reader.loadFromFile
if not isfile(location):
load = reader.loadFromURL
try:
wsdl = load(location)
except Exception, e:
print >> sys.stderr, "Error loading %s: \n\t%s" % (location, e)
traceback.print_exc(sys.stderr)
# exit code UNIX specific, Windows?
if hasattr(os, 'EX_NOINPUT'): sys.exit(os.EX_NOINPUT)
sys.exit("error loading %s" %location)
if isinstance(wsdl, XMLSchema.XMLSchema):
wsdl.location = location
files = _wsdl2py(options, wsdl)
else:
files = _wsdl2py(options, wsdl)
files.append(_wsdl2dispatch(options, wsdl))
if getattr(options, 'pydoc', False):
_writepydoc(os.path.join('docs', 'API'), *files)
if is_cmdline:
return
return files
#def wsdl2dispatch(args=None):
# """Deprecated: wsdl2py now generates everything
# A utility for automatically generating service skeleton code from a wsdl
# definition.
# """
# op = optparse.OptionParser()
# op.add_option("-a", "--address",
# action="store_true", dest="address", default=False,
# help="ws-addressing support, must include WS-Addressing schema.")
# op.add_option("-d", "--debug",
# action="callback", callback=SetDebugCallback,
# help="debug output")
# op.add_option("-t", "--types",
# action="store", dest="types", default=None, type="string",
# help="Write generated files to OUTPUT_DIR")
# op.add_option("-o", "--output-dir",
# action="store", dest="output_dir", default=".", type="string",
# help="file to load types from")
# op.add_option("-s", "--simple-naming",
# action="store_true", dest="simple_naming", default=False,
# help="Simplify generated naming.")
#
# if args is None:
# (options, args) = op.parse_args()
# else:
# (options, args) = op.parse_args(args)
#
# if len(args) != 1:
# print>>sys.stderr, 'Expecting a file/url as argument (WSDL).'
# sys.exit(os.EX_USAGE)
#
# reader = WSDLTools.WSDLReader()
# if isfile(args[0]):
# _wsdl2dispatch(options, reader.loadFromFile(args[0]))
# return
#
# _wsdl2dispatch(options, reader.loadFromURL(args[0]))
def _wsdl2py(options, wsdl):
if options.twisted:
from ZSI.generate.containers import ServiceHeaderContainer
try:
ServiceHeaderContainer.imports.remove('from ZSI import client')
except ValueError:
pass
ServiceHeaderContainer.imports.append('from ZSI.twisted import client')
if options.simple_naming:
# Use a different client suffix
# WriteServiceModule.client_module_suffix = "_client"
# Write messages definitions to a separate file.
#wsdl2pyServiceDescription.separate_messages = True
# Use more simple type and element class names
containers.SetTypeNameFunc( lambda n: '%s_' %(NC_to_CN(n)) )
containers.SetElementNameFunc( lambda n: '%s' %(NC_to_CN(n)) )
# Don't add "_" to the attribute name (remove when --aname works well)
containers.ContainerBase.func_aname = lambda instnc,n: TextProtect(str(n))
# write out the modules with their names rather than their number.
utility.namespace_name = lambda cls, ns: utility.Namespace2ModuleName(ns)
files = []
append = files.append
if isinstance(wsdl, XMLSchema.XMLSchema):
wsm = WriteServiceModule(_XMLSchemaAdapter(wsdl.location, wsdl),
addressing=options.address)
else:
wsm = WriteServiceModule(wsdl, addressing=options.address)
client_mod = wsm.getClientModuleName()
client_file = join(options.output_dir, '%s.py' %client_mod)
append(client_file)
fd = open(client_file, 'w+')
wsm.writeClient(fd)
fd.close()
types_mod = wsm.getTypesModuleName()
types_file = join(options.output_dir, '%s.py' %types_mod)
append(types_file)
fd = open(types_file, 'w+' )
wsm.writeTypes(fd)
fd.close()
return files
def _wsdl2dispatch(options, wsdl):
"""TOOD: Remove ServiceContainer stuff, and replace with WSGI.
"""
kw = dict()
if options.twisted:
from ZSI.twisted.WSresource import WSResource
kw['base'] = WSResource
ss = ServiceDescription(**kw)
if options.address is True:
raise RuntimeError, 'WS-Address w/twisted currently unsupported, edit the "factory" attribute by hand'
else:
# TODO: make all this handler arch
if options.address is True:
ss = ServiceDescriptionWSA()
else:
ss = ServiceDescription(**kw)
ss.fromWSDL(wsdl)
file_name = ss.getServiceModuleName()+'.py'
fd = open( join(options.output_dir, file_name), 'w+')
ss.write(fd)
fd.close()
return file_name
class _XMLSchemaAdapter:
"""Adapts an obj XMLSchema.XMLSchema to look like a WSDLTools.WSDL,
just setting a couple attributes code expects to see.
"""
def __init__(self, location, schema):
"""Parameters:
location -- base location, file path
schema -- XMLSchema instance
"""
self.name = '_'.join(split(location)[-1].split('.'))
self.types = {schema.targetNamespace:schema}
import os, pydoc, sys, warnings, inspect
import os.path
from distutils import log
from distutils.command.build_py import build_py
from distutils.util import convert_path
#from setuptools import find_packages
#from setuptools import Command
from ZSI.schema import ElementDeclaration, TypeDefinition
#from pyGridWare.utility.generate.Modules import NR
#from pyGridWare.utility.generate.Modules import CLIENT, TYPES
#def find_packages_modules(where='.'):
# #pack,mod,mod_file
# """Return a list all Python packages found within directory 'where'
# """
# out = []
# stack=[(convert_path(where), '')]
# while stack:
# where,prefix = stack.pop(0)
# for name in os.listdir(where):
# fn = os.path.join(where,name)
# #if (os.path.isdir(fn) and
# # os.path.isfile(os.path.join(fn,'__init__.py'))
# #):
# # out.append(prefix+name); stack.append((fn,prefix+name+'.'))
# if (os.path.isdir(fn) and
# os.path.isfile(os.path.join(fn,'__init__.py'))):
# stack.append((fn,prefix+name+'.'))
# continue
#
# if name == '__init__.py' or not name.endswith('.py'):
# continue
#
# out.append((prefix, name.split('.py')[0]))
#
# return out
def _writedoc(doc, thing, forceload=0):
"""Write HTML documentation to a file in the current directory.
"""
try:
object, name = pydoc.resolve(thing, forceload)
page = pydoc.html.page(pydoc.describe(object), pydoc.html.document(object, name))
fname = os.path.join(doc, name + '.html')
file = open(fname, 'w')
file.write(page)
file.close()
except (ImportError, pydoc.ErrorDuringImport), value:
traceback.print_exc(sys.stderr)
else:
return name + '.html'
def _writeclientdoc(doc, thing, forceload=0):
"""Write HTML documentation to a file in the current directory.
"""
docmodule = pydoc.HTMLDoc.docmodule
def strongarm(self, object, name=None, mod=None, *ignored):
result = docmodule(self, object, name, mod, *ignored)
# Grab all the aliases to pyclasses and create links.
nonmembers = []
push = nonmembers.append
for k,v in inspect.getmembers(object, inspect.isclass):
if inspect.getmodule(v) is not object and getattr(v,'typecode',None) is not None:
push('%s: pyclass alias ' %(v.__name__,k))
result += self.bigsection('Aliases', '#ffffff', '#eeaa77', ''.join(nonmembers))
return result
pydoc.HTMLDoc.docmodule = strongarm
try:
object, name = pydoc.resolve(thing, forceload)
page = pydoc.html.page(pydoc.describe(object), pydoc.html.document(object, name))
name = os.path.join(doc, name + '.html')
file = open(name, 'w')
file.write(page)
file.close()
except (ImportError, pydoc.ErrorDuringImport), value:
log.debug(str(value))
pydoc.HTMLDoc.docmodule = docmodule
def _writetypesdoc(doc, thing, forceload=0):
"""Write HTML documentation to a file in the current directory.
"""
try:
object, name = pydoc.resolve(thing, forceload)
name = os.path.join(doc, name + '.html')
except (ImportError, pydoc.ErrorDuringImport), value:
log.debug(str(value))
return
# inner classes
cdict = {}
fdict = {}
elements_dict = {}
types_dict = {}
for kname,klass in inspect.getmembers(thing, inspect.isclass):
if thing is not inspect.getmodule(klass):
continue
cdict[kname] = inspect.getmembers(klass, inspect.isclass)
for iname,iklass in cdict[kname]:
key = (kname,iname)
fdict[key] = _writedoc(doc, iklass)
if issubclass(iklass, ElementDeclaration):
try:
typecode = iklass()
except (AttributeError,RuntimeError), ex:
elements_dict[iname] = _writebrokedoc(doc, ex, iname)
continue
elements_dict[iname] = None
if typecode.pyclass is not None:
elements_dict[iname] = _writedoc(doc, typecode.pyclass)
continue
if issubclass(iklass, TypeDefinition):
try:
typecode = iklass(None)
except (AttributeError,RuntimeError), ex:
types_dict[iname] = _writebrokedoc(doc, ex, iname)
continue
types_dict[iname] = None
if typecode.pyclass is not None:
types_dict[iname] = _writedoc(doc, typecode.pyclass)
continue
def strongarm(self, object, name=None, mod=None, funcs={}, classes={}, *ignored):
"""Produce HTML documentation for a class object."""
realname = object.__name__
name = name or realname
bases = object.__bases__
object, name = pydoc.resolve(object, forceload)
contents = []
push = contents.append
if name == realname:
title = 'class %s' % (
name, realname)
else:
title = '%s = class %s' % (
name, name, realname)
mdict = {}
if bases:
parents = []
for base in bases:
parents.append(self.classlink(base, object.__module__))
title = title + '(%s)' % pydoc.join(parents, ', ')
doc = self.markup(pydoc.getdoc(object), self.preformat, funcs, classes, mdict)
doc = doc and '%s ' % doc
for iname,iclass in cdict[name]:
fname = fdict[(name,iname)]
if elements_dict.has_key(iname):
push('class %s: element declaration typecode '\
%(fname,iname))
pyclass = elements_dict[iname]
if pyclass is not None:
push('
')
elif types_dict.has_key(iname):
push('class %s: type definition typecode ' %(fname,iname))
pyclass = types_dict[iname]
if pyclass is not None:
push('