Fixed a suds.xsd.sxbasic.SchemaObject resolve() invalid cached value bug.

When called with parameter nobuiltin=True on a node whose type is a builtin, the
original implementation cached the builtin type as the result so a repeated
resolve() call returned an incorrect value.

Added related test case. Refactored the resolve() implementation into an
external function dealing with result caching and in internal worker function
doing the actual type resolution. Updated todo list.
This commit is contained in:
Jurko Gospodnetić 2011-12-26 18:14:57 +01:00
parent 0ae85957e5
commit 4a0b406cf5
3 changed files with 82 additions and 19 deletions

View File

@ -243,14 +243,16 @@ PRIORETIZED:
(+) * Prevent possible endless resolve() loops due to resolve()
(+) directly or indirectly returning the same TypedContent
(+) instance.
(+) * (Jurko) Clean up suds.xsd.sxbasic.TypedContent.resolve().
(+) * Refactor to cache the final resolved type instead of a possibly only
(+) partially resolved one when resolving without allowing resolving to
(+) builtin types.
(+) * Research.
(+) * Prepare test.
(+) * Update code.
* (Jurko) Clean up suds.xsd.sxbasic.TypedContent.resolve().
* Refactor to cache the final resolved type instead of a possibly only
partially resolved one when resolving without allowing resolving to
builtin types.
* Research.
* Prepare test.
* Update code.
* (Jurko) Check and remove the splitPrefix import from suds.xsd.sxbasic and
other modules if it is no longer needed.
NON PRIORETIZED:

View File

@ -61,17 +61,30 @@ class TypedContent(Content):
@return: The resolved (true) type.
@rtype: L{SchemaObject}
"""
# Implementation note:
# Note that there is no need for a recursive implementation here
# since a node can reference an external type node but there is no way
# using WSDL to then make that type node actually be a reference to a
# different type node.
qref = self.qref()
if qref is None:
return self
cached = self.resolved_cache.get(nobuiltin)
if cached is not None:
return cached
resolved = self.__resolve_type(nobuiltin)
self.resolved_cache[nobuiltin] = resolved
return resolved
def __resolve_type(self, nobuiltin=False):
"""
Private resolve() worker without any result caching.
@param nobuiltin: Flag indicating whether resolving to XSD builtin
types should not be allowed.
@return: The resolved (true) type.
@rtype: L{SchemaObject}
Implementation note:
Note that there is no need for a recursive implementation here since
a node can reference an external type node but there is no way using
WSDL to then make that type node actually be a reference to a different
type node.
"""
qref = self.qref()
if qref is None:
return self
query = TypeQuery(qref)
query.history = [self]
log.debug('%s, resolving: %s\n using:%s', self.id, qref, query)
@ -79,11 +92,9 @@ class TypedContent(Content):
if resolved is None:
log.debug(self.schema)
raise TypeNotFound(qref)
self.resolved_cache[nobuiltin] = resolved
result = resolved
if resolved.builtin() and nobuiltin:
result = self
return result
return self
return resolved
def qref(self):
"""

View File

@ -1437,11 +1437,61 @@ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
# Resolving builtin type nodes.
assert typo_u1.resolve().__class__ is suds.xsd.sxbuiltin.XString
assert typo_u1.resolve(nobuiltin=False).__class__ is \
suds.xsd.sxbuiltin.XString
assert typo_u1.resolve(nobuiltin=True) is typo_u1
assert elemento_x2.resolve(nobuiltin=True) is typo
assert elemento_x3.resolve(nobuiltin=True) is elemento_x3
def test_schema_node_resolve__nobuiltin_caching():
client = _client_from_wsdl(
"""<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions targetNamespace="my-namespace"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ns="my-namespace"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema targetNamespace="my-namespace"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Elemento1" type="xsd:string" />
<xsd:element name="Elemento2" type="xsd:string" />
<xsd:element name="Elemento3" type="xsd:string" />
<xsd:element name="Elemento4" type="xsd:string" />
</xsd:schema>
</wsdl:types>
</wsdl:definitions>
""")
schema = client.wsdl.schema
# Collect references to the test schema element nodes.
assert len(schema.elements) == 4
e1 = schema.elements["Elemento1", "my-namespace"]
e2 = schema.elements["Elemento2", "my-namespace"]
e3 = schema.elements["Elemento3", "my-namespace"]
e4 = schema.elements["Elemento4", "my-namespace"]
# Repeating the same resolve() call twice makes sure that the first call
# does not cache an incorrect value, thus causing the second call to return
# an incorrect result.
assert e1.resolve().__class__ is suds.xsd.sxbuiltin.XString
assert e1.resolve().__class__ is suds.xsd.sxbuiltin.XString
assert e2.resolve(nobuiltin=True) is e2
assert e2.resolve(nobuiltin=True) is e2
assert e3.resolve().__class__ is suds.xsd.sxbuiltin.XString
assert e3.resolve(nobuiltin=True) is e3
assert e3.resolve(nobuiltin=True) is e3
assert e4.resolve(nobuiltin=True) is e4
assert e4.resolve().__class__ is suds.xsd.sxbuiltin.XString
assert e4.resolve().__class__ is suds.xsd.sxbuiltin.XString
def test_schema_node_resolve__invalid_type():
client = _client_from_wsdl(
"""<?xml version='1.0' encoding='UTF-8'?>