Commits

Ali Gholami Rudi  committed 479fbdd

Changing memorydb to use a new object db interface

  • Participants
  • Parent commits 2f28d52

Comments (0)

Files changed (13)

File docs/dev/issues.txt

 
 * Not saving return value in callinfo when we're approximating?
 * Should every unknown be calculated everytime?
+* Changing `callinfo` to match similar args
+* Saving python elements with no source; `Abstract...`
 * When to forget old results?
-* Returning a `Generator` for generator functions with unknown return type?
-* Changing `callinfo` to match similar args
-* Saving python elements with now source; `Abstract...`
-* Better per name data holding in `callinfo`
-* Not overwriting useful per object data in `callinfo`
 * Some `self`\s are unknown!
 * Updating our db when performing refactorings like move module
+* Returning a `Generator` for generator functions with unknown return type?
 
 
 Invalidating Information
 in that module to be lost.
 
 
-Using A Real Database
----------------------
+Saving Data On Disk
+-------------------
 
 There are two main reasons for saving object information into disk.
 One is that we can use these information in future sessions.  The
 other is holding all type information in memory takes lots of space.
 
-We can take two approaches:
-
 * Manual DB:
 
   We can use a simple saving to files approach.  This won't solve the
 information and testing.
 
 
-Saving More Info
-----------------
+Better Data Management
+----------------------
 
-We probably have to extend the information we hold for each individual
-call info.::
+Invalidate when:
+
+* When calculating
+
+  * The return value is invalid
+  * Per name value is invalid
+
+* When cleaning up
+
+  * A file is invalid
+  * A scope is invalid
+  * A parameter is invalid
+  * The number of parameters are invalid
+
+* Overwriting rules
+
+  * Overwrite less accurate values
+
+* Maching similar parameters
+
+
+Beeter Invalidation Support
+---------------------------
+
+We will save more data.::
 
   class ObjectInfo(object):
 
       value = None
-      time = None
+      session = None
       exactness = None
 
       def __getstate__(self):
       def __setstate__(self, data):
           pass
 
+For each per name and returned value we save this structure.  The
+`session` is an identifier that shows the session this information was
+calculated.
 
-It can be used both for call info and per name objects.
+`exactness` is a positive integer that indicates the exactness of the
+value.
+
+Rules:
+
+* `exactness` should be decreased when:
+
+  * holding file changes
+  * 'uknown's are involved
+  * time passes
+
+* `exactness` should increase when a value is recalculated
+* We should recalculate the value when:
+
+  * `exactness` is less than some value
+
+Issues:
+
+* How to test this?
+
+
+A Common DB Interface
+---------------------
+
+::
+
+  class ObjectDB(object):
+
+      def __init__(self, validator):
+          pass
+
+      def get_scope_info(self, file, key):
+          pass
+
+      def validate_file(self, file):
+          pass
+
+      def sync(self):
+          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 get_parameters(self):
+          pass
+
+      def get_returned(self):
+          pass
+
+
+  class Validator(object):
+
+      def is_file_valid(self, file):
+          pass
+
+      def is_scope_valid(self, file, key):
+          pass
+
+      def is_value_valid(self, value):
+          pass
+
+      def get_invalid_value(self):
+          pass
+
+      def is_more_valid(self, new, old):
+          pass
 
 
 Using `shelve` For `_DiskObjectDB`

File docs/dev/library.txt

 See code documentation and unit-tests for more.
 
 
-`Project.do`
-------------
+`Project.do()`
+--------------
 
 For committing changes returned by refactorings.
 
 `redo` methods for undoing or redoing changes.
 
 
-`Project.validate`
-------------------
+`Project.validate()`
+--------------------
 
 When using rope as a library you probably change the files in that
 project in parallel (for example in IDEs).  To force rope to
 validates all files and directories in the project.
 
 
+`Project.close()`
+-----------------
+
+Closes project open resources.  Always call this function when you
+don't need a project anymore.  Currently it only closes the files used
+for storing object information.  Since some parts of these files are
+in memory for efficiency not closing a project might put them in an
+inconsistent state.
+
+
 `rope.base.fscommands`
 ----------------------
 
 use your new class.
 
 
