Commits

illume committed 350912a

Got a basic test runner in as well as sqlitepickle.

  • Participants
  • Parent commits fc14f24

Comments (0)

Files changed (6)

File trunk/buildout.cfg

     .
 
 
-[test]
-recipe = zc.recipe.testrunner
-eggs = pywebsite
+#[test]
+#recipe = zc.recipe.testrunner
+#eggs = pywebsite
 
-[py]
-recipe = zc.recipe.egg:script
-interpreter = py
-eggs = pywebsite
+#[py]
+#recipe = zc.recipe.egg:script
+#interpreter = py
+#eggs = pywebsite

File trunk/lib/sqlitepickle.py

+"""
+Using sqlite3 and the pickle module for a simple key value store,
+where the keys are text and the values are pickled objects.
+
+Compatible with python2.6 and python3.1 and python2.5 (with pysqlite2).
+
+>>> db = SQLPickle()
+>>> db.save('key', 'value')
+>>> db.get('key')
+'value'
+
+
+sqlite3:
+    http://docs.python.org/3.1/library/sqlite3.html
+pickle:
+    http://docs.python.org/3.1/library/pickle.html
+
+
+"""
+
+import sys
+try:
+    import sqlite3
+except ImportError:
+    from pysqlite2 import dbapi2 as sqlite3
+
+try:
+    import cPickle as pickle
+except ImportError:
+    import pickle
+
+try:
+    import UserDict
+    UserDict = UserDict.UserDict
+except ImportError:
+    import collections
+    UserDict = collections.UserDict
+
+serialiser = pickle
+sqlite3.register_converter("pickle", serialiser.loads)
+
+
+class SQLPickle(object):
+
+    def __init__(self, database = ':memory:', table_name = 'key_values'):
+        self.open(database, table_name)
+
+    def _connect(self, **kwargs):
+        detect_types = sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES
+        kwargs['detect_types'] = detect_types
+        self._conn = sqlite3.connect(**kwargs)
+
+    def open(self, database = ':memory:', table_name = 'key_values'):
+        """
+        """
+
+        self._table_name = table_name
+        self._connect(database=database)
+        self._cursor = self._conn.cursor()
+        # fields by name, comment out for normal rows.
+        self._cursor.row_factory = sqlite3.Row
+
+        q = """create table %s (
+                  id INTEGER PRIMARY KEY AUTOINCREMENT,
+                  key text,
+                  value pickle,
+                  UNIQUE (key)
+               );
+            """ % self._table_name
+        try:
+            self._conn.execute(q)
+        except sqlite3.OperationalError:
+            pass
+
+
+    def save(self, key, value):
+        """
+        """
+        # use the highest and fastest protocol available.
+        data_string = sqlite3.Binary( serialiser.dumps(value, 2) )
+        try:
+            self._conn.execute("insert into %s values (null, ?, ?)" % self._table_name, 
+                               (key, data_string,))
+        except sqlite3.IntegrityError:
+            # update instead
+            self._conn.execute("update %s set value = ? where key = ?" % self._table_name, 
+                               (data_string, key))
+
+
+    def get(self, key, default = None):
+        """
+        """
+        q = "select * from %s where key = ?" % self._table_name
+        arow = self._cursor.execute(q, (key,)).fetchone()
+        if arow is None:
+            return default
+        return arow['value']
+
+    def keys(self):
+        """
+        """
+        q = "select key from %s" % self._table_name
+        keys = self._cursor.execute(q).fetchall()
+        return [k['key'] for k in keys]
+
+    def commit(self):
+        self._conn.commit()
+
+    def rollback(self):
+        self._conn.rollback()
+
+    def close(self):
+        self._conn.close()
+
+
+
+

File trunk/readme.txt

+pywebsite is for making websites with python

File trunk/run_tests.py

+#!/usr/bin/env python
+import sys, os, re, unittest
+
+main_dir = os.path.split(os.path.abspath(sys.argv[0]))[0]
+test_subdir = 'test'
+
+# Make sure we're in the correct directory
+os.chdir( main_dir )
+
+# Add the modules directory to the python path    
+sys.path.insert( 0, test_subdir )
+
+
+# Load all the tests
+suite = unittest.TestSuite()
+test_module_re = re.compile('^(.+_test)\.py$')
+for file in os.listdir(test_subdir):
+    for module in test_module_re.findall(file):
+        if module in ["XXX_test"]:
+            continue
+        print 'loading ' + module
+        __import__( module )
+        test = unittest.defaultTestLoader.loadTestsFromName( module )
+        suite.addTest( test )
+
+verbose = "--verbose" in sys.argv or "-v" in sys.argv
+
+# Run the tests
+runner = unittest.TextTestRunner()
+
+if verbose: runner.verbosity = 2
+runner.run( suite )

