[Checkins] SVN: lovely.memcached/trunk/ lovely.memcached proj

Bernd Dorn bernd.dorn at lovelysystems.com
Fri Mar 30 06:28:32 EDT 2007


Log message for revision 73944:
  lovely.memcached proj

Changed:
  A   lovely.memcached/trunk/
  A   lovely.memcached/trunk/README.txt
  A   lovely.memcached/trunk/bootstrap.py
  A   lovely.memcached/trunk/buildout.cfg
  A   lovely.memcached/trunk/setup.cfg
  A   lovely.memcached/trunk/setup.py
  A   lovely.memcached/trunk/src/
  A   lovely.memcached/trunk/src/lovely/
  A   lovely.memcached/trunk/src/lovely/__init__.py
  A   lovely.memcached/trunk/src/lovely/memcached/
  A   lovely.memcached/trunk/src/lovely/memcached/README.txt
  A   lovely.memcached/trunk/src/lovely/memcached/__init__.py
  A   lovely.memcached/trunk/src/lovely/memcached/browser/
  A   lovely.memcached/trunk/src/lovely/memcached/browser/README.txt
  A   lovely.memcached/trunk/src/lovely/memcached/browser/__init__.py
  A   lovely.memcached/trunk/src/lovely/memcached/browser/configure.zcml
  A   lovely.memcached/trunk/src/lovely/memcached/browser/ftesting.zcml
  A   lovely.memcached/trunk/src/lovely/memcached/browser/stats.pt
  A   lovely.memcached/trunk/src/lovely/memcached/browser/tests.py
  A   lovely.memcached/trunk/src/lovely/memcached/configure.zcml
  A   lovely.memcached/trunk/src/lovely/memcached/interfaces.py
  A   lovely.memcached/trunk/src/lovely/memcached/tests.py
  A   lovely.memcached/trunk/src/lovely/memcached/utility.py

-=-
Added: lovely.memcached/trunk/README.txt
===================================================================
--- lovely.memcached/trunk/README.txt	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/README.txt	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,6 @@
+================
+lovely.memcached
+================
+
+This package provides a zope3 utility that abstracts a client for
+memcached servers see: http://www.danga.com/memcached.


Property changes on: lovely.memcached/trunk/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/bootstrap.py
===================================================================
--- lovely.memcached/trunk/bootstrap.py	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/bootstrap.py	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)


Property changes on: lovely.memcached/trunk/bootstrap.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/buildout.cfg
===================================================================
--- lovely.memcached/trunk/buildout.cfg	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/buildout.cfg	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,10 @@
+[buildout]
+develop = .
+parts = test
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = lovely.memcached [test]
+
+
+


Property changes on: lovely.memcached/trunk/buildout.cfg
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/setup.cfg
===================================================================
--- lovely.memcached/trunk/setup.cfg	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/setup.cfg	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,2 @@
+[egg_info]
+tag_svn_revision = 1


Property changes on: lovely.memcached/trunk/setup.cfg
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/setup.py
===================================================================
--- lovely.memcached/trunk/setup.py	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/setup.py	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,27 @@
+#!python
+from setuptools import setup, find_packages
+
+setup (
+    name='lovely.memcached',
+    version='0.1dev',
+    author = "Lovely Systems",
+    author_email = "office at lovelysystems.com",
+    description = "A memcached client utiltiy for zope 3",
+    license = "ZPL 2.1",
+    keywords = "zope3 zope memcached cache ram",
+    url = 'svn://svn.zope.org/repos/main/lovely.memcached',
+    packages = find_packages('src'),
+    include_package_data = True,
+    package_dir = {'':'src'},
+    namespace_packages = ['lovely'],
+    extras_require = dict(test = ['zope.app.testing',
+                                  'zope.app.securitypolicy',
+                                  'zope.app.zcmlfiles',
+                                  'zope.testbrowser']),
+    install_requires = ['setuptools',
+                        'python-memcached',
+                        'ZODB3',
+                        'zope.schema',
+        ],
+    dependency_links = ['http://download.zope.org/distribution']
+    )


Property changes on: lovely.memcached/trunk/setup.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/__init__.py
===================================================================
--- lovely.memcached/trunk/src/lovely/__init__.py	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/__init__.py	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,5 @@
+# this is a namespace package
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    pass


