Commits

Anonymous committed 6d5a07f

Adding basic SqliteDB

  • Participants
  • Parent commits 1d335d0

Comments (0)

Files changed (12)

docs/dev/issues.txt

 and testing options I decided to do one of the followings:
 
 
-New ObjectDB Interface
-----------------------
+Eliminating ScopeInfo
+---------------------
 
-A new low level interface for using object DBs:
+`objectdb` uses `ScopeInfo` for obtaining callinfo and pername
+information.  But in sqlite these data are stored in different tables.
+We should either adapt them to `ScopeInfo` interface or change the
+interface.
 
-  class InternalDB(object):
+The problem with adapting `ScopeInfo` is that dbs don't know anything
+about it.  It is the `objectdb` that assigns it to a scope.
 
-      files = None
+Candidate Interfaces::
 
-  class Table(object):
+  pass
 
-      def get_table(self, key, table_name):
-          pass
-
-      def add(self, key):
-          pass
-
-      def remove(self, key):
-          pass
-
-      def contains(self, key):
-          pass
-
-      def get_all(self):
-          pass
-
-  class LeafTable(object):
-
-      def get(self, key):
-          pass
-
-      def set(self, key, value):
-          pass
-
-      def remove(self, key):
-          pass
-
-      def get_all(self, key):
-          pass
-
-      def has_key(self, key):
-          pass
-
-  base = db.base_table()
-  myfile = base.get_table('myfile')
-  pername = myfile.get_table('myscope', 'pername')
-
-* files
-* scopes
-* last level
-
-  * pername: scope_id, name, value
-  * callinfo: scope_id, args, returned
 
 
 Using Sqlite3 Directly
           pass
 
 
-  def create_table(name, **fields):
-      pass
-
-  scopes = create_table('scopes', scope_id='INTEGER',
-                        file='CHAR(255)', key='CHAR(255)')
-
-  scopes.insert(file='myfile', key='mykey')
-
-
 Better Concluded Data
 =====================
 

docs/dev/workingon.txt

 Adding SqliteDB For ObjectInfo
 ==============================
 
-* Upgrading the old shelvedb
-* Implementing SqlightObjectDB
+- Moving validation from ScopeInfo to ObjectDB
+- Value overwriting in SqliteDB
+
+* Sharing connections
+* Seperate threads
+* Deleting multiple values
+* Removing entries with foreigh keys
+
+* Upgrading the old shelvedb; putting ScopeInfo back to memorydb
 * Reporting exceptions that happen in `StoppableTaskRunner`
 
 

rope/base/oi/memorydb.py

+import UserDict
+
 from rope.base.oi import objectdb
 
 
-class MemoryObjectDB(objectdb.ObjectDB, objectdb.FileDict):
+class MemoryDB(objectdb.FileDict):
 
-    def __init__(self, validation):
-        super(MemoryObjectDB, self).__init__(validation)
+    def __init__(self):
         self._files = {}
         self.files = self
 
         return key in self._files
 
     def __getitem__(self, key):
-        return self._files[key]
+        return FileInfo(self._files[key])
 
     def create(self, path):
         self._files[path] = {}
 
     def sync(self):
         pass
+
+class FileInfo(objectdb.FileInfo):
+
+    def __init__(self, scopes):
+        self.scopes = scopes
+
+    def create_scope(self, key):
+        self.scopes[key] = ScopeInfo()
+
+    def keys(self):
+        return self.scopes.keys()
+
+    def __contains__(self, key):
+        return key in self.scopes
+
+    def __getitem__(self, key):
+        return self.scopes[key]
+
+    def __delitem__(self, key):
+        del self.scopes[key]
+
+
+class ScopeInfo(objectdb.ScopeInfo):
+
+    def __init__(self):
+        self.call_info = {}
+        self.per_name = {}
+
+    def get_per_name(self, name):
+        return self.per_name.get(name, None)
+
+    def save_per_name(self, name, value):
+        self.per_name[name] = value
+
+    def get_returned(self, parameters):
+        return self.call_info.get(parameters, None)
+
+    def get_call_infos(self):
+        for args, returned in self.call_info.items():
+            yield objectdb.CallInfo(args, returned)
+
+    def add_call(self, parameters, returned):
+        self.call_info[parameters] = returned
+
+    def __getstate__(self):
+        return (self.call_info, self.per_name)
+
+    def __setstate__(self, data):
+        self.call_info, self.per_name = data

