Anonymous avatar Anonymous committed aea2ab5

Including imports in PyCore objects

Comments (0)

Files changed (9)

+=========
+Done List
+=========
+
+
+> Public release 0.2pre2 : June 4, 2006
+
+
 - Next/prev word stops at underlines and capitals : May 29, 2006
 
 
 
 - Highlighting keywords : March 21, 2006
   Only python files(*.py) should be highlighted.
+

docs/pythonsource.txt

 *** PythonSource ***
   * Formatting code
   * Basic refactorings
-  * Content assist
   * Advanced refactorings
   * Type inferencing
     * static
     * dynamic
     * ask user
+  * Code assists
   * Auto completion
 
 >>> Advanced Refactorings; Need type inferencing
+======================
 rope; A Python IDE ...
+======================
 
---- Stories ---
+Stories
+=======
 
 * Organize imports @ 2
 
   Add a graphical view for running tests.
 
 
-* Open Type @ 2
-
-
 * Enhance open dialog @ 1
 
 
   * Handle MYClass style names in next/prev word
 
 
-* Show quick outline; C-o @ 2
-
-
 * Auto-completing inherited methods @ 2
 
 
-* Auto-completing function parameter names when calling @ 2
-
-
 * Optimizing StatementRangeFinder @ 1
   Add CachedLines and not starting from the start of the lines
 
 
-* Hold the list of project classes and import them automatically
+* Auto-importing modules @ 3
+  Hold the list of project classes and import them automatically
   in codeassist
 
 
+* Open Type; C-T @ 3
+
+
 * Compound statements and auto-completion @ 1
   Completions for for-loop, except, lambda and with variables
 
   * Sorting proposals
 
 
+* Auto-completing function parameter names when calling @ 2
+
+
+* Show quick outline; C-o @ 2
+
+
+> Public release 0.2 : June 18, 2006
+
+
+* Go to definition; F3 @ 2
+
+
 * Auto completion contexts; strings, comments, functions and ... @ 2
 
 
 * Auto completion after "."s @ 2
 
 
-* Auto-completing "self."s @ 3
+* Auto-completing "self."s @ 4
 
 
-> Public release 0.2pre2 : June 4, 2006
-
-
---- Remaining Stories ---
+Remaining Stories
+=================
 ? Change program goals and description; principles.html
   ? Go toward refactoring and ... library rather than an IDE
 ? roadmap.html
   ? SF repository; How to synchronize local SVN with SF SVN?
 ? Should workingon.txt be under version control?
 ? Functional tests
-i Separate domain and presentation everywhere
+? Separate domain and presentation everywhere
 * Logo
 ? Project resource consistency; What if it is deleted after being created.
+

docs/workingon.txt

-*** Auto-completing "self."s @ 2 ***
+Auto-completing "self."s @ 2
+============================
 
-- Add project.RootFolder
-- Using path separators when setting PYTHONPATH
-- Package
-- PyElement.get_name()
-- Variables in global scope
-- Variables in class scope
-- Finding attributes set in class.__init__
-- Accessing PyObject type
-- Builtin types: Module, Function, Type
-- Add Unknown type
-- Classes inside classes
+- Better attributes names in pycore classes
+- Introduction of PyName
+- Nested modules
+- What if the element does not exist
+- Making modules from strings
+- Imports and pycore
 
-? What if the element does not exist
-* Better attributes names in pycore classes
-? PyObject.info
-    * Function types should have args, defaults, keywords attributes
+* Better names for making the distinction between PyName and PyObject
+* Add to runtests
+? PyObject might have additional information based on their types; visitor
+  * Function types should have args, defaults, keywords attributes
+* Making scopes using PyNames
 ? PyObject equality check; Value objects
 ? Getting children only when necessary, invalidating
 ? Classes and functions defined in functions
 
+* Project.pycore
+* Change from-import code assist to use PyCore
 ? Don't look for local variable completions
 ? Add PythonHierarchy.create_element(Resource)
 * Using os.path.normpath