File trunk/setup.py

     'description':      '',
 }
 
+
+cmdclass = {}
 PACKAGEDATA = {
+    'cmdclass':    cmdclass,
+
     'package_dir': {'pywebsite': 'lib',
                     'pywebsite.tests': 'test',
                     'pywebsite.docs': 'docs',
 }
 
 
-from distutils.core import setup
+
+
+
+
+from distutils.core import setup, Command
 import sys
 
 # allow optionally using setuptools for bdist_egg.
 if "-setuptools" in sys.argv:
-    from setuptools import setup, find_packages
+    from setuptools import setup, Command
     sys.argv.remove ("-setuptools")
 
     EXTRAS.update({'include_package_data': True,
     )
 
 
+# test command.  For doing 'python setup.py test'
+class TestCommand(Command):
+    user_options = [ ]
+
+    def initialize_options(self):
+        self._dir = os.getcwd()
+
+    def finalize_options(self):
+        pass
+
+    def run(self):
+        '''
+        runs the tests with default options.
+        '''
+        import subprocess
+        return subprocess.call([sys.executable, "run_tests.py"])
+
+cmdclass['test'] = TestCommand
+
+
+
 PACKAGEDATA.update(METADATA)
 PACKAGEDATA.update(EXTRAS)
 setup(**PACKAGEDATA)

File trunk/test/sqlitepickle_test.py

+"""
+
+"""
+import time
+import unittest
+import os
+import tempfile
+from pywebsite import sqlitepickle
+
+class TestSQLPickle(unittest.TestCase):
+
+
+    def test_open(self):
+        p = sqlitepickle.SQLPickle()
+        key, value = 'asdf', 'qwer'
+        p.save(key, value)
+        value2 = p.get(key)
+        self.assertEqual(value, value2)
+        p.close()
+
+    def test_rollback(self):
+        p = sqlitepickle.SQLPickle()
+        key, value = 'asdf', 'qwer'
+        p.save(key, value)
+        p.rollback()
+        self.assertEqual(None, p.get(key))
+        self.assertEqual(2, p.get(key, 2))
+
+
+    def test_afile(self):
+        """ try saving to a file.
+        """
+        f = tempfile.NamedTemporaryFile(delete=True)
+        fname = f.name
+        del f
+        
+        p = sqlitepickle.SQLPickle(fname)
+        key, value, value2 = 'asdf', 'qwer', 'qwer2'
+        p.save(key, value)
+        # overwrite the value.
+        p.save(key, value2)
+        self.assertEqual(value2, p.get(key))
+        p.close()
+        # cleanup.
+        os.remove(fname)
+        
+
+    def test_different_data(self):
+        """ try saving different types of data
+        """
+        p = sqlitepickle.SQLPickle()
+        key = '2'
+        value = {'content': 'w', 'id': '2', 'submit': 'submit', 'title': 'a'}
+        p.save(key, value)
+        self.assertEqual(value, p.get(key))
+        key2 = 2
+        p.save(key2, value)
+        self.assertEqual(value, p.get(key2))
+        #key = (1,2)
+        #p.save(key, value)
+
+        p.close()
+ 
+
+
+
+
+    def xxtest_time(self):
+        f = tempfile.NamedTemporaryFile(delete=True)
+        fname = f.name
+        del f
+        
+        p = sqlitepickle.SQLPickle(fname)
+        key, value, value2 = 'asdf', 'qwer', 'qwer2'
+        t1 = time.time()
+        num = 10000
+        for x in range(num):
+            p.save("%s" % x, x)
+        t2 = time.time()
+        p.save("s", range(num))
+        p.close()
+        print (t2-t1)
+        print (num/ (t2-t1))
+
+        # cleanup.
+        os.remove(fname)
+
+if __name__ == '__main__':
+    unittest.main()
+