summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjortel <devnull@localhost>2010-03-31 15:54:26 +0000
committerjortel <devnull@localhost>2010-03-31 15:54:26 +0000
commit245384074da49f25c536f2f2950b66dc5681c3b0 (patch)
tree49bc0373d2185c5f55f3f55e95635443caba2229
parent5da4157327c96e1c9edb7087e1002fb4d13e0f65 (diff)
downloadsuds-245384074da49f25c536f2f2950b66dc5681c3b0.tar.gz
Enhance caching: Add cachingpolicy (0=xml documents, 1=wsdl object); Add DocumentCache that can be used to cache XML files in string XML. This may be useful as the speed and reliability of python pickle is questionable. For now, the default cache will remain the ObjectCache.
-rw-r--r--suds/cache.py50
-rw-r--r--suds/options.py8
-rw-r--r--suds/reader.py74
3 files changed, 94 insertions, 38 deletions
diff --git a/suds/cache.py b/suds/cache.py
index 0e2b314..c2bd624 100644
--- a/suds/cache.py
+++ b/suds/cache.py
@@ -21,6 +21,8 @@ Contains basic caching classes.
import os
from tempfile import gettempdir as tmp
from suds.transport import *
+from suds.sax.parser import Parser
+from suds.sax.element import Element
from datetime import datetime as dt
from datetime import timedelta
from cStringIO import StringIO
@@ -115,8 +117,6 @@ class FileCache(Cache):
"""
A file-based URL cache.
@cvar fnprefix: The file name prefix.
- @type fnprefix: str
- @ivar fnsuffix: The file name suffix.
@type fnsuffix: str
@ivar duration: The cached file duration which defines how
long the file will be cached.
@@ -125,7 +125,6 @@ class FileCache(Cache):
@type location: str
"""
fnprefix = 'suds'
- fnsuffix = 'gcf'
units = ('months', 'weeks', 'days', 'hours', 'minutes', 'seconds')
def __init__(self, location=None, **duration):
@@ -143,6 +142,14 @@ class FileCache(Cache):
self.duration = (None, 0)
self.setduration(**duration)
+ def fnsuffix(self):
+ """
+ Get the file name suffix
+ @return: The suffix
+ @rtype: str
+ """
+ return 'gcf'
+
def setduration(self, **duration):
"""
Set the caching duration which defines how long the
@@ -255,14 +262,34 @@ class FileCache(Cache):
return open(fn, *args)
def __fn(self, id):
- 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)
+ name = id
+ suffix = self.fnsuffix()
+ fn = '%s-%s.%s' % (self.fnprefix, name, suffix)
return os.path.join(self.location, fn)
+
+
+class DocumentCache(FileCache):
+ """
+ Provides xml document caching.
+ """
+
+ def fnsuffix(self):
+ return 'xml'
+
+ def get(self, id):
+ try:
+ fp = FileCache.getf(self, id)
+ if fp is None:
+ return None
+ p = Parser()
+ return p.parse(fp)
+ except:
+ FileCache.purge(self, id)
+
+ def put(self, id, object):
+ if isinstance(object, Element):
+ FileCache.put(self, id, str(object))
+ return object
class ObjectCache(FileCache):
@@ -273,6 +300,9 @@ class ObjectCache(FileCache):
"""
protocol = 2
+ def fnsuffix(self):
+ return 'px'
+
def get(self, id):
try:
fp = FileCache.getf(self, id)
diff --git a/suds/options.py b/suds/options.py
index 7e5c069..4cf3660 100644
--- a/suds/options.py
+++ b/suds/options.py
@@ -85,9 +85,14 @@ class Options(Skin):
- type: I{bool}
- default: False
- B{autoblend} - Flag that ensures that the schema(s) defined within the
- WSDL import each other. B{**Experimental**}.
+ WSDL import each other.
- type: I{bool}
- default: False
+ - B{cachingpolicy} - The caching policy.
+ - type: I{int}
+ - 0 = Cache XML documents.
+ - 1 = Cache WSDL (pickled) object.
+ - default: 0
"""
def __init__(self, **kwargs):
domain = __name__
@@ -105,5 +110,6 @@ class Options(Skin):
Definition('prefixes', bool, True),
Definition('retxml', bool, False),
Definition('autoblend', bool, False),
+ Definition('cachingpolicy', int, 0),
]
Skin.__init__(self, domain, definitions, kwargs)
diff --git a/suds/reader.py b/suds/reader.py
index 84e6822..0bac400 100644
--- a/suds/reader.py
+++ b/suds/reader.py
@@ -21,6 +21,7 @@ Contains xml document reader classes.
from suds.sax.parser import Parser
from suds.transport import Request
+from suds.cache import Cache, NoCache
from suds.store import DocumentStore
from logging import getLogger
@@ -28,31 +29,34 @@ from logging import getLogger
log = getLogger(__name__)
-class ObjectId(object):
-
- def __init__(self, name, suffix):
- self.name = name
- self.suffix = suffix
-
-
-class DocumentReader:
+class Reader:
"""
- 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
+ The reader provides integration with cache.
@ivar options: An options object.
@type options: I{Options}
"""
-
- suffix = 'pxd'
-
+
def __init__(self, options):
"""
@param options: An options object.
@type options: I{Options}
"""
self.options = options
+
+ def mangle(self, name, x):
+ """
+ Mangle the name by hashing the I{name} and appending I{x}.
+ @return: the mangled name.
+ """
+ h = abs(hash(name))
+ return '%s-%s' % (h, x)
+
+
+class DocumentReader(Reader):
+ """
+ The XML document reader provides an integration
+ between the SAX L{Parser} and the document cache.
+ """
def open(self, url):
"""
@@ -66,8 +70,8 @@ class DocumentReader:
@return: The specified XML document.
@rtype: I{Document}
"""
- id = ObjectId(url, self.suffix)
- cache = self.options.cache
+ cache = self.cache()
+ id = self.mangle(url, 'document')
d = cache.get(id)
if d is None:
d = self.download(url)
@@ -88,23 +92,28 @@ class DocumentReader:
fp = self.options.transport.open(Request(url))
sax = Parser()
return sax.parse(file=fp)
+
+ def cache(self):
+ """
+ Get the cache.
+ @return: The I{options} when I{cachingpolicy} = B{0}.
+ @rtype: L{Cache}
+ """
+ if self.options.cachingpolicy == 0:
+ return self.options.cache
+ else:
+ return NoCache()
-class DefinitionsReader:
+class DefinitionsReader(Reader):
"""
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.
@@ -113,7 +122,7 @@ class DefinitionsReader:
create the object not found in the cache.
@type fn: I{Constructor}
"""
- self.options = options
+ Reader.__init__(self, options)
self.fn = fn
def open(self, url):
@@ -129,8 +138,8 @@ class DefinitionsReader:
@return: The WSDL object.
@rtype: I{Definitions}
"""
- id = ObjectId(url, self.suffix)
- cache = self.options.cache
+ cache = self.cache()
+ id = self.mangle(url, 'wsdl')
d = cache.get(id)
if d is None:
d = self.fn(url, self.options)
@@ -140,3 +149,14 @@ class DefinitionsReader:
for imp in d.imports:
imp.imported.options = self.options
return d
+
+ def cache(self):
+ """
+ Get the cache.
+ @return: The I{options} when I{cachingpolicy} = B{1}.
+ @rtype: L{Cache}
+ """
+ if self.options.cachingpolicy == 1:
+ return self.options.cache
+ else:
+ return NoCache() \ No newline at end of file