+``.ropeproject`` Folder
+-----------------------
+
+From version ``0.5m4`` rope makes a ``.ropeproject`` folder in the
+project by default for saving project configurations and data.  The
+name of this folder is passed to the constructor if you want to change
+that.  Also you can force rope not to make such a folder by passing
+`None`.
+
+If such a folder exists rope loads the ``config.py`` file in that
+folder.  It might also use it for storing object information.
+
+
 `rope.base.pycore.PyCore`
 =========================
 
 
   >>> pkg.remove()
   >>> mod1.remove()
+  >>> project.close()
 
 See code documentation and test suites for more information.

File docs/dev/workingon.txt

 Moving CallInfo To Disk
 =======================
 
-* Adding `rope.base.resources` module
-* Renaming `rope.base.change` to `changes`
-* Documenting `Project.close()`
-* Use ``/dev/shm/sample_project`` as project root for faster testing?
-* Adding ``use_memory_db`` config
+- Documenting `Project.close()`
+- Use ``/dev/shm/sample_project`` as project root for faster testing?
+
+* Using a new objectdb interface
+* Changing `shelvedb` to use the new interface
+* Adding `Validator`\s
+* Testing dbs
+* `sqlite3db`
+* Renaming `rope.base.oi.callinfo` to `objectinfo`
 * Adding clear objectdb command
 * Multiple ropes on one project; problems for objectdb
 
-* What happens when `NoProject` saves call information
-* Adding method to static method refactoring
+* ``some_path + '/' + file`` might cause extra leading slash
+* Better key bindings for template assists
+* Formatting problems in move refactoring
+* Changing method to static method refactoring
 * Recursive SOI; Go where the calls go
 * Adding an option not to collect per name information
 * Evaluate function parameter defaults in staticoi?

File rope/base/oi/callinfo.py

 import os
-import re
-import shelve
 
+import rope.base.oi.transform
 import rope.base.project
-from rope.base import pyobjects
+from rope.base.oi import memorydb
 
 
 class ObjectInfoManager(object):
 
     def __init__(self, project):
         self.project = project
-        self.to_textual = _PyObjectToTextual(project)
-        self.to_pyobject = _TextualToPyObject(project)
-        self.per_object = {}
-        prefered_db = project.get_prefs().get('objectdb_type', 'memory')
-        if prefered_db == 'memory' or \
-           isinstance(project, rope.base.project.NoProject) or \
-           project.ropefolder is None:
-            self.objectdb = _MemoryObjectDB()
-        else:
-            self.objectdb = _DiskObjectDB(project)
+        self.to_textual = rope.base.oi.transform.PyObjectToTextual(project)
+        self.to_pyobject = rope.base.oi.transform.TextualToPyObject(project)
+        self.objectdb = memorydb.MemoryObjectDB()
 
     def get_returned(self, pyobject, args):
-        organizer = self.find_organizer(pyobject)
-        if organizer:
-            return self.to_pyobject.transform(
-                organizer.get_returned(self._args_to_textual(pyobject, args)))
+        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():
+            returned = call_info.get_returned()
+            if returned and returned[0] not in ('unknown', 'none'):
+                result = returned
+                break
+            if result is None:
+                result = returned
+        if result is not None:
+            return self.to_pyobject.transform(result)
 
     def get_exact_returned(self, pyobject, args):
