diff options
Diffstat (limited to 'suds')
-rw-r--r-- | suds/bindings/binding.py | 24 | ||||
-rw-r--r-- | suds/bindings/rpc.py | 4 | ||||
-rw-r--r-- | suds/cache.py | 194 | ||||
-rw-r--r-- | suds/client.py | 12 | ||||
-rw-r--r-- | suds/mx/encoded.py | 2 | ||||
-rw-r--r-- | suds/mx/literal.py | 9 | ||||
-rw-r--r-- | suds/reader.py | 76 | ||||
-rw-r--r-- | suds/wsdl.py | 142 | ||||
-rw-r--r-- | suds/xsd/schema.py | 49 | ||||
-rw-r--r-- | suds/xsd/sxbasic.py | 24 |
10 files changed, 309 insertions, 227 deletions
diff --git a/suds/bindings/binding.py b/suds/bindings/binding.py index c2e7810..a6d421e 100644 --- a/suds/bindings/binding.py +++ b/suds/bindings/binding.py @@ -61,10 +61,14 @@ class Binding: @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl - self.schema = wsdl.schema - self.options = wsdl.options self.multiref = MultiRef() + def schema(self): + return self.wsdl.schema + + def options(self): + return self.wsdl.options + def unmarshaller(self, typed=True): """ Get the appropriate XML decoder. @@ -72,7 +76,7 @@ class Binding: @rtype: L{UmxTyped} """ if typed: - return UmxTyped(self.schema) + return UmxTyped(self.schema()) else: return UmxBasic() @@ -82,7 +86,7 @@ class Binding: @return: An L{MxLiteral} marshaller. @rtype: L{MxLiteral} """ - return MxLiteral(self.schema) + return MxLiteral(self.schema(), self.options().xstq) def param_defs(self, method): """ @@ -114,7 +118,7 @@ class Binding: content = self.bodycontent(method, args, kwargs) body = self.body(content) env = self.envelope(header, body) - if self.options.prefixes: + if self.options().prefixes: body.normalizePrefixes() env.promotePrefixes() else: @@ -230,7 +234,7 @@ class Binding: fault = soapbody.getChild('Fault') unmarshaller = self.unmarshaller(False) p = unmarshaller.process(fault) - if self.options.faults: + if self.options().faults: raise WebFault(p, faultroot) return (faultroot, p.detail) @@ -329,10 +333,10 @@ class Binding: """ n = 0 content = [] - wsse = self.options.wsse + wsse = self.options().wsse if wsse is not None: content.append(wsse.xml()) - headers = self.options.soapheaders + headers = self.options().soapheaders if not isinstance(headers, (tuple,list,dict)): headers = (headers,) if len(headers) == 0: @@ -405,7 +409,7 @@ class Binding: query = ElementQuery(p.element) else: query = TypeQuery(p.type) - pt = query.execute(self.schema) + pt = query.execute(self.schema()) if pt is None: raise TypeNotFound(query.ref) if p.type is not None: @@ -441,7 +445,7 @@ class Binding: query = ElementQuery(part.element) else: query = TypeQuery(part.type) - pt = query.execute(self.schema) + pt = query.execute(self.schema()) if pt is None: raise TypeNotFound(query.ref) if part.type is not None: diff --git a/suds/bindings/rpc.py b/suds/bindings/rpc.py index 9acd3e1..f780aa4 100644 --- a/suds/bindings/rpc.py +++ b/suds/bindings/rpc.py @@ -84,7 +84,7 @@ class Encoded(RPC): """ def marshaller(self): - return MxEncoded(self.schema) + return MxEncoded(self.schema()) def unmarshaller(self, typed=True): """ @@ -93,6 +93,6 @@ class Encoded(RPC): @rtype: L{UmxTyped} """ if typed: - return UmxEncoded(self.schema) + return UmxEncoded(self.schema()) else: return RPC.unmarshaller(self, typed) diff --git a/suds/cache.py b/suds/cache.py index 80764dc..661bf27 100644 --- a/suds/cache.py +++ b/suds/cache.py @@ -33,49 +33,85 @@ except: log = getLogger(__name__) -class ByteCache: +class Cache: """ - The URL caching object. + An object object cache. """ + + def get(self, id): + """ + Get a object from the cache by ID. + @param id: The object ID. + @type id: str + @return: The object, else None + @rtype: any + """ + raise Exception('not-implemented') - def put(self, id, fp): + def getf(self, id): """ - Put an item into the cache. - @param id: A file ID. + Get a object from the cache by ID. + @param id: The object ID. @type id: str - @param fp: A file stream. - @type fp: stream - @return: The stream. - @rtype: stream + @return: The object, else None + @rtype: any """ raise Exception('not-implemented') - def get(self, id): + def put(self, id, object): + """ + Put a object into the cache. + @param id: The object ID. + @type id: str + @param object: The object to add. + @type object: any + """ + raise Exception('not-implemented') + + def putf(self, id, fp): """ - Get an item from the cache by id. - @param id: A file ID. + Write a fp into the cache. + @param id: The object ID. @type id: str - @return: A stream when found, else None. - @rtype: stream + @param fp: File pointer. + @type fp: file-like object. """ raise Exception('not-implemented') def purge(self, id): """ - Purge a file from the cache by id. - @param id: A file ID. + Purge a object from the cache by id. + @param id: A object ID. @type id: str """ raise Exception('not-implemented') def clear(self): """ - Clear the cache. + Clear all objects from the cache. """ raise Exception('not-implemented') + + +class NoCache(Cache): + """ + The passthru object cache. + """ + + def get(self, id): + return None + + def getf(self, id): + return None + + def put(self, id, object): + pass + + def putf(self, id, fp): + pass -class FileCache(ByteCache): +class FileCache(Cache): """ A file-based URL cache. @cvar fnprefix: The file name prefix. @@ -89,6 +125,7 @@ class FileCache(ByteCache): @type location: str """ fnprefix = 'suds' + fnsuffix = 'gcf' units = ('months', 'weeks', 'days', 'hours', 'minutes', 'seconds') def __init__(self, location=None, **duration): @@ -100,7 +137,6 @@ class FileCache(ByteCache): The duration may be: (months|weeks|days|hours|minutes|seconds). @type duration: {unit:value} """ - self.fnsuffix = 'xml' if location is None: location = os.path.join(tmp(), 'suds') self.location = location @@ -142,25 +178,45 @@ class FileCache(ByteCache): log.debug(self.location, exc_info=1) return self - def put(self, id, fp): + def put(self, id, bfr): + try: + fn = self.__fn(id) + f = self.open(fn, 'w') + f.write(bfr) + f.close() + return bfr + except: + log.debug(id, exc_info=1) + return fp + + def putf(self, id, fp): try: fn = self.__fn(id) f = self.open(fn, 'w') f.write(fp.read()) f.close() - return open(fn) + return fp except: log.debug(id, exc_info=1) return fp - + def get(self, id): try: + f = self.getf(id) + bfr = f.read() + f.close() + return bfr + except: + pass + + def getf(self, id): + try: fn = self.__fn(id) self.validate(fn) return self.open(fn) except: pass - + def validate(self, fn): """ Validate that the file has not expired based on the I{duration}. @@ -199,91 +255,35 @@ class FileCache(ByteCache): return open(fn, *args) def __fn(self, id): - fn = '%s-%s.%s' % (self.fnprefix, abs(hash(id)), self.fnsuffix) + if hasattr(id, 'name') and hasattr(id, 'suffix'): + name = id.name + suffix = id.suffix + else: + name = id + suffix = self.fnsuffix + fn = '%s-%s.%s' % (self.fnprefix, abs(hash(name)), suffix) return os.path.join(self.location, fn) -class Cache: - """ - The XML document cache. - """ - - def get(self, id): - """ - Get a document from the store by ID. - @param id: The document ID. - @type id: str - @return: The document, else None - @rtype: I{Document} - """ - raise Exception('not-implemented') - - def put(self, id, document): - """ - Put a document into the store. - @param id: The document ID. - @type id: str - @param document: The document to add. - @type document: I{Document} - """ - raise Exception('not-implemented') - - def purge(self, id): - """ - Purge a document from the cache by id. - @param id: A document ID. - @type id: str - """ - raise Exception('not-implemented') - - def clear(self): - """ - Clear all documents from the cache. - """ - raise Exception('not-implemented') - - -class NoCache(Cache): +class ObjectCache(FileCache): """ - The passthru document cache. + Provides pickled object caching. + @cvar protocol: The pickling protocol. + @type protocol: int """ - - def get(self, id): - return None - - def put(self, id, document): - pass - - -class DocumentStore(Cache): - - def __init__(self, location=None, **duration): - """ - @param location: The directory for the cached documents. - @type location: str - @param duration: The cached file duration which defines how - long the document will be cached. A duration=0 means forever. - The duration may be: (months|weeks|days|hours|minutes|seconds). - @type duration: {unit:value} - """ - cache = FileCache(location, **duration) - cache.fnsuffix = 'pxd' - self.cache = cache + protocol = 2 def get(self, id): try: - fp = self.cache.get(id) + fp = FileCache.getf(self, id) if fp is None: return None else: return pickle.load(fp) except: - self.cache.purge(id) + FileCache.purge(self, id) - def put(self, id, document): - ostr = StringIO() - pickle.dump(document, ostr) - istr = StringIO(ostr.getvalue()) - fp = self.cache.put(id, istr) - fp.close() - return document + def put(self, id, object): + bfr = pickle.dumps(object, self.protocol) + FileCache.put(self, id, bfr) + return object diff --git a/suds/client.py b/suds/client.py index 0d7c7f3..b91a7da 100644 --- a/suds/client.py +++ b/suds/client.py @@ -23,6 +23,7 @@ import suds import suds.metrics as metrics from cookielib import CookieJar from suds import * +from suds.reader import DefinitionsReader from suds.transport import TransportError, Request from suds.transport.https import HttpAuthenticated from suds.servicedefinition import ServiceDefinition @@ -32,7 +33,7 @@ from sudsobject import Object from suds.resolver import PathResolver from suds.builder import Builder from suds.wsdl import Definitions -from suds.cache import DocumentStore +from suds.cache import ObjectCache from suds.sax.document import Document from suds.sax.parser import Parser from suds.options import Options @@ -104,9 +105,10 @@ class Client(object): options = Options() options.transport = HttpAuthenticated() self.options = options - options.cache = DocumentStore(days=1) + options.cache = ObjectCache(days=1) self.set_options(**kwargs) - self.wsdl = Definitions(url, options) + reader = DefinitionsReader(options, Definitions) + self.wsdl = reader.open(url) self.factory = Factory(self.wsdl) self.service = ServiceSelector(self, self.wsdl.services) self.sd = [] @@ -587,7 +589,6 @@ class SoapClient: timer.start() result = None binding = self.method.binding.input - binding.options = self.options msg = binding.get_message(self.method, args, kwargs) timer.stop() metrics.log.debug( @@ -750,17 +751,14 @@ class SimClient(SoapClient): def __reply(self, reply, args, kwargs): """ simulate the reply """ binding = self.method.binding.input - binding.options = self.options msg = binding.get_message(self.method, args, kwargs) log.debug('inject (simulated) send message:\n%s', msg) binding = self.method.binding.output - binding.options = self.options return self.succeeded(binding, reply) def __fault(self, reply): """ simulate the (fault) reply """ binding = self.method.binding.output - binding.options = self.options if self.options.faults: r, p = binding.get_fault(reply) self.last_received(r) diff --git a/suds/mx/encoded.py b/suds/mx/encoded.py index 93fe444..9cbc8c5 100644 --- a/suds/mx/encoded.py +++ b/suds/mx/encoded.py @@ -87,7 +87,7 @@ class Encoded(Literal): return ns = None name = content.real.name - if self.options.xstq: + if self.xstq: ns = content.real.namespace() Typer.manual(node, name, ns) diff --git a/suds/mx/literal.py b/suds/mx/literal.py index 706d14a..937ad8e 100644 --- a/suds/mx/literal.py +++ b/suds/mx/literal.py @@ -53,14 +53,17 @@ class Typed(Core): @type resolver: L{GraphResolver} """ - def __init__(self, schema): + def __init__(self, schema, xstq=True): """ @param schema: A schema object @type schema: L{xsd.schema.Schema} + @param xstq: The B{x}ml B{s}chema B{t}ype B{q}ualified flag indicates + that the I{xsi:type} attribute values should be qualified by namespace. + @type xstq: bool """ Core.__init__(self) self.schema = schema - self.options = schema.options + self.xstq = xstq self.resolver = GraphResolver(self.schema) def reset(self): @@ -190,7 +193,7 @@ class Typed(Core): return ns = None name = content.real.name - if self.options.xstq: + if self.xstq: ns = content.real.namespace('ns1') Typer.manual(node, name, ns) diff --git a/suds/reader.py b/suds/reader.py index 16eff1f..70a7074 100644 --- a/suds/reader.py +++ b/suds/reader.py @@ -21,13 +21,31 @@ Contains xml document reader classes. from suds.sax.parser import Parser from suds.transport import Request +from logging import getLogger + + +log = getLogger(__name__) + + +class ObjectId(object): + + def __init__(self, name, suffix): + self.name = name + self.suffix = suffix + class DocumentReader: """ The XML document reader provides an integration between the SAX L{Parser} and the document cache. + @cvar suffix: The cache file suffix. + @type suffix: str + @ivar options: An options object. + @type options: I{Options} """ + suffix = 'pxd' + def __init__(self, options): """ @param options: An options object. @@ -39,18 +57,68 @@ class DocumentReader: """ Open an XML document at the specified I{url}. First, the document attempted to be retrieved from - the I{document cache}. If not found, it is downloaded and + the I{object cache}. If not found, it is downloaded and parsed using the SAX parser. The result is added to the - document store for the next open(). + cache for the next open(). @param url: A document url. @type url: str. @return: The specified XML document. @rtype: I{Document} """ - d = self.options.cache.get(url) + id = ObjectId(url, self.suffix) + cache = self.options.cache + d = cache.get(id) if d is None: fp = self.options.transport.open(Request(url)) sax = Parser() d = sax.parse(file=fp) - self.options.cache.put(url, d) + cache.put(id, d) return d + + +class DefinitionsReader: + """ + The WSDL definitions reader provides an integration + between the Definitions and the object cache. + @cvar suffix: The cache file suffix. + @type suffix: str + @ivar options: An options object. + @type options: I{Options} + @ivar fn: A factory function (constructor) used to + create the object not found in the cache. + @type fn: I{Constructor} + """ + + suffix = 'pw' + + def __init__(self, options, fn): + """ + @param options: An options object. + @type options: I{Options} + @param fn: A factory function (constructor) used to + create the object not found in the cache. + @type fn: I{Constructor} + """ + self.options = options + self.fn = fn + + def open(self, url): + """ + Open a WSDL at the specified I{url}. + First, the WSDL attempted to be retrieved from + the I{object cache}. If not found, it is downloaded and + instantiated using the I{fn} constructor. The result is added + to the cache for the next open(). + @param url: A WSDL url. + @type url: str. + @return: The WSDL object. + @rtype: I{Definitions} + """ + id = ObjectId(url, self.suffix) + cache = self.options.cache + d = cache.get(id) + if d is None: + d = self.fn(url, self.options) + cache.put(id, d) + d.options = self.options + return d
\ No newline at end of file diff --git a/suds/wsdl.py b/suds/wsdl.py index 558f8be..c3e47be 100644 --- a/suds/wsdl.py +++ b/suds/wsdl.py @@ -29,9 +29,8 @@ from suds.bindings.rpc import RPC, Encoded from suds.xsd import qualify, Namespace from suds.xsd.schema import Schema, SchemaCollection from suds.xsd.query import ElementQuery -from suds.sudsobject import Object -from suds.sudsobject import Factory as SFactory -from suds.reader import DocumentReader +from suds.sudsobject import Object, Facade, Metadata +from suds.reader import DocumentReader, DefinitionsReader from urlparse import urljoin import re, soaparray @@ -42,41 +41,6 @@ soapns = (None, 'http://schemas.xmlsoap.org/wsdl/soap/') soap12ns = (None, 'http://schemas.xmlsoap.org/wsdl/soap12/') -class Factory: - """ - Simple WSDL object factory. - @cvar tags: Dictionary of tag->constructor mappings. - @type tags: dict - """ - - tags =\ - { - 'import' : lambda x,y: Import(x,y), - 'types' : lambda x,y: Types(x,y), - 'message' : lambda x,y: Message(x,y), - 'portType' : lambda x,y: PortType(x,y), - 'binding' : lambda x,y: Binding(x,y), - 'service' : lambda x,y: Service(x,y), - } - - @classmethod - def create(cls, root, definitions): - """ - Create an object based on the root tag name. - @param root: An XML root element. - @type root: L{Element} - @param definitions: A definitions object. - @type definitions: L{Definitions} - @return: The created object. - @rtype: L{WObject} - """ - fn = cls.tags.get(root.name) - if fn is not None: - return fn(root, definitions) - else: - return None - - class WObject(Object): """ Base object for wsdl types. @@ -93,9 +57,9 @@ class WObject(Object): """ Object.__init__(self) self.root = root - pmd = SFactory.metadata() + pmd = Metadata() pmd.excludes = ['root'] - pmd.wrappers = dict(qname=lambda x: repr(x)) + pmd.wrappers = dict(qname=repr) self.__metadata__.__print__ = pmd def resolve(self, definitions): @@ -127,7 +91,7 @@ class NamedObject(WObject): self.name = root.get('name') self.qname = (self.name, definitions.tns[1]) pmd = self.__metadata__.__print__ - pmd.wrappers['qname'] = lambda x: repr(x) + pmd.wrappers['qname'] = repr class Definitions(WObject): @@ -189,7 +153,7 @@ class Definitions(WObject): pmd = self.__metadata__.__print__ pmd.excludes.append('children') pmd.excludes.append('wsdl') - pmd.wrappers['schema'] = lambda x: repr(x) + pmd.wrappers['schema'] = repr self.open_imports() self.resolve() self.build_schema() @@ -246,14 +210,14 @@ class Definitions(WObject): """ Process L{Types} objects and create the schema collection """ container = SchemaCollection(self) for t in [t for t in self.types if t.local()]: - for r in t.contents(): - entry = (r, self) - container.add(entry) + for root in t.contents(): + schema = Schema(root, self.url, self.options, container) + container.add(schema) if not len(container): # empty - r = Element.buildPath(self.root, 'types/schema') - entry = (r, self) - container.add(entry) - self.schema = container.load() + root = Element.buildPath(self.root, 'types/schema') + schema = Schema(root, self.url, self.options, container) + container.add(schema) + self.schema = container.load(self.options) for s in [t.schema() for t in self.types if t.imported()]: self.schema.merge(s) return self.schema @@ -270,10 +234,10 @@ class Definitions(WObject): ptype = p.binding.type operations = p.binding.type.operations.values() for name in [op.name for op in operations]: - m = SFactory.object('Method') + m = Facade('Method') m.name = name m.location = p.location - m.binding = SFactory.object('binding') + m.binding = Facade('binding') op = binding.operation(name) m.soap = op.soap key = '/'.join((op.soap.style, op.soap.input.body.use)) @@ -302,7 +266,11 @@ class Definitions(WObject): if resolved.builtin(): continue body.wrapped = True - + + def __getstate__(self): + d = self.__dict__.copy() + del d['options'] + return d class Import(WObject): @@ -316,6 +284,9 @@ class Import(WObject): @type imported: L{Definitions} """ + def getid(x): + return x.id + def __init__(self, root, definitions): """ @param root: An XML root element. @@ -328,7 +299,7 @@ class Import(WObject): self.ns = root.get('namespace') self.imported = None pmd = self.__metadata__.__print__ - pmd.wrappers['imported'] = ( lambda x: x.id ) + pmd.wrappers['imported'] = getid def load(self, definitions): """ Load the object by opening the URL """ @@ -336,7 +307,8 @@ class Import(WObject): log.debug('importing (%s)', url) if '://' not in url: url = urljoin(definitions.url, url) - d = Definitions(url, definitions.options) + reader = DefinitionsReader(definitions.options, Definitions) + d = reader.open(url) if d.root.match(Definitions.Tag, wsdlns): self.import_definitions(definitions, d) return @@ -424,9 +396,8 @@ class Part(NamedObject): @type definitions: L{Definitions} """ NamedObject.__init__(self, root, definitions) - pmd = SFactory.metadata() - pmd.wrappers = \ - dict(element=lambda x: repr(x), type=lambda x: repr(x)) + pmd = Metadata() + pmd.wrappers = dict(element=repr, type=repr) self.__metadata__.__print__ = pmd tns = definitions.tns self.element = self.__getref('element', tns) @@ -482,7 +453,7 @@ class PortType(NamedObject): NamedObject.__init__(self, root, definitions) self.operations = {} for c in root.getChildren('operation'): - op = SFactory.object('Operation') + op = Facade('Operation') op.name = c.get('name') op.tns = definitions.tns input = c.getChild('input') @@ -497,7 +468,7 @@ class PortType(NamedObject): op.output = output.get('message') faults = [] for fault in c.getChildren('fault'): - f = SFactory.object('Fault') + f = Facade('Fault') f.name = fault.get('name') f.message = fault.get('message') faults.append(f) @@ -576,7 +547,7 @@ class Binding(NamedObject): self.soap = None log.debug('binding: "%s" not a soap binding', self.name) return - soap = SFactory.object('soap') + soap = Facade('soap') self.soap = soap self.soap.style = sr.get('style', default='document') self.add_operations(self.root, definitions) @@ -593,17 +564,17 @@ class Binding(NamedObject): """ Add <operation/> children """ dsop = Element('operation', ns=soapns) for c in root.getChildren('operation'): - op = SFactory.object('Operation') + op = Facade('Operation') op.name = c.get('name') sop = c.getChild('operation', default=dsop) - soap = SFactory.object('soap') + soap = Facade('soap') soap.action = '"%s"' % sop.get('soapAction', default='') soap.style = sop.get('style', default=self.soap.style) - soap.input = SFactory.object('Input') - soap.input.body = SFactory.object('Body') + soap.input = Facade('Input') + soap.input.body = Facade('Body') soap.input.headers = [] - soap.output = SFactory.object('Output') - soap.output.body = SFactory.object('Body') + soap.output = Facade('Output') + soap.output.body = Facade('Body') soap.output.headers = [] op.soap = soap input = c.getChild('input') @@ -626,7 +597,7 @@ class Binding(NamedObject): if sf is None: continue fn = fault.get('name') - f = SFactory.object('Fault') + f = Facade('Fault') f.name = sf.get('name', default=fn) f.use = sf.get('use', default='literal') faults.append(f) @@ -657,7 +628,7 @@ class Binding(NamedObject): """ add the input/output header properties """ if root is None: return - header = SFactory.object('Header') + header = Facade('Header') parent.headers.append(header) header.use = root.get('use', default='literal') ns = root.get('namespace') @@ -911,3 +882,38 @@ class Service(NamedObject): def __gt__(self, other): return True + + +class Factory: + """ + Simple WSDL object factory. + @cvar tags: Dictionary of tag->constructor mappings. + @type tags: dict + """ + + tags =\ + { + 'import' : Import, + 'types' : Types, + 'message' : Message, + 'portType' : PortType, + 'binding' : Binding, + 'service' : Service, + } + + @classmethod + def create(cls, root, definitions): + """ + Create an object based on the root tag name. + @param root: An XML root element. + @type root: L{Element} + @param definitions: A definitions object. + @type definitions: L{Definitions} + @return: The created object. + @rtype: L{WObject} + """ + fn = cls.tags.get(root.name) + if fn is not None: + return fn(root, definitions) + else: + return None diff --git a/suds/xsd/schema.py b/suds/xsd/schema.py index 2998cc4..a22f1c5 100644 --- a/suds/xsd/schema.py +++ b/suds/xsd/schema.py @@ -55,7 +55,6 @@ class SchemaCollection: @type wsdl: L{suds.wsdl.Definitions} """ self.wsdl = wsdl - self.options = wsdl.options self.children = [] self.namespaces = {} @@ -63,34 +62,34 @@ class SchemaCollection: """ Add a schema node to the collection. Schema(s) within the same target namespace are consolidated. - @param schema: A <schema/> entry. - @type schema: (L{suds.wsdl.Definitions},L{sax.element.Element}) + @param schema: A schema object. + @type schema: (L{Schema}) """ - root, wsdl = schema - child = Schema(root, wsdl.url, self.options, container=self) - key = child.tns[1] + key = schema.tns[1] existing = self.namespaces.get(key) if existing is None: - self.children.append(child) - self.namespaces[key] = child + self.children.append(schema) + self.namespaces[key] = schema else: - existing.root.children += root.children - existing.root.nsprefixes.update(root.nsprefixes) + existing.root.children += schema.root.children + existing.root.nsprefixes.update(schema.root.nsprefixes) - def load(self): + def load(self, options): """ Load the schema objects for the root nodes. - de-references schemas - merge schemas + @param options: An options dictionary. + @type options: L{options.Options} @return: The merged schema. @rtype: L{Schema} """ - if self.options.autoblend: + if options.autoblend: self.autoblend() for child in self.children: child.build() for child in self.children: - child.open_imports() + child.open_imports(options) for child in self.children: child.dereference() log.debug('loaded:\n%s', self) @@ -165,8 +164,6 @@ class Schema: @type root: L{sax.element.Element} @ivar baseurl: The I{base} URL for this schema. @type baseurl: str - @ivar options: An options dictionary. - @type options: L{options.Options} @ivar container: A schema collection containing this schema. @type container: L{SchemaCollection} @ivar types: A schema types cache. @@ -201,7 +198,6 @@ class Schema: self.id = objid(self) self.tns = self.mktns() self.baseurl = baseurl - self.options = options self.container = container self.children = [] self.all = [] @@ -211,9 +207,8 @@ class Schema: self.attributes = {} self.groups = {} self.agrps = {} - doctor = self.options.doctor - if doctor is not None: - doctor.examine(root) + if options.doctor is not None: + options.doctor.examine(root) form = self.root.get('elementFormDefault') if form is None: self.form_qualified = False @@ -221,7 +216,7 @@ class Schema: self.form_qualified = ( form == 'qualified' ) if container is None: self.build() - self.open_imports() + self.open_imports(options) log.debug('built:\n%s', self) self.dereference() log.debug('dereferenced:\n%s', self) @@ -291,17 +286,19 @@ class Schema: schema.merged = True return self - def open_imports(self): + def open_imports(self, options): """ Instruct all contained L{sxbasic.Import} children to import the schema's which they reference. The contents of the imported schema are I{merged} in. + @param options: An options dictionary. + @type options: L{options.Options} """ for imp in self.imports: - imported = imp.open() + imported = imp.open(options) if imported is None: continue - imported.open_imports() + imported.open_imports(options) log.debug('imported:\n%s', imported) self.merge(imported) @@ -376,7 +373,7 @@ class Schema: except: return False - def instance(self, root, baseurl): + def instance(self, root, baseurl, options): """ Create and return an new schema object using the specified I{root} and I{url}. @@ -384,11 +381,13 @@ class Schema: @type root: L{sax.element.Element} @param baseurl: A base URL. @type baseurl: str + @param options: An options dictionary. + @type options: L{options.Options} @return: The newly created schema object. @rtype: L{Schema} @note: This is only used by Import children. """ - return Schema(root, baseurl, self.options) + return Schema(root, baseurl, options) def str(self, indent=0): tab = '%*s'%(indent*3, '') diff --git a/suds/xsd/sxbasic.py b/suds/xsd/sxbasic.py index d58dfff..a10e0cd 100644 --- a/suds/xsd/sxbasic.py +++ b/suds/xsd/sxbasic.py @@ -495,9 +495,11 @@ class Import(SchemaObject): self.location = self.locations.get(self.ns[1]) self.opened = False - def open(self): + def open(self, options): """ Open and import the refrenced schema. + @param options: An options dictionary. + @type options: L{options.Options} @return: The referenced schema. @rtype: L{Schema} """ @@ -510,7 +512,7 @@ class Import(SchemaObject): if self.location is None: log.debug('imported schema (%s) not-found', self.ns[1]) else: - result = self.download() + result = self.download(options) log.debug('imported:\n%s', result) return result @@ -521,17 +523,17 @@ class Import(SchemaObject): else: return self.schema.locate(self.ns) - def download(self): + def download(self, options): """ download the schema """ url = self.location try: if '://' not in url: url = urljoin(self.schema.baseurl, url) - reader = DocumentReader(self.schema.options) + reader = DocumentReader(options) d = reader.open(url) root = d.root() root.set('url', url) - return self.schema.instance(root, url) + return self.schema.instance(root, url, options) except TransportError: msg = 'imported schema (%s) at (%s), failed' % (self.ns[1], url) log.error('%s, %s', self.id, msg, exc_info=True) @@ -559,9 +561,11 @@ class Include(SchemaObject): self.location = self.locations.get(self.ns[1]) self.opened = False - def open(self): + def open(self, options): """ Open and include the refrenced schema. + @param options: An options dictionary. + @type options: L{options.Options} @return: The referenced schema. @rtype: L{Schema} """ @@ -569,22 +573,22 @@ class Include(SchemaObject): return self.opened = True log.debug('%s, including location="%s"', self.id, self.location) - result = self.download() + result = self.download(options) log.debug('included:\n%s', result) return result - def download(self): + def download(self, options): """ download the schema """ url = self.location try: if '://' not in url: url = urljoin(self.schema.baseurl, url) - reader = DocumentReader(self.schema.options) + reader = DocumentReader(options) d = reader.open(url) root = d.root() root.set('url', url) self.__applytns(root) - return self.schema.instance(root, url) + return self.schema.instance(root, url, options) except TransportError: msg = 'include schema at (%s), failed' % url log.error('%s, %s', self.id, msg, exc_info=True) |