rope/base/oi/objectdb.py

 
 class ObjectDB(object):
 
-    def __init__(self, validation):
+    def __init__(self, db, validation):
+        self.db = db
         self.validation = validation
         self.observers = []
+        self.files = db.files
 
     def validate_files(self):
         for file in self.files:
 
     def get_returned(self, path, key, args):
         scope_info = self._get_scope_info(path, key, readonly=True)
-        return scope_info.get_returned(args)
+        result = scope_info.get_returned(args)
+        if self.validation.is_value_valid(result):
+            return result
 
     def get_pername(self, path, key, name):
         scope_info = self._get_scope_info(path, key, readonly=True)
-        return scope_info.get_per_name(name)
+        result = scope_info.get_per_name(name)
+        if self.validation.is_value_valid(result):
+            return result
 
     def get_callinfos(self, path, key):
         scope_info = self._get_scope_info(path, key, readonly=True)
 
     def add_callinfo(self, path, key, args, returned):
         scope_info = self._get_scope_info(path, key, readonly=False)
-        scope_info.add_call(args, returned)
+        old_returned = scope_info.get_returned(args)
+        if self.validation.is_more_valid(returned, old_returned):
+            scope_info.add_call(args, returned)
 
     def add_pername(self, path, key, name, value):
         scope_info = self._get_scope_info(path, key, readonly=False)
-        scope_info.save_per_name(name, value)
+        old_value = scope_info.get_per_name(name)
+        if self.validation.is_more_valid(value, old_value):
+            scope_info.save_per_name(name, value)
 
     def add_file_list_observer(self, observer):
         self.observers.append(observer)
 
     def sync(self):
-        pass
+        self.db.sync()
 
     def _get_scope_info(self, path, key, readonly=True):
         if path not in self.files:
         if key not in self.files[path]:
             if readonly:
                 return _NullScopeInfo()
-            self.files[path][key] = ScopeInfo()
+            self.files[path].create_scope(key)
         result = self.files[path][key]
-        result._set_validation(self.validation)
+        if isinstance(result, dict):
+            print self.files, self.files[path], self.files[path][key]
         return result
 
     def _file_removed(self, path):
             raise NotImplementedError()
 
 
+class FileInfo(UserDict.DictMixin):
+
+    def create_scope(self, key):
+        pass
+
+
+class FileDict(UserDict.DictMixin):
+
+    def create(self, key):
+        pass
+
+    def rename(self, key, new_key):
+        pass
+
+
+class ScopeInfo(object):
+
+    def get_per_name(self, name):
+        pass
+
+    def save_per_name(self, name, value):
+        pass
+
+    def get_returned(self, parameters):
+        pass
+
+    def get_call_infos(self):
+        pass
+
+    def add_call(self, parameters, returned):
+        pass
+
+
 class CallInfo(object):
 
     def __init__(self, args, returned):
 
     def removed(self, path):
         pass
-
-
-class FileDict(UserDict.DictMixin):
-
-    def create(self, key):
-        pass
-
-    def rename(self, key, new_key):
-        pass
-
-
-class ScopeInfo(object):
-
-    def __init__(self):
-        self.call_info = {}
-        self.per_name = {}
-        self._validation = None
-
-    def _set_validation(self, validation):
-        """Should be called after creation or unpickling"""
-        self._validation = validation
-
-    def get_per_name(self, name):
-        result = self.per_name.get(name, None)
-        if result is not None and not self._validation.is_value_valid(result):
-            del self.per_name[name]
-            return None
-        return result
-
-    def save_per_name(self, name, value):
-        if name not in self.per_name or \
-           self._validation.is_more_valid(value, self.per_name[name]):
-            self.per_name[name] = value
-
-    def get_returned(self, parameters):
-        result = self.call_info.get(parameters, None)
-        if result is not None and not self._validation.is_value_valid(result):
-            self.call_info[parameters] = None
-            return None
-        return result
-
-    def get_call_infos(self):
-        for args, returned in self.call_info.items():
-            yield CallInfo(args, returned)
-
-    def add_call(self, parameters, returned):
-        if parameters not in self.call_info or \
-           self._validation.is_more_valid(returned, self.call_info[parameters]):
-            self.call_info[parameters] = returned
-
-    def __getstate__(self):
-        return (self.call_info, self.per_name)
-
-    def __setstate__(self, data):
-        self.call_info, self.per_name = data

