Skip to content

Commit

Permalink
Enhance caching: Add cachingpolicy (0=xml documents, 1=wsdl object); …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
jortel committed Mar 31, 2010
1 parent 18065fc commit b3d6d18
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 38 deletions.
50 changes: 40 additions & 10 deletions suds/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
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
Expand Down Expand Up @@ -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.
Expand All @@ -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):
Expand All @@ -143,6 +142,14 @@ def __init__(self, location=None, **duration):
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
Expand Down Expand Up @@ -255,14 +262,34 @@ def open(self, fn, *args):
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):
Expand All @@ -273,6 +300,9 @@ class ObjectCache(FileCache):
"""
protocol = 2

def fnsuffix(self):
return 'px'

def get(self, id):
try:
fp = FileCache.getf(self, id)
Expand Down
8 changes: 7 additions & 1 deletion suds/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand All @@ -105,5 +110,6 @@ def __init__(self, **kwargs):
Definition('prefixes', bool, True),
Definition('retxml', bool, False),
Definition('autoblend', bool, False),
Definition('cachingpolicy', int, 0),
]
Skin.__init__(self, domain, definitions, kwargs)
74 changes: 47 additions & 27 deletions suds/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,42 @@

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


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):
"""
Expand All @@ -66,8 +70,8 @@ def open(self, url):
@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)
Expand All @@ -88,23 +92,28 @@ def download(self, url):
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.
Expand All @@ -113,7 +122,7 @@ def __init__(self, options, fn):
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):
Expand All @@ -129,8 +138,8 @@ def open(self, url):
@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)
Expand All @@ -140,3 +149,14 @@ def open(self, url):
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()

0 comments on commit b3d6d18

Please sign in to comment.