1. zjes
  2. rope_py3k

Commits

Ali Gholami Rudi  committed adb0fcb

Adding objectdb and sqlitedb modules

  • Participants
  • Parent commits 83e2bee
  • Branches trunk

Comments (0)

Files changed (8)

File docs/dev/issues.txt

View file
 information and testing.
 
 
-Using A Database
-----------------
+Using SqliteDB
+==============
 
 The shelve module fails mysteriously sometimes.  For this reason I
 think using a database for saving our object information would
 help us get rid of some of the problems.  After a few inspections
 and testing options I decided to do one of the followings:
 
-Using SQLAlchemy
-----------------
 
-SQLAlchemy is a nice tool.  But there are problems:
+New ObjectDB Interface
+----------------------
 
-* Requiring a third party library
-* I could not find a good way to create tables using classes and not
-  using `sqlalchemy.Table` function.
+A new low level interface for using object DBs:
 
+  class InternalObjectDB(object):
 
-Using Sqlite3 directly
+      def get_files(self):
+          pass
+
+      def get_returned(self, file, key, args):
+          pass
+
+      def get_pername(self, file, key, name):
+          pass
+
+      def get_callinfos(self, file, key):
+          pass
+
+      def add_callinfo(self, file, key, args, returned):
+          pass
+
+      def save_pername(self, file, key, name):
+          pass
+
+  class Table(object):
+
+      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
 ----------------------
 
 The good thing about using sqlite3 is that it is always available in
 
 Maybe we can make it a bit easier by using a helper class::
 
-  class Table(object):
+  class _Table(object):
 
-      def __init__(self):
+      def __init__(self, table_name):
           pass
 
-      def select(self, **kwds):
+      def select(self, what='*', **kwds):
           pass
 
       def insert(self, **kwds):
   scopes.insert(file='myfile', key='mykey')
 
 
-Implementing A Simple ORM
--------------------------
-
-I don't want to put much time on it.  My needs are simple.  Lets
-estimate the amount of work needed for it.
-
-* Integer, CHAR, ForeignKey
-* Only one to many relations
-* SELECT *
-* SELECT * where attr=x
-* INSERT
-* UPDATE
-* DELETE
-* ...
-
-This means lots of work and I will give up!
-
-
 Better Concluded Data
 =====================
 

File docs/dev/workingon.txt

View file
-Small Stories
-=============
+Adding SqliteDB For ObjectInfo
+==============================
 
-- Changing star import from packages to include everything; even
-  all its sum-modules
-- Raising exceptions when moving a module to a nonexistent package
-
-Possible plans for the next release:
-
-* Better concluded data
-* Using DBs in ObjectInfoManager
-* Adding call for UI contributions section and interesting tasks
-* Document features and organize them
-* Annotation and tags in source code; not changing the source?
+- Adding `sqlitedb` module
+- Adding `objectdb` module
 
 
 Remaining Small Stories
 
 Docs:
 
+* Adding call for UI contributions section and interesting tasks
+* Document features and organize them
 * Document how to move fields
 * Describe why rope does not stop the user from performing wrong
   refactorings

File rope/base/oi/memorydb.py

View file
-class MemoryObjectDB(object):
+from rope.base.oi import objectdb
+
+
+class MemoryObjectDB(objectdb.ObjectDB):
 
     def __init__(self, validation):
         self.files = {}
     def get_scope_info(self, path, key, readonly=True):
         if path not in self.files:
             if readonly:
-                return NullScopeInfo()
+                return objectdb._NullScopeInfo()
             self._add_file(path)
         if key not in self.files[path]:
             if readonly:
-                return NullScopeInfo()
+                return objectdb._NullScopeInfo()
             self.files[path][key] = ScopeInfo()
             self.files[path][key]._set_validation(self.validation)
         return self.files[path][key]
 
     def get_call_infos(self):
         for args, returned in self.call_info.items():
-            yield CallInfo(args, returned)
+            yield objectdb.CallInfo(args, returned)
 
     def add_call(self, parameters, returned):
         if parameters not in self.call_info or \
 
     def __setstate__(self, data):
         self.call_info, self.per_name = data
-
-
-class NullScopeInfo(object):
-
-    def __init__(self, error_on_write=True):
-        self.error_on_write = error_on_write
-
-    def get_per_name(self, name):
-        pass
-
-    def save_per_name(self, name, value):
-        if self.error_on_write:
-            raise NotImplementedError()
-
-    def get_returned(self, parameters):
-        pass
-
-    def get_call_infos(self):
-        return []
-
-    def add_call(self, parameters, returned):
-        if self.error_on_write:
-            raise NotImplementedError()
-
-
-class CallInfo(object):
-
-    def __init__(self, args, returned):
-        self.args = args
-        self.returned = returned
-
-    def get_parameters(self):
-        return self.args
-
-    def get_returned(self):
-        return self.returned
-
-
-class FileListObserver(object):
-
-    def added(self, path):
-        pass
-
-    def removed(self, path):
-        pass