rope/base/oi/objectinfer.py

-from rope.base import pyobjects, pynames, builtins, evaluate
+from rope.base import evaluate, pyobjects, builtins, pynames
 from rope.base.oi import dynamicoi, staticoi
 
 
                 return result
 
     def get_passed_objects(self, pyfunction, parameter_index):
-        result = self.object_info.get_passed_objects(pyfunction, parameter_index)
+        result = self.object_info.get_passed_objects(pyfunction,
+                                                     parameter_index)
         if not result:
             statically_inferred = self.soi.infer_parameter_objects(pyfunction)
             if len(statically_inferred) > parameter_index:
-                result.add(statically_inferred[parameter_index])
+                result.append(statically_inferred[parameter_index])
         return result
 
     def _infer_assignment(self, assignment, pymodule):

rope/base/oi/objectinfo.py

+import sys
+
 import rope.base.project
 from rope.base.oi import objectdb, memorydb, shelvedb, transform
 
         self.to_textual = transform.PyObjectToTextual(project)
         self.to_pyobject = transform.TextualToPyObject(project)
         self.doi_to_pyobject = transform.DOITextualToPyObject(project)
-        preferred = project.get_prefs().get('objectdb_type', 'memory')
-        validation = TextualValidation(self.to_pyobject)
-        if preferred == 'memory' or project.ropefolder is None:
-            self.objectdb = memorydb.MemoryObjectDB(validation)
-        else:
-            self.objectdb = shelvedb.ShelveObjectDB(project, validation)
+        self._init_objectdb()
         if project.get_prefs().get('validate_objectdb', False):
             self._init_validation()
 