-        organizer = self.find_organizer(pyobject)
-        if organizer:
-            return self.to_pyobject.transform(
-                organizer.get_exact_returned(self._args_to_textual(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)
 
     def _args_to_textual(self, pyfunction, args):
         parameters = list(pyfunction.get_param_names(special_args=False))
         return textual_args
 
     def get_parameter_objects(self, pyobject):
-        organizer = self.find_organizer(pyobject)
-        if organizer is not None:
-            pyobjects = [self.to_pyobject.transform(parameter)
-                         for parameter in organizer.get_parameters()]
-            return pyobjects
+        scope_info = self._find_scope_info(pyobject)
+        parameters = None
+        for call_info in scope_info.get_call_infos():
+            args = call_info.get_parameters()
+            if len(args) > 0 and args[0] not in ('unknown', 'none'):
+                parameters = args
+                break
+            if parameters is None:
+                parameters = args
+        if parameters:
+            return [self.to_pyobject.transform(parameter)
+                    for parameter in parameters]
 
     def doi_data_received(self, data):
         self._save_data(data[0], data[1], data[2])
         self._save_data(function_text, params_text, returned_text)
 
     def save_per_name(self, scope, name, data):
-        key = (self.to_textual.transform(scope.pyobject), name)
-        self.per_object[key] = self.to_textual.transform(data)
+        scope_info = self._find_scope_info(scope.pyobject, readonly=False)
+        scope_info.save_per_name(name, data)
 
     def get_per_name(self, scope, name):
-        key = (self.to_textual.transform(scope.pyobject), name)
-        data = self.per_object.get(key, ('unknown',))
-        return self.to_pyobject.transform(data)
+        scope_info = self._find_scope_info(scope.pyobject)
+        return scope_info.get_per_name(name)
 
     def _save_data(self, function, args, returned=('unknown',)):
-        self.objectdb.get_call_info(function[1], function[2], create=True).\
-             add_call_information(args, returned)
+        self.objectdb.get_scope_info(function[1], function[2], readonly=False).\
+             add_call(args, returned)
 
-    def find_organizer(self, pyobject):
+    def _find_scope_info(self, pyobject, readonly=True):
         resource = pyobject.get_module().get_resource()
         if resource is None:
-            return
+            return memorydb.NullScopeInfo(error_on_write=False)
         path = os.path.abspath(resource.real_path)
         lineno = pyobject.get_ast().lineno
-        return self.objectdb.get_call_info(path, lineno, create=False)
+        return self.objectdb.get_scope_info(path, lineno, readonly=readonly)
 
-    def close(self):
-        self.objectdb.close()
-
-
-class _MemoryObjectDB(object):
-
-    def __init__(self):
-        self.files = {}
-
-    def get_call_info(self, path, key, create=True):
-        if path not in self.files:
-            if create:
-                self.files[path] = {}
-            else:
-                return
-        if key not in self.files[path]:
-            if create:
-                self.files[path][key] = {}
-            else:
-                return
-        return _CallInformationOrganizer(self.files[path][key])
-
-    def close(self):
-        pass
-
-
-class _DiskObjectDB(object):
-    
-    def __init__(self, project):
-        self.project = project
-        self._root = None
-        self._index = None
-        self.cache = {}
-
-    def _get_root(self):
-        if self._root is None:
-            self._root = self._get_resource(self.project.ropefolder,
-                                            'objectdb', is_folder=True)
-        return self._root
-
-    def _get_index(self):
-        if self._index is None:
-            index_file = self.project.get_file(self.root.path + '/index.shelve')
-            self._index = shelve.open(index_file.real_path, writeback=True)
-        return self._index
-
-    root = property(_get_root)
-    index = property(_get_index)
-
-    def _get_resource(self, parent, name, is_folder=False):
-        if parent.has_child(name):
-            return parent.get_child(name)
-        else:
-            if is_folder:
-                return parent.create_folder(name)
-            else:
-                return parent.create_file(name)
-
-    def _get_file_dict(self, path, create=True):
-        if path not in self.cache:
-            if path not in self.index:
-                # TODO: Use better and shorter names
-                self.index[path] = os.path.basename(path) + \
-                                   str(hash(path)) + '.shelve'
-            name = self.index[path]
-            resource = self.project.get_file(self.root.path + '/' + name)
-            if not create and not resource.exists():
-                return
-            self.cache[path] = shelve.open(resource.real_path, writeback=True)
-        return self.cache[path]
-
-    def get_call_info(self, path, key, create=True):
-        key = str(key)
-        file_dict = self._get_file_dict(path, create=create)
-        if file_dict is None:
-            return
-        if key not in file_dict:
-            if create:
-                file_dict[key] = {}
-            else:
-                return
-        return _CallInformationOrganizer(file_dict[key])
-
-    def close(self):
-        self.index.close()
-        for file_dict in self.cache.values():
-            file_dict.close()
-        self._index = None
-        self.cache.clear()
-
-
-class _CallInformationOrganizer(object):
-
-    def __init__(self, info=None):
-        if info is None:
-            self.info = {}
-        else:
-            self.info = info
-
-    def add_call_information(self, args, returned):
-        self.info[args] = returned
-
-    def get_parameters(self):
-        for args in self.info.keys():
-            if len(args) > 0 and args[0] not in ('unknown', 'none'):
-                return args
-        return self.info.keys()[0]
-
-    def get_returned(self, args):
-        result = self.get_exact_returned(args)
-        if result != ('unknown',):
-            return result
-        return self._get_default_returned()
-
-    def get_exact_returned(self, args):
-        if len(self.info) == 0 or args is None:
-            return ('unknown',)
-        if self.info.get(args, ('unknown',)) != ('unknown',):
-            return self.info[args]
-        return ('unknown',)
-
-    def _get_default_returned(self):
-        for returned in self.info.values():
-            if returned[0] not in ('unknown'):
-                return returned
-        return ('unknown',)
-
-
-class _TextualToPyObject(object):
-
-    def __init__(self, project):
-        self.project = project
-
-    def transform(self, textual):
-        """Transform an object from textual form to `PyObject`"""
-        type = textual[0]
-        try:
-            method = getattr(self, type + '_to_pyobject')
-            return method(textual)
-        except AttributeError:
-            return None
-
-    def module_to_pyobject(self, textual):
-        path = textual[1]
-        return self._get_pymodule(path)
-
-    def builtin_to_pyobject(self, textual):
-        name = textual[1]
-        if name == 'str':
-            return rope.base.builtins.get_str()
-        if name == 'list':
-            holding = self.transform(textual[2])
-            return rope.base.builtins.get_list(holding)
-        if name == 'dict':
-            keys = self.transform(textual[2])
-            values = self.transform(textual[3])
-            return rope.base.builtins.get_dict(keys, values)
-        if name == 'tuple':
-            objects = []
-            for holding in textual[2:]:
-                objects.append(self.transform(holding))
-            return rope.base.builtins.get_tuple(*objects)
-        if name == 'set':
-            holding = self.transform(textual[2])
-            return rope.base.builtins.get_set(holding)
-        if name == 'iter':
-            holding = self.transform(textual[2])
-            return rope.base.builtins.get_iterator(holding)
-        if name == 'generator':
-            holding = self.transform(textual[2])
-            return rope.base.builtins.get_generator(holding)
-        if name == 'file':
-            return rope.base.builtins.get_file()
-        if name == 'function':
-            if textual[2] in rope.base.builtins.builtins:
-                return rope.base.builtins.builtins[textual[2]].get_object()
-        return None
-
-    def unknown_to_pyobject(self, textual):
-        return None
-
-    def none_to_pyobject(self, textual):
-        return None
-
-    def function_to_pyobject(self, textual):
-        return self._get_pyobject_at(textual[1], textual[2])
-
-    def class_to_pyobject(self, textual):
-        path, name = textual[1:]
-        pymodule = self._get_pymodule(path)
-        module_scope = pymodule.get_scope()
-        suspected = None
-        if name in module_scope.get_names():
-            suspected = module_scope.get_name(name).get_object()
-        if suspected is not None and isinstance(suspected, pyobjects.PyClass):
-            return suspected
-        else:
-            lineno = self._find_occurrence(name, pymodule.get_resource().read())
-            if lineno is not None:
-                inner_scope = module_scope.get_inner_scope_for_line(lineno)
-                return inner_scope.pyobject
-
-    def instance_to_pyobject(self, textual):
-        type = self.class_to_pyobject(textual)
-        if type is not None:
-            return rope.base.pyobjects.PyObject(type)
-
-    def _find_occurrence(self, name, source):
-        pattern = re.compile(r'^\s*class\s*' + name + r'\b')
-        lines = source.split('\n')
-        for i in range(len(lines)):
-            if pattern.match(lines[i]):
-                return i + 1
-
-    def _get_pymodule(self, path):
-        root = os.path.abspath(self.project.address)
-        if path.startswith(root):
-            relative_path = path[len(root):]
-            if relative_path.startswith('/') or relative_path.startswith(os.sep):
-                relative_path = relative_path[1:]
-            resource = self.project.get_resource(relative_path)
-        else:
-            resource = rope.base.project.get_no_project().get_resource(path)
-        return self.project.get_pycore().resource_to_pyobject(resource)
-
-    def _get_pyobject_at(self, path, lineno):
-        scope = self._get_pymodule(path).get_scope()
-        inner_scope = scope.get_inner_scope_for_line(lineno)
-        return inner_scope.pyobject
-
-
-class _PyObjectToTextual(object):
-
-    def __init__(self, project):
-        self.project = project
-
-    def transform(self, pyobject):
-        """Transform a `PyObject` to textual form"""
-        if pyobject is None:
-            return ('none',)
-        object_type = type(pyobject)
-        try:
-            method = getattr(self, object_type.__name__ + '_to_textual')
-            return method(pyobject)
-        except AttributeError:
-            return ('unknown',)
-
-    def PyObject_to_textual(self, pyobject):
-        if type(pyobject.get_type()) != pyobjects.PyObject:
-            result = self.transform(pyobject.get_type())
-            if result[0] == 'class':
-                return ('instance',) + result[1:]
-            return result
-        return ('unknown',)
-
-    def PyFunction_to_textual(self, pyobject):
-        return ('function', self._get_pymodule_path(pyobject.get_module()),
-                pyobject.get_ast().lineno)
-
-    def PyClass_to_textual(self, pyobject):
-        return ('class', self._get_pymodule_path(pyobject.get_module()),
-                pyobject.get_name())
-
-    def PyModule_to_textual(self, pyobject):
-        return ('module', self._get_pymodule_path(pyobject))
-
-    def PyPackage_to_textual(self, pyobject):
-        return ('module', self._get_pymodule_path(pyobject))
-
-    def List_to_textual(self, pyobject):
-        return ('builtin', 'list', self.transform(pyobject.holding))
-
-    def Dict_to_textual(self, pyobject):
-        return ('builtin', 'dict', self.transform(pyobject.keys),
-                self.transform(pyobject.values))
-
-    def Tuple_to_textual(self, pyobject):
-        objects = [self.transform(holding) for holding in pyobject.get_holding_objects()]
-        return tuple(['builtin', 'tuple'] + objects)
-
-    def Set_to_textual(self, pyobject):
-        return ('builtin', 'set', self.transform(pyobject.holding))
-
-    def Iterator_to_textual(self, pyobject):
-        return ('builtin', 'iter', self.transform(pyobject.holding))
-
-    def Generator_to_textual(self, pyobject):
-        return ('builtin', 'generator', self.transform(pyobject.holding))
-
-    def Str_to_textual(self, pyobject):
-        return ('builtin', 'str')
-
-    def File_to_textual(self, pyobject):
-        return ('builtin', 'file')
-
-    def BuiltinFunction_to_textual(self, pyobject):
-        return ('builtin', 'function', pyobject.get_name())
-
-    def _get_pymodule_path(self, pymodule):
-        resource = pymodule.get_resource()
-        resource_path = resource.path
-        if os.path.isabs(resource_path):
-            return resource_path
-        return os.path.abspath(
-            os.path.normpath(os.path.join(self.project.address,
-                                          resource_path)))
+    def sync(self):
+        self.objectdb.sync()

File rope/base/oi/memorydb.py

+class MemoryObjectDB(object):
+
+    def __init__(self):
+        self.files = {}
+
+    def get_scope_info(self, path, key, readonly=True):
+        if path not in self.files:
+            if readonly:
+                return NullScopeInfo()
+            self.files[path] = {}
+        if key not in self.files[path]:
+            if readonly:
+                return NullScopeInfo()
+            self.files[path][key] = ScopeInfo()
+        return self.files[path][key]
+
+    def sync(self):
+        pass
+
+    def validate_file(self):
+        pass
+
+
+class ScopeInfo(object):
+
+    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 CallInfo(args, returned)
+
+    def add_call(self, parameters, returned):
+        self.call_info[parameters] = returned
+
+
+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

File rope/base/oi/shelvedb.py

+import os
+import shelve
+
+import rope.base.oi.memorydb
+
+
+# FIXME: Adapt to the new ObjectDB interface
+class ShelveObjectDB(object):
+    
+    def __init__(self, project):
+        self.project = project
+        self._root = None
+        self._index = None
+        self.cache = {}
+
+    def _get_root(self):
+        if self._root is None:
+            self._root = self._get_resource(self.project.ropefolder,
+                                            'objectdb', is_folder=True)
+        return self._root
+
+    def _get_index(self):
+        if self._index is None:
+            index_file = self.project.get_file(self.root.path + '/index.shelve')
+            self._index = shelve.open(index_file.real_path, writeback=True)
+        return self._index
+
+    root = property(_get_root)
+    index = property(_get_index)
+
+    def _get_resource(self, parent, name, is_folder=False):
+        if parent.has_child(name):
+            return parent.get_child(name)
+        else:
+            if is_folder:
+                return parent.create_folder(name)
+            else:
+                return parent.create_file(name)
+
+    def _get_file_dict(self, path, readonly=True):
+        if path not in self.cache:
+            if path not in self.index:
+                # TODO: Use better and shorter names
+                self.index[path] = os.path.basename(path) + \
+                                   str(hash(path)) + '.shelve'
+            name = self.index[path]
+            resource = self.project.get_file(self.root.path + '/' + name)
+            if readonly and not resource.exists():
+                return
+            self.cache[path] = shelve.open(resource.real_path, writeback=True)
+        return self.cache[path]
+
+    def get_scope_info(self, path, key, readonly=True):
+        key = str(key)
+        file_dict = self._get_file_dict(path, readonly=readonly)
+        if file_dict is None:
+            return
+        if key not in file_dict:
+            if not readonly:
+                file_dict[key] = {}
+            else:
+                return
+        return rope.base.oi.memorydb._CallInformationOrganizer(file_dict[key])
+
+    def sync(self):
+        self.index.close()
+        for file_dict in self.cache.values():
+            file_dict.close()
+        self._index = None
+        self.cache.clear()

File rope/base/oi/transform.py

+import os
+import re
+
+import rope.base.project
+
+
+class PyObjectToTextual(object):
+
+    def __init__(self, project):
+        self.project = project
+
+    def transform(self, pyobject):
+        """Transform a `PyObject` to textual form"""
+        if pyobject is None:
+            return ('none',)
+        object_type = type(pyobject)
+        try:
+            method = getattr(self, object_type.__name__ + '_to_textual')
+            return method(pyobject)
+        except AttributeError:
+            return ('unknown',)
+
+    def PyObject_to_textual(self, pyobject):
+        if type(pyobject.get_type()) != rope.base.pyobjects.PyObject:
+            result = self.transform(pyobject.get_type())
+            if result[0] == 'class':
+                return ('instance',) + result[1:]
+            return result
+        return ('unknown',)
+
+    def PyFunction_to_textual(self, pyobject):
+        return ('function', self._get_pymodule_path(pyobject.get_module()),
+                pyobject.get_ast().lineno)
+
+    def PyClass_to_textual(self, pyobject):
+        return ('class', self._get_pymodule_path(pyobject.get_module()),
+                pyobject.get_name())
+
+    def PyModule_to_textual(self, pyobject):
+        return ('module', self._get_pymodule_path(pyobject))
+
+    def PyPackage_to_textual(self, pyobject):
+        return ('module', self._get_pymodule_path(pyobject))
+
+    def List_to_textual(self, pyobject):
+        return ('builtin', 'list', self.transform(pyobject.holding))
+
+    def Dict_to_textual(self, pyobject):
+        return ('builtin', 'dict', self.transform(pyobject.keys),
+                self.transform(pyobject.values))
+
+    def Tuple_to_textual(self, pyobject):
+        objects = [self.transform(holding) for holding in pyobject.get_holding_objects()]
+        return tuple(['builtin', 'tuple'] + objects)
+
+    def Set_to_textual(self, pyobject):
+        return ('builtin', 'set', self.transform(pyobject.holding))
+
+    def Iterator_to_textual(self, pyobject):
+        return ('builtin', 'iter', self.transform(pyobject.holding))
+
+    def Generator_to_textual(self, pyobject):
+        return ('builtin', 'generator', self.transform(pyobject.holding))
+
+    def Str_to_textual(self, pyobject):
+        return ('builtin', 'str')
+
+    def File_to_textual(self, pyobject):
+        return ('builtin', 'file')
+
+    def BuiltinFunction_to_textual(self, pyobject):
+        return ('builtin', 'function', pyobject.get_name())
+
+    def _get_pymodule_path(self, pymodule):
+        resource = pymodule.get_resource()
+        resource_path = resource.path
+        if os.path.isabs(resource_path):
+            return resource_path
+        return os.path.abspath(
+            os.path.normpath(os.path.join(self.project.address,
+                                          resource_path)))
+
+
+class TextualToPyObject(object):
+
+    def __init__(self, project):
+        self.project = project
+
+    def transform(self, textual):
+        """Transform an object from textual form to `PyObject`"""
+        type = textual[0]
+        try:
+            method = getattr(self, type + '_to_pyobject')
+            return method(textual)
+        except AttributeError:
+            return None
+
+    def module_to_pyobject(self, textual):
+        path = textual[1]
+        return self._get_pymodule(path)
+
+    def builtin_to_pyobject(self, textual):
+        name = textual[1]
+        if name == 'str':
+            return rope.base.builtins.get_str()
+        if name == 'list':
+            holding = self.transform(textual[2])
+            return rope.base.builtins.get_list(holding)
+        if name == 'dict':
+            keys = self.transform(textual[2])
+            values = self.transform(textual[3])
+            return rope.base.builtins.get_dict(keys, values)
+        if name == 'tuple':
+            objects = []
+            for holding in textual[2:]:
+                objects.append(self.transform(holding))
+            return rope.base.builtins.get_tuple(*objects)
+        if name == 'set':
+            holding = self.transform(textual[2])
+            return rope.base.builtins.get_set(holding)
+        if name == 'iter':
+            holding = self.transform(textual[2])
+            return rope.base.builtins.get_iterator(holding)
+        if name == 'generator':
+            holding = self.transform(textual[2])
+            return rope.base.builtins.get_generator(holding)
+        if name == 'file':
+            return rope.base.builtins.get_file()
+        if name == 'function':
+            if textual[2] in rope.base.builtins.builtins:
+                return rope.base.builtins.builtins[textual[2]].get_object()
+        return None
+
+    def unknown_to_pyobject(self, textual):
+        return None
+
+    def none_to_pyobject(self, textual):
+        return None
+
+    def function_to_pyobject(self, textual):
+        return self._get_pyobject_at(textual[1], textual[2])
+
+    def class_to_pyobject(self, textual):
+        path, name = textual[1:]
+        pymodule = self._get_pymodule(path)
+        module_scope = pymodule.get_scope()
+        suspected = None
+        if name in module_scope.get_names():
+            suspected = module_scope.get_name(name).get_object()
+        if suspected is not None and isinstance(suspected, rope.base.pyobjects.PyClass):
+            return suspected
+        else:
+            lineno = self._find_occurrence(name, pymodule.get_resource().read())
+            if lineno is not None:
+                inner_scope = module_scope.get_inner_scope_for_line(lineno)
+                return inner_scope.pyobject
+
+    def instance_to_pyobject(self, textual):
+        type = self.class_to_pyobject(textual)
+        if type is not None:
+            return rope.base.pyobjects.PyObject(type)
+
+    def _find_occurrence(self, name, source):
+        pattern = re.compile(r'^\s*class\s*' + name + r'\b')
+        lines = source.split('\n')
+        for i in range(len(lines)):
+            if pattern.match(lines[i]):
+                return i + 1
+
+    def _get_pymodule(self, path):
+        root = os.path.abspath(self.project.address)
+        if path.startswith(root):
+            relative_path = path[len(root):]
+            if relative_path.startswith('/') or relative_path.startswith(os.sep):
+                relative_path = relative_path[1:]
+            resource = self.project.get_resource(relative_path)
+        else:
+            resource = rope.base.project.get_no_project().get_resource(path)
+        return self.project.get_pycore().resource_to_pyobject(resource)
+
+    def _get_pyobject_at(self, path, lineno):
+        scope = self._get_pymodule(path).get_scope()
+        inner_scope = scope.get_inner_scope_for_line(lineno)
+        return inner_scope.pyobject

File rope/base/project.py

         self.file_access = rope.base.fscommands.FileAccess()
         self._history = rope.base.history.History(maxundos=100)
         self.operations = rope.base.change._ResourceOperations(self, fscommands)
+        self.prefs = rope.base.prefs.Prefs()
         self._pycore = None
 
     def get_resource(self, resource_name):
         return False
 
     def close(self):
-        pass
+        """Closes project open resources"""
+
+    def get_prefs(self):
+        return self.prefs
 
     def _get_resource_path(self, name):
         pass
         if fscommands is None:
             fscommands = rope.base.fscommands.create_fscommands(self._address)
         super(Project, self).__init__(fscommands)
-        self.prefs = rope.base.prefs.Prefs()
         self.ignored = _IgnoredResources()
         self.prefs.add_callback('ignored_resources', self.ignored.set_ignored)
         self.set('ignored_resources', ['*.pyc', '.svn', '*~', '.ropeproject'])
         return self.ignored.is_ignored(resource)
 
     def close(self):
-        self.pycore.call_info.close()
-
-    def get_prefs(self):
-        return self.prefs
+        self.pycore.call_info.sync()
 
     def set(self, key, value):
         """Set the `key` preference to `value`"""

File rope/ui/registers.py

 
 def _ask_name(name, callback):
     toplevel = Tkinter.Toplevel()
-    toplevel.title('Add Register')
+    toplevel.title('Add ' + name.title())
     label = Tkinter.Label(toplevel, text=(name.title() + ' Name:'))
     text = Tkinter.Entry(toplevel)
     def done(event):

File ropetest/projecttest.py

                                                             file_path)).read())
 
     @testutils.assert_raises(RopeError)