-? What to do for AssList and AssTuple
+? What to do for AssList and AssTuple AST nodes
 ? Next/Prev words should stop at start/end of the line
-* Change from-import code assist to use PyCore
+? Consider using StatementRangeFinder in highlight module
 ? Move Project.find_module and find_package to PyCore
 ? Move Project.create_module and create_package to PyCore
 
 
---- Before 0.2 Release ---
+Before 0.2 Release
+==================
 * GUI testing redux; make a ropefunctest directory; ? rename ropetest to ropeunittest
 * Better editor changing dialog; use uihelpers module
 * More builtin templates; hash, eq
 
 
 
---- Remaining Stories ---
-
+Remaining Stories
+=================
 ? From-import might cache module global variables
 ? Directories should contain __init__.py to be packages in codeassist
 ? Auto-completion on relative imports
 ? Better version number selection
 ? Remote pair programming support
 ? Separating ui modules and packages
-    ? Decide which modules are the domain and which are the presentation
-    ? Should editing tools access Editor directly? Which of them?
-    ? Specifing the type of each story; UI or Core
+  ? Decide which modules are the domain and which are the presentation
+  ? Should editing tools access Editor directly? Which of them?
+  ? Specifing the type of each story; UI or Core
 ? The connection between ASTs, module hierarchies and type databases
 

rope/codeassist.py

 from rope.exceptions import RopeException
 from rope.codeanalyze import StatementRangeFinder, ArrayLinesAdapter
 
-
 class RopeSyntaxError(RopeException):
     pass
 

rope/exceptions.py

 
 class RopeUIException(RopeException):
     """Base exception for user interface parts of rope"""
+
 import compiler
 
+import rope.exceptions
+
+
+class ModuleNotFoundException(rope.exceptions.RopeException):
+    """Module not found exception"""
+
 
 class PyCore(object):
 
 
     def get_module(self, name):
         results = self.project.find_module(name)
+        if not results:
+            raise ModuleNotFoundException('Module %s not found' % name)
         result = results[0]
-        return self.create(results[0])
+        return self._create(results[0])
 
-    def create(self, resource):
+    def get_string_module(self, module_content):
+        attributes = {}
+        ast = compiler.parse(module_content)
+        visitor = _GlobalVisitor(self)
+        compiler.walk(ast, visitor)
+        attributes.update(visitor.names)
+        result = PyObject(PyType.get_type('Module'), attributes)
+        result.is_package = False
+        return result
+
+    def _create(self, resource):
         if resource.is_folder():
             attributes = {}
             for child in resource.get_children():
                 if child.is_folder():
-                    attributes[child.get_name()] = self.create(child)
+                    attributes[child.get_name()] = PyName(self.create(child))
                 elif child.get_name().endswith('.py') and child.get_name() != '__init__.py':
-                    attributes[child.get_name()[:-3]] = self.create(child)
-            return PyObject(PyType.get_type('Module'), attributes)
+                    name = child.get_name()[:-3]
+                    attributes[name] = PyName(self._create(child))
+            result = PyObject(PyType.get_type('Module'), attributes)
+            result.is_package = True
+            return result
         else:
-            attributes = {}
-            ast = compiler.parse(resource.read())
-            visitor = _GlobalVisitor()
-            compiler.walk(ast, visitor)
-            attributes.update(visitor.result)
-            return PyObject(PyType.get_type('Module'), attributes)
-
-    def create_module(self, contents):
-        attributes = {}
-        ast = compiler.parse(contents)
-        visitor = _GlobalVisitor()
-        compiler.walk(ast, visitor)
-        attributes.update(visitor.result)
-        return PyObject(PyType.get_type('Module'), attributes)
-
+            return self.get_string_module(resource.read())
 
 
 class PyObject(object):
 
-    def __init__(self, py_type, attributes=None):
-        self.type = py_type
+    def __init__(self, type_, attributes=None):
+        self.type = type_
         if attributes is None:
             attributes = {}
         self.object_attributes = attributes
         return PyType.types[name]
 
 
+class PyName(object):
+
+    def __init__(self, object_=None):
+        self.object = object_
+
+
 class _GlobalVisitor(object):
 