+    def _init_objectdb(self):
+        preferred = self.project.get_prefs().get('objectdb_type', 'memory')
+        validation = TextualValidation(self.to_pyobject)
+        if preferred == 'memory' or self.project.ropefolder is None:
+            db = memorydb.MemoryDB()
+        elif preferred == 'sqlite' and sys.version_info >= (2, 5, 0):
+            import rope.base.oi.sqlitedb
+            db = rope.base.oi.sqlitedb.SqliteDB(self.project)
+        else:
+            db = shelvedb.ShelveDB(self.project)
+        self.objectdb = objectdb.ObjectDB(db, validation)
+
     def _init_validation(self):
         self.objectdb.validate_files()
         observer = rope.base.project.ResourceObserver(
             if len(args) > parameter_index:
                 parameter = self.to_pyobject(args[parameter_index])
                 if parameter is not None:
-                    result.add(parameter)
+                    result.append(parameter)
         return result
 
     def doi_data_received(self, data):
 
     def is_value_valid(self, value):
         # ???: Should none and unknown be considered valid?
-        if value[0] in ('none', 'unknown'):
-            return True
+        if value is None or value[0] in ('none', 'unknown'):
+            return False
         return self.to_pyobject(value) is not None
 
     def is_more_valid(self, new, old):
+        if old is None:
+            return True
         return new[0] not in ('unknown', 'none')
 
     def is_file_valid(self, path):

rope/base/oi/shelvedb.py

 import random
 import shelve
 
-from rope.base.oi import objectdb
+from rope.base.oi import objectdb, memorydb
 
 
-class ShelveObjectDB(objectdb.ObjectDB, objectdb.FileDict):
+class ShelveDB(objectdb.FileDict):
 
-    def __init__(self, project, validation):
-        super(ShelveObjectDB, self).__init__(validation)
+    def __init__(self, project):
         self.project = project
         self._root = None
         self._index = None
         return key in self.index
 
     def __getitem__(self, key):
-        return self._get_file_dict(key)
+        return memorydb.FileInfo(self._get_file_dict(key))
 
     def create(self, key):
         self._get_file_dict(key, readonly=False)

rope/base/oi/sqlitedb.py

+import cPickle as pickle
+import UserDict
+import sqlite3
+
+from rope.base.oi import objectdb
+
+
+class SqliteDB(objectdb.FileDict):
+
+    def __init__(self, project):
+        self.project = project
+        self._connection = None
+        self._cursor = None
+        if not self._get_db_file().exists():
+            self.create_tables()
+        self.files_table = Table(self, 'files')
+        self.scopes_table = Table(self, 'scopes')
+        self.callinfos_table = Table(self, 'callinfos')
+        self.pernames_table = Table(self, 'pernames')
+        self.files = FilesTable(self)
+
+    def _get_cursor(self):
+        if self._cursor is None:
+            db = self._get_db_file()
+            self._connection = sqlite3.connect(db.real_path)
+            self._cursor = self._connection.cursor()
+        return self._cursor
+
+    def _get_db_file(self):
+        return self.project.get_file(self.project.ropefolder.path +
+                                     '/objectdb.sqlite3')
+
+    cursor = property(_get_cursor)
+
+    def create_tables(self):
+        files_table = 'CREATE TABLE files(' \
+                      'file_id INTEGER NOT NULL,' \
+                      'path VARCHAR(255),' \
+                      'PRIMARY KEY (file_id))'
+
+        scopes_table = 'CREATE TABLE scopes(' \
+                       'scope_id INTEGER NOT NULL,' \
+                       'file_id INTEGER,' \
+                       'key VARCHAR(255),' \
+                       'PRIMARY KEY (scope_id),' \
+                       'FOREIGN KEY (file_id) REFERENCES files (file_id))'
+
+        callinfo_table = 'CREATE TABLE callinfos(' \
+                         'scope_id INTEGER,' \
+                         'args BLOB,' \
+                         'returned BLOB,' \
+                         'FOREIGN KEY (scope_id) REFERENCES scopes (scope_id))'
+
+        pername_table = 'CREATE TABLE pernames(' \
+                        'scope_id INTEGER,' \
+                        'name VARCHAR(255),' \
+                        'value BLOB,' \
+                        'FOREIGN KEY (scope_id) REFERENCES scopes (scope_id))'
+        self.cursor.execute(files_table)
+        self.cursor.execute(scopes_table)
+        self.cursor.execute(callinfo_table)
+        self.cursor.execute(pername_table)
+
+    def sync(self):
+        if self._cursor is not None:
+            self._connection.commit()
+            self._cursor.close()
+            self._connection.close()
+            self._cursor = None
+            self._connection = None
+
+
+class FilesTable(objectdb.FileDict):
+
+    def __init__(self, db):
+        self.db = db
+        self.table = db.files_table
+
+    def keys(self):
+        return [item[0] for item in self.table.select('path')]
+
+    def __getitem__(self, path):
+        file_id = self.table.select('file_id', path=path)[0][0]
+        return _FileInfo(self.db, file_id)
+
+    def create(self, path):
+        self.table.insert(path=path)
+
+    def __contains__(self, path):
+        return self.table.contains(path=path)
+
+    def rename(self, path, newpath):
+        self.table.update({'path': newpath}, path=path)
+
+    def __delitem__(self, path):
+        # TODO: removing foreign keys
+        self.table.delete(path=path)
+
+
+class _FileInfo(objectdb.FileInfo):
+
+    def __init__(self, db, file_id):
+        self.db = db
+        self.file_id = file_id
+        self.table = db.scopes_table
+
+    def create_scope(self, key):
+        self.table.insert(file_id=self.file_id, key=key)
+
+    def keys(self):
+        return [item[0] for item in self.table.select(
+                'key', file_id=self.file_id)]
+
+    def __contains__(self, key):
+        return self.table.contains(file_id=self.file_id, key=key)
+
+    def __getitem__(self, key):
+        scope_id = self.table.select(
+            'scope_id', file_id=self.file_id, key=key)[0][0]
+        return _ScopeInfo(self.db, scope_id)
+
+    def __delitem__(self, key):
+        self.table.delete(file_id=self.file_id, key=key)
+
+
+class _ScopeInfo(objectdb.ScopeInfo):
+
+    def __init__(self, db, scope_id):
+        self.db = db
+        self.scope_id = scope_id
+        self.callinfo = db.callinfos_table
+        self.pername = db.pernames_table
+
+    def get_per_name(self, name):
+        result = self.pername.select('value', scope_id=self.scope_id,
+                                     name=name)
+        if result:
+            return pickle.loads(str(result[0][0]))
+        return None
+
+    def save_per_name(self, name, value):
+        value = buffer(pickle.dumps(value))
+        self.pername.update({'value': value},
+                            scope_id=self.scope_id, name=name)
+
+    def get_returned(self, parameters):
+        parameters = buffer(pickle.dumps(parameters))
+        result = self.callinfo.select('returned', scope_id=self.scope_id,
+                                      args=parameters)
+        if result:
+            return pickle.loads(str(result[0][0]))
+        return None
+
+    def get_call_infos(self):
+        result = self.callinfo.select('args, returned', scope_id=self.scope_id)
+        for args, returned in result:
+            yield objectdb.CallInfo(pickle.loads(str(args)),
+                                    pickle.loads(str(returned)))
+
+    def add_call(self, parameters, returned):
+        parameters = buffer(pickle.dumps(parameters))
+        returned = buffer(pickle.dumps(returned))
+        self.callinfo.update({'returned': returned},
+                             args=parameters, scope_id=self.scope_id)
+
+
+class Table(object):
+
+    def __init__(self, db, name):
+        self.db = db
+        self.name = name
+        self._cursor = None
+
+    def _get_cursor(self):
+        return self.db.cursor
+
+    cursor = property(_get_cursor)
+
+    def select(self, what='*', **kwds):
+        where = self._get_where(kwds)
+        command = 'SELECT %s FROM %s %s' % (what, self.name, where)
+        return self.cursor.execute(command, kwds.values()).fetchall()
+
+    def _get_where(self, kwds):
+        conditions = []
+        for key in kwds:
+            conditions.append('%s = ?' % key)
+        if conditions:
+            return 'WHERE ' + ' AND '.join(conditions)
+        return ''
+
+    def contains(self, **kwds):
+        return len(self.select(**kwds)) > 0
+
+    def insert(self, **kwds):
+        if self.contains(**kwds):
+            self.delete(**kwds)
+        names = []
+        for name in kwds:
+            names.append(name)
+        values = []
+        for value in kwds.values():
+            values.append(value)
+        command = 'INSERT INTO %s (%s) VALUES (%s)' % \
+                  (self.name, ', '.join(names),
+                   ', '.join(['?'] * len(values)))
+        self.cursor.execute(command, values)
+
+    def delete(self, **kwds):
+        where = self._get_where(kwds)
+        command = 'DELETE FROM %s %s' % (self.name, where)
+        return self.cursor.execute(command, kwds.values())
+
+    def update(self, sets, **kwds):
+        if not self.contains(**kwds):
+            new_kwds = dict(kwds)
+            new_kwds.update(sets)
+            self.insert(**new_kwds)
+            return
+        where = self._get_where(kwds)
+        values = []
+        commands = []
+        for key, value in sets.items():
+            commands.append('%s = ?' % key)
+            values.append(value)
+        values.extend(kwds.values())
+        command = 'UPDATE %s SET %s %s' % (self.name,
+                                           ', '.join(commands), where)
+        return self.cursor.execute(command, values)

ropetest/__init__.py

 import ropetest.pycoretest
 import ropetest.pyscopestest
 import ropetest.objectinfertest
+import ropetest.objectdbtest
 import ropetest.advanced_oi_test
 import ropetest.runmodtest
 import ropetest.builtintest
     result.addTests(ropetest.pycoretest.suite())
     result.addTests(ropetest.pyscopestest.suite())
     result.addTests(ropetest.objectinfertest.suite())
+    result.addTests(ropetest.objectdbtest.suite())
     result.addTests(ropetest.advanced_oi_test.suite())
     result.addTests(ropetest.runmodtest.suite())
     result.addTests(unittest.makeSuite(ropetest.builtintest.BuiltinTypesTest))

ropetest/objectdbtest.py

+import unittest
+
+from rope.base.oi import objectdb, memorydb, shelvedb, sqlitedb
+from ropetest import testutils
+
+
+def _do_for_all_dbs(function):
+    def called(self):
+        for db in self.dbs:
+            function(self, db)
+    return called
+
+
+class _MockValidation(object):
+
+    def is_value_valid(self, value):
+        return value != -1
+
+    def is_more_valid(self, new, old):
+        return new != -1
+
+    def is_file_valid(self, path):
+        return path != 'invalid'
+
+    def is_scope_valid(self, path, key):
+        return path != 'invalid' and key != 'invalid'
+
+
+class _MockFileListObserver(object):
+
+    log = ''
+
+    def added(self, path):
+        self.log += 'added %s ' % path
+
+    def removed(self, path):
+        self.log += 'removed %s ' % path
+
+
+class ObjectDBTest(unittest.TestCase):
+
+    def setUp(self):
+        super(ObjectDBTest, self).setUp()
+        self.project = testutils.sample_project()
+        validation = _MockValidation()
+        self.dbs = [
+            objectdb.ObjectDB(memorydb.MemoryDB(), validation),
+            objectdb.ObjectDB(shelvedb.ShelveDB(self.project), validation),
+            objectdb.ObjectDB(sqlitedb.SqliteDB(self.project), validation)]
+
+    def tearDown(self):
+        for db in self.dbs:
+            db.sync()
+        testutils.remove_project(self.project)
+        super(ObjectDBTest, self).tearDown()
+
+    @_do_for_all_dbs
+    def test_simple_per_name(self, db):
+        db.add_pername('file', 'key', 'name', 1)
+        self.assertEqual(1, db.get_pername('file', 'key', 'name'))
+
+    @_do_for_all_dbs
+    def test_simple_per_name_does_not_exist(self, db):
+        self.assertEquals(None, db.get_pername('file', 'key', 'name'))
+
+    @_do_for_all_dbs
+    def test_simple_per_name_after_syncing(self, db):
+        db.add_pername('file', 'key', 'name', 1)
+        db.sync()
+        self.assertEquals(1, db.get_pername('file', 'key', 'name'))
+
+    @_do_for_all_dbs
+    def test_getting_returned(self, db):
+        db.add_callinfo('file', 'key', (1, 2), 3)
+        self.assertEquals(3, db.get_returned('file', 'key', (1, 2)))
+
+    @_do_for_all_dbs
+    def test_getting_returned_when_does_not_match(self, db):
+        db.add_callinfo('file', 'key', (1, 2), 3)
+        self.assertEquals(None, db.get_returned('file', 'key', (1, 1)))
+
+    @_do_for_all_dbs
+    def test_getting_call_info(self, db):
+        db.add_callinfo('file', 'key', (1, 2), 3)
+
+        call_infos = list(db.get_callinfos('file', 'key'))
+        self.assertEquals(1, len(call_infos))
+        self.assertEquals((1, 2), call_infos[0].get_parameters())
+        self.assertEquals(3, call_infos[0].get_returned())
+
+    @_do_for_all_dbs
+    def test_invalid_per_name(self, db):
+        db.add_pername('file', 'key', 'name', -1)
+        self.assertEquals(None, db.get_pername('file', 'key', 'name'))
+
+    @_do_for_all_dbs
+    def test_overwriting_per_name(self, db):
+        db.add_pername('file', 'key', 'name', 1)
+        db.add_pername('file', 'key', 'name', 2)
+        self.assertEquals(2, db.get_pername('file', 'key', 'name'))
+
+    @_do_for_all_dbs
+    def test_not_overwriting_with_invalid_per_name(self, db):
+        db.add_pername('file', 'key', 'name', 1)
+        db.add_pername('file', 'key', 'name', -1)
+        self.assertEquals(1, db.get_pername('file', 'key', 'name'))
+
+    @_do_for_all_dbs
+    def test_getting_invalid_returned(self, db):
+        db.add_callinfo('file', 'key', (1, 2), -1)
+        self.assertEquals(None, db.get_returned('file', 'key', (1, 2)))
+
+    @_do_for_all_dbs
+    def test_not_overwriting_with_invalid_returned(self, db):
+        db.add_callinfo('file', 'key', (1, 2), 3)
+        db.add_callinfo('file', 'key', (1, 2), -1)
+        self.assertEquals(3, db.get_returned('file', 'key', (1, 2)))
+
+    @_do_for_all_dbs
+    def test_get_files(self, db):
+        db.add_callinfo('file1', 'key', (1, 2), 3)
+        db.add_callinfo('file2', 'key', (1, 2), 3)
+        self.assertEquals(set(['file1', 'file2']), set(db.get_files()))
+
+    @_do_for_all_dbs
+    def test_validating_files(self, db):
+        db.add_callinfo('invalid', 'key', (1, 2), 3)
+        db.validate_files()
+        self.assertEquals(0, len(db.get_files()))
+
+    @_do_for_all_dbs
+    def test_validating_file_for_scopes(self, db):
+        db.add_callinfo('file', 'invalid', (1, 2), 3)
+        db.validate_file('file')
+        self.assertEquals(1, len(db.get_files()))
+        self.assertEquals(0, len(list(db.get_callinfos('file', 'invalid'))))
+
+    @_do_for_all_dbs
+    def test_validating_file_moved(self, db):
+        db.add_callinfo('file', 'key', (1, 2), 3)
+
+        db.file_moved('file', 'newfile')
+        self.assertEquals(1, len(db.get_files()))
+        self.assertEquals(1, len(list(db.get_callinfos('newfile', 'key'))))
+
+    @_do_for_all_dbs
+    def test_using_file_list_observer(self, db):
+        db.add_callinfo('invalid', 'key', (1, 2), 3)
+        observer = _MockFileListObserver()
+        db.add_file_list_observer(observer)
+        db.validate_files()
+        self.assertEquals('removed invalid ', observer.log)
+
+
+def suite():
+    result = unittest.TestSuite()
+    result.addTests(unittest.makeSuite(ObjectDBTest))
+    return result
+
+
+if __name__ == '__main__':
+    unittest.main()

ropetest/objectinfertest.py

 import unittest
 
-from rope.base import project, builtins
-from rope.base.oi import memorydb, shelvedb
+import rope.base.project
+import rope.base.builtins
 from ropetest import testutils
 
 
                   'for s in f():\n    a_var = s\n')
         pymod = self.pycore.resource_to_pyobject(mod)
         a_var = pymod.get_attribute('a_var').get_object()