File rope/base/oi/objectdb.py

View file
+class ObjectDB(object):
+
+#    def __init__(self, validation):
+#        self.validation = validation
+#        self.observers = observers
+
+    def get_scope_info(self, path, key, readonly=True):
+        pass
+
+    def get_returned(self, path, key, args):
+        scope_info = self.get_scope_info(path, key, readonly=True)
+        return scope_info.get_returned(args)
+
+    def get_pername(self, path, key, name):
+        scope_info = self.get_scope_info(path, key, readonly=True)
+        return scope_info.get_per_name(name)
+
+    def get_callinfos(self, path, key):
+        scope_info = self.get_scope_info(path, key, readonly=True)
+        return scope_info.get_call_infos()
+
+    def add_callinfo(self, path, key, args, returned):
+        scope_info = self.get_scope_info(path, key, readonly=False)
+        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)
+
+    def get_files(self):
+        pass
+
+    def validate_files(self):
+        pass
+
+    def validate_file(self, file):
+        pass
+
+    def file_moved(self, file, newfile):
+        pass
+
+    def add_file_list_observer(self, observer):
+        self.observers.append(observer)
+
+    def sync(self):
+        pass
+
+
+class _NullScopeInfo(object):
+
+    def __init__(self, error_on_write=True):
+        self.error_on_write = error_on_write
+
+    def get_per_name(self, name):
+        pass
+
+    def save_per_name(self, name, value):
+        if self.error_on_write:
+            raise NotImplementedError()
+
+    def get_returned(self, parameters):
+        pass
+
+    def get_call_infos(self):
+        return []
+
+    def add_call(self, parameters, returned):
+        if self.error_on_write:
+            raise NotImplementedError()
+
+
+class CallInfo(object):
+
+    def __init__(self, args, returned):
+        self.args = args
+        self.returned = returned
+
+    def get_parameters(self):
+        return self.args
+
+    def get_returned(self):
+        return self.returned
+
+
+class FileListObserver(object):
+
+    def added(self, path):
+        pass
+
+    def removed(self, path):
+        pass

File rope/base/oi/objectinfo.py

View file
-import os
-
-import rope.base.oi.transform
 import rope.base.project
-from rope.base.oi import memorydb, shelvedb
+from rope.base.oi import objectdb, memorydb, shelvedb, transform
 
 
 class ObjectInfoManager(object):
 
     def __init__(self, project):
         self.project = project
-        self.to_textual = rope.base.oi.transform.PyObjectToTextual(project)
-        self.to_pyobject = rope.base.oi.transform.TextualToPyObject(project)
-        self.doi_to_pyobject = rope.base.oi.transform.DOITextualToPyObject(project)
+        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:
         result = self.get_exact_returned(pyobject, args)
         if result is not None:
             return result
-        scope_info = self._find_scope_info(pyobject)
-        for call_info in scope_info.get_call_infos():
+        path, key = self._get_scope(pyobject)
+        if path is None:
+            return None
+        for call_info in self.objectdb.get_callinfos(path, key):
             returned = call_info.get_returned()
             if returned and returned[0] not in ('unknown', 'none'):
                 result = returned
             if result is None:
                 result = returned
         if result is not None:
-            return self.to_pyobject.transform(result)
+            return self.to_pyobject(result)
 
     def get_exact_returned(self, pyobject, args):
-        scope_info = self._find_scope_info(pyobject)
-        returned = scope_info.get_returned(
-            self._args_to_textual(pyobject, args))
-        if returned is not None:
-            return self.to_pyobject.transform(returned)
+        path, key = self._get_scope(pyobject)
+        if path is not None:
+            returned = self.objectdb.get_returned(
+                path, key, self._args_to_textual(pyobject, args))
+            if returned is not None:
+                return self.to_pyobject(returned)
 
     def _args_to_textual(self, pyfunction, args):
         parameters = list(pyfunction.get_param_names(special_args=False))
         arguments = args.get_arguments(parameters)[:len(parameters)]