-    def test_failing_when_creating_file_inside_non_existant_folder(self):
-        self.project.root.create_file('NonexistantFolder/SomeFile.txt')
+    def test_failing_when_creating_file_inside_non_existent_folder(self):
+        self.project.root.create_file('NonexistentFolder/SomeFile.txt')
 
     def test_nested_directories(self):
         folder_name = 'SampleFolder'
                                                      self.sample_folder)))
 
     @testutils.assert_raises(RopeError)
-    def test_removing_non_existant_files(self):
-        self.project.get_resource('NonExistantFile.txt').remove()
+    def test_removing_non_existent_files(self):
+        self.project.get_resource('NonExistentFile.txt').remove()
 
     def test_removing_nested_files(self):
         file_name = self.sample_folder + '/sample_file.txt'

File ropetest/pycoretest.py

         self.assertEquals(get_base_type('Type'), var.get_type())
 
     @testutils.assert_raises(ModuleNotFoundError)
-    def test_non_existant_module(self):
+    def test_non_existent_module(self):
         self.pycore.get_module('doesnotexistmodule')
 
     def test_imported_names(self):
         self.assertTrue('a_var' not in pymod.get_attribute('pkg1').get_object().
                         get_attribute('pkg2').get_object().get_attributes())
 
-    def test_from_import_nonexistant_module(self):
+    def test_from_import_nonexistent_module(self):
         mod = self.pycore.get_string_module('from doesnotexistmod import DoesNotExistClass\n')
         self.assertTrue('DoesNotExistClass' in mod.get_attributes())
         self.assertEquals(get_base_type('Unknown'),
                           mod.get_attribute('DoesNotExistClass').
                           get_object().get_type())
 
-    def test_from_import_nonexistant_name(self):
+    def test_from_import_nonexistent_name(self):
         mod = self.pycore.get_string_module('from samplemod import DoesNotExistClass\n')
         self.assertTrue('DoesNotExistClass' in mod.get_attributes())
         self.assertEquals(get_base_type('Unknown'),

File ropetest/ui/coretest.py

         editor.get_editor().set_text('file2')
         editor.save()
 
-    def test_error_when_making_already_existant_file(self):
+    def test_error_when_making_already_existent_file(self):
         try:
             editor = Core.get_core().create_file(self.sample_file)
             self.fail('Show have throws exception; file already exists')

File ropetest/ui/statusbartest.py

         status.remove()
         self.assertNotEquals(status, self.manager.create_status('sample'))
 
-    def test_getting_a_nonexistant_status(self):
+    def test_getting_a_nonexistent_status(self):
         try:
-            status = self.manager.get_status('nonexistant')
+            status = self.manager.get_status('nonexistent')
             self.fail('should have raised exception')
         except StatusBarException:
             pass