-        self.assertTrue(isinstance(a_var.get_type(), builtins.Str))
+        self.assertTrue(isinstance(a_var.get_type(), rope.base.builtins.Str))
 
     def test_considering_nones_to_be_unknowns(self):
         mod = self.pycore.get_string_module(
         self.assertEquals(c_class, a_var.get_type())
 
 
-def _do_for_all_dbs(function):
-    def called(self):
-        for db in self.dbs:
-            function(self, db)
-    return called
-
-
-class _MockValidation(object):
-
-    def is_value_valid(self, value):
-        return value != -1
-
-    def is_more_valid(self, new, old):
-        return new != -1
-
-    def is_file_valid(self, path):
-        return path != 'invalid'
-
-    def is_scope_valid(self, path, key):
-        return path != 'invalid' and key != 'invalid'
-
-
-class _MockFileListObserver(object):
-
-    log = ''
-
-    def added(self, path):
-        self.log += 'added %s ' % path
-
-    def removed(self, path):
-        self.log += 'removed %s ' % path
-
-
-class ObjectDBTest(unittest.TestCase):
-
-    def setUp(self):
-        super(ObjectDBTest, self).setUp()
-        self.project = testutils.sample_project()
-        validation = _MockValidation()
-        self.dbs = [memorydb.MemoryObjectDB(validation),
-                    shelvedb.ShelveObjectDB(self.project, validation)]
-
-    def tearDown(self):
-        for db in self.dbs:
-            db.sync()
-        testutils.remove_project(self.project)
-        super(ObjectDBTest, self).tearDown()
-
-    @_do_for_all_dbs
-    def test_simple_per_name(self, db):
-        db.add_pername('file', 'key', 'name', 1)
-        self.assertEqual(1, db.get_pername('file', 'key', 'name'))
-
-    @_do_for_all_dbs
-    def test_simple_per_name_does_not_exist(self, db):
-        self.assertEquals(None, db.get_pername('file', 'key', 'name'))
-
-    @_do_for_all_dbs
-    def test_simple_per_name_after_syncing(self, db):
-        db.add_pername('file', 'key', 'name', 1)
-        db.sync()
-
-        self.assertEquals(1, db.get_pername('file', 'key', 'name'))
-
-    @_do_for_all_dbs
-    def test_getting_returned(self, db):
-        db.add_callinfo('file', 'key', (1, 2), 3)
-        self.assertEquals(3, db.get_returned('file', 'key', (1, 2)))
-
-    @_do_for_all_dbs
-    def test_getting_returned_when_does_not_match(self, db):
-        db.add_callinfo('file', 'key', (1, 2), 3)
-        self.assertEquals(None, db.get_returned('file', 'key', (1, 1)))
-
-    @_do_for_all_dbs
-    def test_getting_call_info(self, db):
-        db.add_callinfo('file', 'key', (1, 2), 3)
-
-        call_infos = list(db.get_callinfos('file', 'key'))
-        self.assertEquals(1, len(call_infos))
-        self.assertEquals((1, 2), call_infos[0].get_parameters())
-        self.assertEquals(3, call_infos[0].get_returned())
-
-    @_do_for_all_dbs
-    def test_invalid_per_name(self, db):
-        db.add_pername('file', 'key', 'name', -1)
-        self.assertEquals(None, db.get_pername('file', 'key', 'name'))
-
-    @_do_for_all_dbs
-    def test_overwriting_per_name(self, db):
-        db.add_pername('file', 'key', 'name', 1)
-        db.add_pername('file', 'key', 'name', 2)
-        self.assertEquals(2, db.get_pername('file', 'key', 'name'))
-
-    @_do_for_all_dbs
-    def test_not_overwriting_with_invalid_per_name(self, db):
-        db.add_pername('file', 'key', 'name', 1)
-        db.add_pername('file', 'key', 'name', -1)
-        self.assertEquals(1, db.get_pername('file', 'key', 'name'))
-
-    @_do_for_all_dbs
-    def test_getting_invalid_returned(self, db):
-        db.add_callinfo('file', 'key', (1, 2), -1)
-        self.assertEquals(None, db.get_returned('file', 'key', (1, 2)))
-
-    @_do_for_all_dbs
-    def test_not_overwriting_with_invalid_returned(self, db):
-        db.add_callinfo('file', 'key', (1, 2), 3)
-        db.add_callinfo('file', 'key', (1, 2), -1)
-        self.assertEquals(3, db.get_returned('file', 'key', (1, 2)))
-
-    @_do_for_all_dbs
-    def test_get_files(self, db):
-        db.add_callinfo('file1', 'key', (1, 2), 3)
-        db.add_callinfo('file2', 'key', (1, 2), 3)
-        self.assertEquals(set(['file1', 'file2']), set(db.get_files()))
-
-    @_do_for_all_dbs
-    def test_validating_files(self, db):
-        db.add_callinfo('invalid', 'key', (1, 2), 3)
-        db.validate_files()
-        self.assertEquals(0, len(db.get_files()))
-
-    @_do_for_all_dbs
-    def test_validating_file_for_scopes(self, db):
-        db.add_callinfo('file', 'invalid', (1, 2), 3)
-        db.validate_file('file')
-        self.assertEquals(1, len(db.get_files()))
-        self.assertEquals(0, len(list(db.get_callinfos('file', 'invalid'))))
-
-    @_do_for_all_dbs
-    def test_validating_file_moved(self, db):
-        db.add_callinfo('file', 'key', (1, 2), 3)
-
-        db.file_moved('file', 'newfile')
-        self.assertEquals(1, len(db.get_files()))
-        self.assertEquals(1, len(list(db.get_callinfos('newfile', 'key'))))
-
-    @_do_for_all_dbs
-    def test_using_file_list_observer(self, db):
-        db.add_callinfo('invalid', 'key', (1, 2), 3)
-        observer = _MockFileListObserver()
-        db.add_file_list_observer(observer)
-        db.validate_files()
-        self.assertEquals('removed invalid ', observer.log)
-
-
 def suite():
     result = unittest.TestSuite()
     result.addTests(unittest.makeSuite(ObjectInferTest))
-    result.addTests(unittest.makeSuite(ObjectDBTest))
     return result
 
 

ropetest/projecttest.py

             open(project_root, 'w').close()
             project = Project(project_root)
         finally:
-            os.remove(project_root)
+            testutils.remove_recursively(project_root)
 
     def test_creating_folders(self):
         folderName = 'SampleFolder'