-        textual_args = tuple([self.to_textual.transform(arg)
+        textual_args = tuple([self.to_textual(arg)
                               for arg in arguments])
         return textual_args
 
     def get_parameter_objects(self, pyobject):
-        scope_info = self._find_scope_info(pyobject)
+        path, key = self._get_scope(pyobject)
+        if path is None:
+            return None
         parameters = None
-        for call_info in scope_info.get_call_infos():
+        for call_info in self.objectdb.get_callinfos(path, key):
             args = call_info.get_parameters()
             if len(args) > 0 and args[-1][0] not in ('unknown', 'none'):
                 parameters = args
             if parameters is None:
                 parameters = args
         if parameters:
-            return [self.to_pyobject.transform(parameter)
+            return [self.to_pyobject(parameter)
                     for parameter in parameters]
 
     def get_passed_objects(self, pyfunction, parameter_index):
-        scope_info = self._find_scope_info(pyfunction)
-        result = set()
-        for call_info in scope_info.get_call_infos():
+        path, key = self._get_scope(pyobject)
+        if path is None:
+            return
+        result = []
+        for call_info in self.objectdb.get_callinfos(path, key):
             args = call_info.get_parameters()
             if len(args) > parameter_index:
                 parameter = self.to_pyobject(args[parameter_index])
 
     def doi_data_received(self, data):
         def doi_to_normal(textual):
-            pyobject = self.doi_to_pyobject.transform(textual)
-            return self.to_textual.transform(pyobject)
+            pyobject = self.doi_to_pyobject(textual)
+            return self.to_textual(pyobject)
         function = doi_to_normal(data[0])
         args = tuple([doi_to_normal(textual) for textual in data[1]])
         returned = doi_to_normal(data[2])
             self._save_data(function, args, returned)
 
     def function_called(self, pyfunction, params, returned=None):
-        function_text = self.to_textual.transform(pyfunction)
-        params_text = tuple([self.to_textual.transform(param)
+        function_text = self.to_textual(pyfunction)
+        params_text = tuple([self.to_textual(param)
                              for param in params])
         returned_text = ('unknown',)
         if returned is not None:
-            returned_text = self.to_textual.transform(returned)
+            returned_text = self.to_textual(returned)
         self._save_data(function_text, params_text, returned_text)
 
     def save_per_name(self, scope, name, data):
-        scope_info = self._find_scope_info(scope.pyobject, readonly=False)
-        scope_info.save_per_name(name, self.to_textual.transform(data))
+        path, key = self._get_scope(scope.pyobject)
+        if path is not None:
+            self.objectdb.add_pername(path, key, name, self.to_textual(data))
 
     def get_per_name(self, scope, name):
-        scope_info = self._find_scope_info(scope.pyobject)
-        result = scope_info.get_per_name(name)
-        if result is not None:
-            return self.to_pyobject.transform(result)
+        path, key = self._get_scope(scope.pyobject)
+        if path is not None:
+            result = self.objectdb.get_pername(path, key, name)
+            if result is not None:
+                return self.to_pyobject(result)
 
     def _save_data(self, function, args, returned=('unknown',)):
-        self.objectdb.get_scope_info(function[1], function[2], readonly=False).\
-             add_call(args, returned)
+        self.objectdb.add_callinfo(function[1], function[2], args, returned)
 
-    def _find_scope_info(self, pyobject, readonly=True):
+    def _get_scope(self, pyobject):
         resource = pyobject.get_module().get_resource()
         if resource is None:
-            return memorydb.NullScopeInfo(error_on_write=False)
-        textual = self.to_textual.transform(pyobject)
+            return None, None
+        textual = self.to_textual(pyobject)
         if textual[0] == 'defined':
             path = textual[1]
             if len(textual) == 3:
                 key = textual[2]
             else:
                 key = ''
-            return self.objectdb.get_scope_info(path, key, readonly=readonly)
+            return path, key
+        return None, None
 
     def sync(self):
         self.objectdb.sync()
         # ???: Should none and unknown be considered valid?
         if value[0] in ('none', 'unknown'):
             return True
-        return self.to_pyobject.transform(value) is not None
+        return self.to_pyobject(value) is not None
 
     def is_more_valid(self, new, old):
         return new[0] not in ('unknown', 'none')
             textual = ('defined', path)
         else:
             textual = ('defined', path, key)
-        return self.to_pyobject.transform(textual) is not None
+        return self.to_pyobject(textual) is not None
 
 
 class _FileListObserver(object):

File rope/base/oi/shelvedb.py

View file
 import shelve
 import random
 
-from rope.base.oi import memorydb
+from rope.base.oi import objectdb, memorydb
 
 
-class ShelveObjectDB(object):
+class ShelveObjectDB(objectdb.ObjectDB):
 
     def __init__(self, project, validation):
         self.project = project
     def get_scope_info(self, path, key, readonly=True):
         file_dict = self._get_file_dict(path, readonly=readonly)
         if file_dict is None:
-            return memorydb.NullScopeInfo()
+            return objectdb._NullScopeInfo()
         if key not in file_dict:
             if readonly:
-                return memorydb.NullScopeInfo()
+                return objectdb._NullScopeInfo()
             file_dict[key] = memorydb.ScopeInfo()
         result = file_dict[key]
         result._set_validation(self.validation)

File rope/base/oi/sqlitedb.py

Empty file added.

File ropetest/objectinfertest.py

View file
     def removed(self, path):
         self.log += 'removed %s ' % path
 
+
 class ObjectDBTest(unittest.TestCase):
 
     def setUp(self):
 
     @_do_for_all_dbs
     def test_simple_per_name(self, db):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.save_per_name('name', 1)
-
-        scope_info = db.get_scope_info('file', 'key')
-        self.assertEqual(1, scope_info.get_per_name('name'))
+        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):
-        scope_info = db.get_scope_info('file', 'key')
-        self.assertEquals(None, scope_info.get_per_name('name'))
+        self.assertEquals(None, db.get_pername('file', 'key', 'name'))
 
     @_do_for_all_dbs
     def test_simple_per_name_after_syncing(self, db):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.save_per_name('name', 1)
+        db.add_pername('file', 'key', 'name', 1)
         db.sync()
 
-        scope_info = db.get_scope_info('file', 'key')
-        self.assertEquals(1, scope_info.get_per_name('name'))
+        self.assertEquals(1, db.get_pername('file', 'key', 'name'))
 
     @_do_for_all_dbs
     def test_getting_returned(self, db):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
-
-        scope_info = db.get_scope_info('file', 'key')
-        self.assertEquals(3, scope_info.get_returned((1, 2)))
+        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):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
-
-        scope_info = db.get_scope_info('file', 'key')
-        self.assertEquals(None, scope_info.get_returned((1, 1)))
+        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):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
+        db.add_callinfo('file', 'key', (1, 2), 3)
 
-        scope_info = db.get_scope_info('file', 'key')
-        call_infos = list(scope_info.get_call_infos())
+        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):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.save_per_name('name', -1)
-
-        self.assertEquals(None, scope_info.get_per_name('name'))
+        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):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.save_per_name('name', 1)
-        scope_info.save_per_name('name', 2)
-        self.assertEquals(2, scope_info.get_per_name('name'))
+        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):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.save_per_name('name', 1)
-        scope_info.save_per_name('name', -1)
-        self.assertEquals(1, scope_info.get_per_name('name'))
+        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):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.add_call((1, 2), -1)
-
-        self.assertEquals(None, scope_info.get_returned((1, 2)))
+        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):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
-        scope_info.add_call((1, 2), -1)
-
-        self.assertEquals(3, scope_info.get_returned((1, 2)))
+        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):
-        scope_info = db.get_scope_info('file1', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
-        scope_info = db.get_scope_info('file2', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
-
+        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):
-        scope_info = db.get_scope_info('invalid', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
+        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):
-        scope_info = db.get_scope_info('file', 'invalid', readonly=False)
-        scope_info.add_call((1, 2), 3)
+        db.add_callinfo('file', 'invalid', (1, 2), 3)
         db.validate_file('file')
         self.assertEquals(1, len(db.get_files()))
-        scope_info = db.get_scope_info('file', 'invalid', readonly=True)
-        self.assertEquals(0, len(list(scope_info.get_call_infos())))
+        self.assertEquals(0, len(list(db.get_callinfos('file', 'invalid'))))
 
     @_do_for_all_dbs
     def test_validating_file_moved(self, db):
-        scope_info = db.get_scope_info('file', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
+        db.add_callinfo('file', 'key', (1, 2), 3)
 
         db.file_moved('file', 'newfile')
         self.assertEquals(1, len(db.get_files()))
-        scope_info = db.get_scope_info('newfile', 'key', readonly=True)
-        self.assertEquals(1, len(list(scope_info.get_call_infos())))
+        self.assertEquals(1, len(list(db.get_callinfos('newfile', 'key'))))
 
     @_do_for_all_dbs
     def test_using_file_list_observer(self, db):
-        scope_info = db.get_scope_info('invalid', 'key', readonly=False)
-        scope_info.add_call((1, 2), 3)
+        db.add_callinfo('invalid', 'key', (1, 2), 3)
         observer = _MockFileListObserver()
         db.add_file_list_observer(observer)
         db.validate_files()