-    def __init__(self):
-        self.result = {}
+    def __init__(self, pycore):
+        self.names = {}
+        self.pycore = pycore
     
     def visitClass(self, node):
-        self.result[node.name] = _ClassVisitor.make_class(node)
+        self.names[node.name] = PyName(_ClassVisitor.make_class(node))
 
     def visitFunction(self, node):
-        self.result[node.name] = PyObject(py_type=PyType.get_type('Function'))
+        self.names[node.name] = PyName(PyObject(PyType.get_type('Function')))
 
     def visitAssName(self, node):
-        self.result[node.name] = PyObject(PyType.get_type('Unknown'))
+        self.names[node.name] = PyName()
+
+    def visitImport(self, node):
+        for import_pair in node.names:
+            name, alias = import_pair
+            imported = name
+            if alias is not None:
+                imported = alias
+            try:
+                module = self.pycore.get_module(name)
+            except ModuleNotFoundException:
+                module = PyObject(PyType.get_type('Module'))
+            self.names[imported] = PyName(module)
+
+    def visitFrom(self, node):
+        try:
+            module = self.pycore.get_module(node.modname)
+        except ModuleNotFoundException:
+            module = PyObject(PyType.get_type('Module'))
+
+        if node.names[0][0] == '*':
+            if module.is_package:
+                return
+            for name, pyname in module.attributes.iteritems():
+                if not name.startswith('_'):
+                    self.names[name] = pyname
+        else:
+            for (name, alias) in node.names:
+                imported = name
+                if alias is not None:
+                    imported = alias
+                if module.attributes.has_key(name):
+                    self.names[imported] = module.attributes[name]
+                else:
+                    self.names[imported] = PyName()
 
 
 class _ClassVisitor(object):
 
     def __init__(self):
-        self.children = {}
+        self.names = {}
 
     def visitFunction(self, node):
-        self.children[node.name] = PyObject(PyType.get_type('Function'))
+        self.names[node.name] = PyName(PyObject(PyType.get_type('Function')))
         if node.name == '__init__':
             new_visitor = _ClassInitVisitor()
             compiler.walk(node, new_visitor)
-            self.children.update(new_visitor.vars)
+            self.names.update(new_visitor.names)
 
     def visitAssName(self, node):
-        self.children[node.name] = PyObject(PyType.get_type('Unknown'))
+        self.names[node.name] = PyName()
 
     def visitClass(self, node):
-        self.children[node.name] = _ClassVisitor.make_class(node)
+        self.names[node.name] = PyName(_ClassVisitor.make_class(node))
 
     @staticmethod
     def make_class(node):
         new_visitor = _ClassVisitor()
         for n in node.getChildNodes():
             compiler.walk(n, new_visitor)
-        return PyType(new_visitor.children)
+        return PyType(new_visitor.names)
 
 
 class _ClassInitVisitor(object):
 
     def __init__(self):
-        self.vars = {}
+        self.names = {}
     
     def visitAssAttr(self, node):
         if node.expr.name == 'self':
-            self.vars[node.attrname] = PyObject(PyType.get_type('Unknown'))
+            self.names[node.attrname] = PyName()
 

ropetest/pycoretest.py

+import os
 import unittest
 
 from ropetest import testutils
-from rope.pycore import PyCore, PyType
+from rope.pycore import PyCore, PyType, ModuleNotFoundException
 from rope.project import Project
 
 class PyElementHierarchyTest(unittest.TestCase):
         self.assertEquals(PyType.get_type('Module'), result.type)
         self.assertEquals(0, len(result.attributes))
     
+    def test_nested_modules(self):
+        pkg = self.project.create_package(self.project.get_root_folder(), 'pkg')
+        mod = self.project.create_module(pkg, 'mod')
+        package = self.pycore.get_module('pkg')
+        self.assertEquals(PyType.get_type('Module'), package.type)
+        self.assertEquals(1, len(package.attributes))
+        module = package.attributes['mod']
+        self.assertEquals(PyType.get_type('Module'), module.object.type)
+
     def test_package(self):
         pkg = self.project.create_package(self.project.get_root_folder(), 'pkg')
         mod = self.project.create_module(pkg, 'mod')
         mod.write('class SampleClass(object):\n    pass\n')
         mod_element = self.pycore.get_module('mod')
         result = mod_element.attributes['SampleClass']