Property changes on: lovely.memcached/trunk/src/lovely/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/README.txt
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/README.txt	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/README.txt	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,94 @@
+================
+lovely.memcached
+================
+
+This package provides a utility that abstracts a client for memcached
+servers see: http://www.danga.com/memcached.
+
+IMPORTANT:
+
+This test expects a memcache server running on local port 11211 which
+is the default port for memcached.
+
+This test runs in level 2 because it needs external resources to work. If you
+want to run this test you need to use --all as parameter to your test.
+
+Start a memcache instance with : memcached <optional options>
+
+  >>> from lovely.memcached.utility import MemcachedClient
+  >>> util = MemcachedClient()
+  >>> util.servers
+  ['127.0.0.1:11211']
+  >>> util.defaultLifetime
+  3600
+
+To store a new value in the cache we just need to set it.
+
+  >>> util.set('cached value', 'cache_key')
+  >>> util.query('cache_key')
+  'cached value'
+
+If we no longer need the cached value we can invalidate it.
+
+  >>> util.invalidate('cache_key')
+  >>> util.query('cache_key') is None
+  True
+
+We have extended the original implementation on memcache.py for unicode.
+
+  >>> util.set(u'cached value ä', 'cache_key')
+  >>> util.query('cache_key') == u'cached value ä'
+  True
+
+We can invalidate the hole cache.
+
+  >>> util.invalidateAll()
+  >>> util.query('cache_key') is None
+  True
+
+Namespaces
+==========
+
+The utility provides the facility to use namespaces for keys in order
+to let multiple utilities share the same memcached servers. A default
+namespace can be set on the utility which is then used for any get and
+query methods.
+
+  >>> util1 = MemcachedClient(defaultNS=u'1')
+  >>> util2 = MemcachedClient(defaultNS=u'2')
+  >>> util1.set(1,1)
+  >>> util2.set(2,2)
+  >>> util1.query(1)
+  1
+  >>> util1.query(2) is None
+  True
+  >>> util1.query(2, ns=u'2')
+  2
+  >>> util2.query(2)
+  2
+  >>> util2.query(1) is None
+  True
+
+Note that if invalidatAll is called then all namespaces are deleted.
+
+  >>> util1.invalidateAll()
+  >>> util1.query(1) is util2.query(2) is None
+  True
+
+Statistics
+==========
+
+This returns the stats for each server connected.
+
+  >>> util.getStatistics()
+  [('127.0.0.1:11211 (1)', {'total_items':...]
+
+If we use a server which doesn't exist we can still use the cache but noting
+will be stored. This behaviour allows us to run without a connected memcache
+server. As soon as a server is back online it will immediately used.
+
+  >>> util.servers = ['127.0.0.1:8125']
+  >>> util.set('cached value', 'cache_object')
+  >>> util.query('cache_object') is None
+  True
+


Property changes on: lovely.memcached/trunk/src/lovely/memcached/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/__init__.py
===================================================================


Property changes on: lovely.memcached/trunk/src/lovely/memcached/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/browser/README.txt
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/browser/README.txt	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/browser/README.txt	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,32 @@
+==============================
+Memcached utilit browser views
+==============================
+
+Let us add a memcached utility.
+
+  >>> from zope.testbrowser.testing import Browser
+  >>> browser = Browser()
+  >>> browser.addHeader('Authorization','Basic mgr:mgrpw')
+  >>> browser.handleErrors = False
+
+  >>> browser.open('http://localhost/@@contents.html')
+  >>> browser.getLink('Memcached Client').click()
+  >>> browser.getControl(name="new_value").value=u'mc'
+  >>> browser.getControl('Apply').click()
+  >>> browser.open('http://localhost/mc/manage')
+  >>> browser.getLink('Configure').click()
+  >>> browser.url
+  'http://localhost/mc/@@configure.html'
+
+  >>> browser.getControl('Default Lifetime').value = '5400'
+  >>> browser.getControl('Change').click()
+  >>> browser.getControl('Default Lifetime').value
+  '5400'
+
+Let's look at the stats.
+
+  >>> browser.getLink('Statistics').click()
+  >>> browser.url
+  'http://localhost/mc/@@stats.html'
+  >>> '<th>127.0.0.1:11211 (1)</th>' in browser.contents
+  True


Property changes on: lovely.memcached/trunk/src/lovely/memcached/browser/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/browser/__init__.py
===================================================================


Property changes on: lovely.memcached/trunk/src/lovely/memcached/browser/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/browser/configure.zcml
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/browser/configure.zcml	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/browser/configure.zcml	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,30 @@
+<configure 
+    xmlns="http://namespaces.zope.org/browser"
+    i18n_domain="zope"
+    >
+
+  <addMenuItem
+      title="Memcached Client"
+      description="Add a memcached client"
+      class="..utility.MemcachedClient"
+      permission="zope.ManageServices"
+      />
+
+  <editform
+      schema="..interfaces.IMemcachedClient"
+      label="Configure"
+      name="configure.html"
+      menu="zmi_views" title="Configure"
+      permission="zope.ManageServices"
+      />
+
+  <page
+      name="stats.html"
+      menu="zmi_views"
+      title="Statistics"
+      for="..interfaces.IMemcachedClient"
+      permission="zope.ManageServices"
+      template="stats.pt"
+      />
+
+</configure>
\ No newline at end of file


Property changes on: lovely.memcached/trunk/src/lovely/memcached/browser/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/browser/ftesting.zcml
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/browser/ftesting.zcml	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/browser/ftesting.zcml	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,65 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:browser="http://namespaces.zope.org/browser"
+           xmlns:zcml="http://namespaces.zope.org/zcml"
+           xmlns:meta="http://namespaces.zope.org/meta"
+           i18n_domain="zope">
+
+  
+  <include package="zope.app.securitypolicy" file="meta.zcml" />
+
+  <include
+      zcml:condition="installed zope.app.zcmlfiles"
+      package="zope.app.zcmlfiles"
+      />
+  <include
+      zcml:condition="not-installed zope.app.zcmlfiles"
+      package="zope.app"
+      />
+
+  <include package="zope.app.authentication" />
+  <securityPolicy
+      component="zope.app.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
+
+  <include package="zope.app.securitypolicy" />
+
+  <role id="zope.Anonymous" title="Everybody"
+        description="All users have this role implicitly" />
+
+  <role id="zope.Manager" title="Site Manager" />
+
+  
+  <principal
+      id="zope.manager"
+      title="Administrator"
+      login="mgr"
+      password="mgrpw" />
+  
+  <grant
+      role="zope.Manager"
+      principal="zope.manager"
+      />
+  
+  <unauthenticatedPrincipal
+      id="zope.anybody"
+      title="Unauthenticated User" />
+
+  <unauthenticatedGroup
+      id="zope.Anybody"
+      title="Unauthenticated Users" 
+      />
+  
+
+  <authenticatedGroup
+      id="zope.Authenticated"
+      title="Authenticated Users" 
+      />
+  
+  <everybodyGroup
+      id="zope.Everybody"
+      title="All Users" 
+      />
+  <include package="lovely.memcached" />
+  
+  <grantAll role="zope.Manager" />
+  
+</configure>


Property changes on: lovely.memcached/trunk/src/lovely/memcached/browser/ftesting.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/browser/stats.pt
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/browser/stats.pt	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/browser/stats.pt	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,38 @@
+<html metal:use-macro="context/@@standard_macros/view"
+    i18n:domain="zope">
+<body>
+<div metal:fill-slot="body">
+
+  <p><span tal:replace="context/zope:name"/>
+  <span i18n:translate="">Memcached statistics</span></p>
+
+  
+  <div tal:define="stats context/getStatistics"
+       tal:condition="stats">
+  
+  <metal:block tal:define="rows python:sorted(stats[0][1].keys());
+                           colNames python:map(lambda x: x[0], stats);
+                           colData python:map(lambda x: x[1], stats);">
+
+    <table border="1" cellpadding="2">
+      <thead>
+        <th>&nbsp;</th>
+        <th tal:repeat="colName colNames" tal:content="colName"/>
+      </thead>
+      <tbody>
+        <tr tal:repeat="row rows">
+          <th tal:content="row" align="left"/>
+          <td tal:repeat="colName colNames"
+              tal:content="python:colData[repeat['colName'].index()][row]"/>
+        </tr>
+        
+      </tbody>
+    </table>
+    
+  </metal:block>
+  </div>
+  
+</div>
+</body>
+</html>
+


Property changes on: lovely.memcached/trunk/src/lovely/memcached/browser/stats.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/browser/tests.py
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/browser/tests.py	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/browser/tests.py	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,32 @@
+##############################################################################
+#
+# Copyright (c) 2007 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import unittest
+from zope.testing import doctest
+from zope.app.testing import functional
+
+functional.defineLayer('MemcachedLayer', 'ftesting.zcml')
+
+def test_suite():
+    suite = functional.FunctionalDocFileSuite('README.txt')
+    suite.layer = MemcachedLayer
+    suite.level = 2
+    return unittest.TestSuite((suite,))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: lovely.memcached/trunk/src/lovely/memcached/browser/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/configure.zcml
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/configure.zcml	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/configure.zcml	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,26 @@
+<configure 
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope"
+    >
+
+  <class class=".utility.MemcachedClient">
+    <implements
+        interface="zope.annotation.interfaces.IAttributeAnnotatable"
+        />
+
+    <require 
+        permission="zope.View" 
+        interface=".interfaces.IMemcachedClient"
+        />
+
+    <require 
+        permission="zope.ManageServices" 
+        set_schema=".interfaces.IMemcachedClient"
+        />
+  </class>
+
+  <include package=".browser"/>
+  
+</configure>
+


Property changes on: lovely.memcached/trunk/src/lovely/memcached/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/interfaces.py
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/interfaces.py	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/interfaces.py	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2007 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+from zope import interface
+from zope import schema
+
+class IMemcachedClient(interface.Interface):
+    
+    """A memcache client utility"""
+
+    defaultNS = schema.TextLine(
+        title=u'Default Namespace',
+        description=u"The default namespace used by this client",
+        required=False,
+        default=None)
+        
+    servers = schema.List(
+        title = u'Servers',
+        description = u"Servers defined as <hostname>:<port>",
+        value_type = schema.BytesLine(),
+        required = True,
+        default=['127.0.0.1:11211']
+        )
+    
+    defaultLifetime = schema.Int(
+        title = u'Default Lifetime',
+        description = u'The default lifetime of entries',
+        required = True,
+        default = 3600,
+        )
+
+
+    def getStatistics():
+        """returns the memcached stats"""
+
+    def set(data, key, lifetime=None, ns=None):
+        """Sets data with the given key in namespace. Lifetime
+        defaults to defautlLifetime and ns defaults to the
+        default namespace"""
+
+    def query(key, default=None, ns=None):
+        """query the cache for key in namespace, returns default if
+        not found. ns defaults to default namespace."""
+        
+    def invalidate(key, ns=None):
+        """invalidates key in namespace which defaults to default
+        namespace, currently we can not invalidate just a namespace"""
+
+    def invalidateAll():
+        """invalidates all data of the memcached servers, not that all
+        namespaces are invalidated"""


Property changes on: lovely.memcached/trunk/src/lovely/memcached/interfaces.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/tests.py
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/tests.py	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/tests.py	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# Copyright (c) 2007 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import unittest
+from zope.testing import doctest
+from zope.testing.doctestunit import DocTestSuite, DocFileSuite
+
+def test_suite():
+    level1Suites = (
+        DocTestSuite(
+        'lovely.memcached.utility',
+        optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+        ),
+        )
+    level2Suites = (
+        DocFileSuite(
+        'README.txt',
+        optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+        ),
+        )
+    for suite in level2Suites:
+        suite.level = 2
+    return unittest.TestSuite(level2Suites + level1Suites)
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: lovely.memcached/trunk/src/lovely/memcached/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: lovely.memcached/trunk/src/lovely/memcached/utility.py
===================================================================
--- lovely.memcached/trunk/src/lovely/memcached/utility.py	2007-03-30 10:28:05 UTC (rev 73943)
+++ lovely.memcached/trunk/src/lovely/memcached/utility.py	2007-03-30 10:28:31 UTC (rev 73944)
@@ -0,0 +1,146 @@
+##############################################################################
+#
+# Copyright (c) 2007 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+
+import md5
+import logging
+import memcache
+import cPickle
+from threading import local
+import persistent
+
+from zope.schema.fieldproperty import FieldProperty
+from zope import interface
+from interfaces import IMemcachedClient
+
+log = logging.getLogger('lovely.memcached')
+
+class MemcachedClient(persistent.Persistent):
+    interface.implements(IMemcachedClient)
+
+    defaultNS = FieldProperty(IMemcachedClient['defaultNS'])
+    servers = FieldProperty(IMemcachedClient['servers'])
+    defaultLifetime = FieldProperty(IMemcachedClient['defaultLifetime'])
+    
+    def __init__(self, servers=None, defaultAge=None,
+                 defaultNS=None):
+        if servers is not None:
+            self.servers = servers
+        if defaultAge is not None:
+            self.defaultAge = defaultAge
+        if defaultNS is not None:
+            self.defaultNS = defaultNS
+
+    def getStatistics(self):
+        return self.client.get_stats()
+
+    def set(self, data, key, lifetime=None, ns=None):
+        if lifetime is None:
+            lifetime = self.defaultLifetime
+        ns = ns or self.defaultNS or None
+
+        data = cPickle.dumps(data)
+        log.debug('set: %r, %r, %r, %r' % (key, len(data), ns, lifetime))
+        self.client.set(self._buildKey(key, ns), data, lifetime)
+
+    def query(self, key, default=None, ns=None):
+        ns = ns or self.defaultNS or None
+        res = self.client.get(self._buildKey(key, ns))
+        if res is None:
+            return default
+        return cPickle.loads(res)
+
+    def invalidate(self, key, ns=None):
+        ns = ns or self.defaultNS or None
+        log.debug('invalidate: %r, %r '% (key, ns))
+        self.client.delete(self._buildKey(key, ns))
+
+    def invalidateAll(self):
+        # notice this does not look at namespaces
+        self.client.flush_all()
+
+    def _buildKey(self, key, ns):
+
+        """builds a key for key and ns, if key is a persistent
+        object its oid is used
+        
+        >>> vc1 = MemcachedClient()
+        >>> k1 = vc1._buildKey(1, None)
+
+        of course the key is the same for same arguments
+        >>> k1 == vc1._buildKey(1, None)
+        True
+        
+        the key is an md5 digest
+        >>> len(k1)
+        32
+
+        for different namespaces the keys are different
+        
+        >>> vc2 = MemcachedClient()
+        >>> k2 = vc2._buildKey(1, u'vc2')
+        >>> k2 != k1
+        True
+
+        if key has an oid this is taken
+
+        >>> class A: pass
+        >>> a = A()
+        >>> b = A()
+        >>> a._p_oid = "oid of a"
+        >>> b._p_oid = "oid of a"
+        >>> ka1 = vc1._buildKey(a, 1)
+        >>> kb1 = vc1._buildKey(b, 1)
+        >>> ka1 == kb1
+        True
+        >>> b._p_oid = "oid of b"
+        >>> kb1 = vc1._buildKey(b, 1)
+        >>> ka1 == kb1
+        False
+        
+        """
+        oid = getattr(key, '_p_oid', None)
+        if oid is not None:
+            key = oid
+        if ns is not None:
+            m = md5.new(cPickle.dumps((ns, key)))
+        else:
+            m = md5.new(cPickle.dumps(key))
+        return m.hexdigest()
+
+    @property
+    def client(self):
+        servers = getattr(self.storage, 'servers', None)
+        if servers is not self.servers:
+            # we have a change in the list of servers
+            self.storage.client = None
+            self.storage.servers = self.servers
+        client = getattr(self.storage, 'client', None)
+        if client is None:
+            client = memcache.Client(self.servers, debug=0)
+            self.storage.client = client
+        return client
+
+    @property
+    def storage(self):
+        # we use a thread local storage to have a memcache client for every
+        # thread.
+        if not hasattr(self, '_v_storage'):
+            self._v_storage = local()
+        return self._v_storage
+


Property changes on: lovely.memcached/trunk/src/lovely/memcached/utility.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native



More information about the Checkins mailing list