-        self.assertEquals(PyType.get_type('Type'), result.type)
+        self.assertEquals(PyType.get_type('Type'), result.object.type)
 
     def test_simple_function(self):
         mod = self.project.create_module(self.project.get_root_folder(), 'mod')
         mod.write('def sample_function():\n    pass\n')
         mod_element = self.pycore.get_module('mod')
         result = mod_element.attributes['sample_function']
-        self.assertEquals(PyType.get_type('Function'), result.type)
+        self.assertEquals(PyType.get_type('Function'), result.object.type)
 
     def test_class_methods(self):
         mod = self.project.create_module(self.project.get_root_folder(), 'mod')
         mod.write('class SampleClass(object):\n    def sample_method(self):\n        pass\n')
         mod_element = self.pycore.get_module('mod')
         sample_class = mod_element.attributes['SampleClass']
-        self.assertEquals(1, len(sample_class.attributes))
-        method = sample_class.attributes['sample_method']
+        self.assertEquals(1, len(sample_class.object.attributes))
+        method = sample_class.object.attributes['sample_method']
                 
     def test_global_variables(self):
         mod = self.project.create_module(self.project.get_root_folder(), 'mod')
         mod.write('class SampleClass(object):\n    var = 10\n')
         mod_element = self.pycore.get_module('mod')
         sample_class = mod_element.attributes['SampleClass']
-        var = sample_class.attributes['var']
+        var = sample_class.object.attributes['var']
         
     def test_class_attributes_set_in_init(self):
         mod = self.project.create_module(self.project.get_root_folder(), 'mod')
         mod.write('class SampleClass(object):\n    def __init__(self):\n        self.var = 20\n')
         mod_element = self.pycore.get_module('mod')
         sample_class = mod_element.attributes['SampleClass']
-        var = sample_class.attributes['var']
+        var = sample_class.object.attributes['var']
         
-    def test_classes_inside_other_classes_set_in_init(self):
+    def test_classes_inside_other_classes(self):
         mod = self.project.create_module(self.project.get_root_folder(), 'mod')
         mod.write('class SampleClass(object):\n    class InnerClass(object):\n        pass\n\n')
         mod_element = self.pycore.get_module('mod')
         sample_class = mod_element.attributes['SampleClass']
-        var = sample_class.attributes['InnerClass']
-        self.assertEquals(PyType.get_type('Type'), var.type)
+        var = sample_class.object.attributes['InnerClass']
+        self.assertEquals(PyType.get_type('Type'), var.object.type)
+
+    def test_non_existant_module(self):
+        try:
+            self.pycore.get_module('mod')
+            self.fail('And exception should have been raised')
+        except ModuleNotFoundException:
+            pass
+
+    def test_imported_names(self):
+        self.project.create_module(self.project.get_root_folder(), 'mod1')
+        mod = self.project.create_module(self.project.get_root_folder(), 'mod2')
+        mod.write('import mod1\n')
+        module = self.pycore.get_module('mod2')
+        imported_sys = module.attributes['mod1']
+        self.assertEquals(PyType.get_type('Module'), imported_sys.object.type)
+
+    def test_importing_out_of_project_names(self):
+        mod = self.project.create_module(self.project.get_root_folder(), 'mod')
+        mod.write('import sys\n')
+        module = self.pycore.get_module('mod')
+        imported_sys = module.attributes['sys']
+        self.assertEquals(PyType.get_type('Module'), imported_sys.object.type)
+
+    def test_imported_as_names(self):
+        self.project.create_module(self.project.get_root_folder(), 'mod1')
+        mod = self.project.create_module(self.project.get_root_folder(), 'mod2')
+        mod.write('import mod1 as my_import\n')
+        module = self.pycore.get_module('mod2')
+        imported_mod = module.attributes['my_import']
+        self.assertEquals(PyType.get_type('Module'), imported_mod.object.type)
+
+    def test_get_string_module(self):
+        mod = self.pycore.get_string_module('class Sample(object):\n    pass\n')
+        sample_class = mod.attributes['Sample']
+        self.assertEquals(PyType.get_type('Type'), sample_class.object.type)
+
+
+class PyCoreInProjectsTest(unittest.TestCase):
+
+    def setUp(self):
+        super(self.__class__, self).setUp()
+        self.project_root = 'sample_project'
+        os.mkdir(self.project_root)
+        self.project = Project(self.project_root)
+        samplemod = self.project.create_module(self.project.get_root_folder(), 'samplemod')
+        samplemod.write("class SampleClass(object):\n    def sample_method():\n        pass" + \
+                        "\n\ndef sample_func():\n    pass\nsample_var = 10\n" + \
+                        "\ndef _underlined_func():\n    pass\n\n" )
+        package = self.project.create_package(self.project.get_root_folder(), 'package')
+        nestedmod = self.project.create_module(package, 'nestedmod')
+        self.pycore = PyCore(self.project)
+
+    def tearDown(self):
+        testutils.remove_recursively(self.project_root)
+        super(self.__class__, self).tearDown()
+
+    def test_simple_import(self):
+        mod = self.pycore.get_string_module('import samplemod\n')
+        samplemod = mod.attributes['samplemod']
+        self.assertEquals(PyType.get_type('Module'), samplemod.object.type)
+
+    def test_from_import_class(self):
+        mod = self.pycore.get_string_module('from samplemod import SampleClass\n')
+        result = mod.attributes['SampleClass']
+        self.assertEquals(PyType.get_type('Type'), result.object.type)
+        self.assertTrue('sample_func' not in mod.attributes)
+
+    def test_from_import_star(self):
+        mod = self.pycore.get_string_module('from samplemod import *\n')
+        self.assertEquals(PyType.get_type('Type'), mod.attributes['SampleClass'].object.type)
+        self.assertEquals(PyType.get_type('Function'), mod.attributes['sample_func'].object.type)
+        self.assertTrue(mod.attributes['sample_var'] is not None)
+
+    def test_from_import_star_not_imporing_underlined(self):
+        mod = self.pycore.get_string_module('from samplemod import *')
+        self.assertTrue('_underlined_func' not in mod.attributes)
+
+    def test_from_package_import_mod(self):
+        mod = self.pycore.get_string_module('from package import nestedmod\n')
+        self.assertEquals(PyType.get_type('Module'), mod.attributes['nestedmod'].object.type)
+
+    def test_from_package_import_star(self):
+        mod = self.pycore.get_string_module('from package import *\nnest')
+        self.assertTrue('nestedmod' not in mod.attributes)
+
+    def test_unknown_when_module_cannot_be_found(self):
+        mod = self.pycore.get_string_module('from doesnotexist import nestedmod\n')
+        self.assertTrue('nestedmod' in mod.attributes)
+
+    # TODO: These are related to scopes
+    def xxx_test_from_import_function(self):
+        code = 'from samplemod import sample_func\nsample'
+        result = self.assist.assist(code, len(code))
+        self.assert_completion_in_result('sample_func', 'function', result)
+
+    # TODO: These are related to scopes
+    def xxx_test_from_imports_inside_functions(self):
+        code = 'def f():\n    from samplemod import SampleClass\n    Sample'
+        result = self.assist.assist(code, len(code))
+        self.assert_completion_in_result('SampleClass', 'class', result)
+
 
 
 if __name__ == '__main__':
 from distutils.core import setup
 
 setup(name='rope',
-      version='0.2pre2',
-      description='A Python IDE',
+      version='0.2pre3',
+      description='A Python IDE ...',
       author='Ali Gholami Rudi',
       author_email='aligrudi@users.sourceforge.net',
       url='http://rope.sf.net/',
       packages=['rope'],
       scripts=['rope.py'])
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.