Commits

Anonymous committed 4e7f996

Classes and functions defined in functions

Comments (0)

Files changed (3)

docs/workingon.txt

 - Making modules from strings
 - Imports and pycore
 - PyName.get_attributes() and PyName.get_type()
+- PyName._has_block(), PyName._get_ast()
+- Classes and functions defined in functions
 
 * Making scopes using PyNames
-* Better names for making the distinction between PyName and PyObject
-* Add to runtests
+  * Function parameters and scopes
+  ? Builtins and scopes
+  * find_scope(line, indents)
+  * Refactor pycore
+? Factory methods for creating Functions, Classes, Modules
+? Should Scope.get_names return all of the visible names in a scope?
+* Handle circular imports
+? not_found_module.is_package
 ? PyObject might have additional information based on their types; visitor
   * Function types should have args, defaults, keywords attributes
+* Getting children only when necessary, invalidating, Resource.add_change_observer
 ? PyObject equality check; Value objects
-? Getting children only when necessary, invalidating
-? Classes and functions defined in functions
+? A separate module for scopes
 
+? Using inspect on modules that cannot be found in the project
 * Project.pycore
 * Change from-import code assist to use PyCore
 ? Don't look for local variable completions
 ? Consider using StatementRangeFinder in highlight module
 ? Move Project.find_module and find_package to PyCore
 ? Move Project.create_module and create_package to PyCore
+* Correcting indentation on '\n ${cursor}   def f():\n    pass\n'; cursor changes its line
+* 'super' codeassist super(${class}, self)
 
 
 Before 0.2 Release
         return result
 
     def get_string_scope(self, module_content):
-        return Scope()
+        module = self.get_string_module(module_content)
+        return GlobalScope(self, module)
 
     def _create(self, resource):
         if resource.is_folder():
 
 class PyName(object):
 
-    def __init__(self, object_=None):
+    def __init__(self, object_=None, ast=None):
         self.object = object_
+        self.ast = ast
 
     def get_attributes(self):
         return self.object.attributes
     def get_type(self):
         return self.object.type
 
+    def _has_block(self):
+        return self.ast is not None
+    
+    def _get_ast(self):
+        return self.ast
+
 
 class Scope(object):
+
+    def __init__(self, pycore, pyname):
+        self.pycore = pycore
+        self.pyname = pyname
+    
     def get_names(self):
-        return {'sample_func': None}
+        return self.pyname.get_attributes()
 
+    def get_scopes(self):
+        '''Returns the subscopes of this scope.
+        
+        The returned scopes should be sorted by the order they appear
+        '''
+        block_objects = [pyname for pyname in self.pyname.get_attributes().values()
+                         if pyname._has_block()]
+        def block_compare(x, y):
+            return cmp(x._get_ast().lineno, y._get_ast().lineno)
+        block_objects.sort(cmp=block_compare)
+        result = []
+        for block in block_objects:
+            if block.get_type() == PyType.get_type('Function'):
+                result.append(FunctionScope(self.pycore, block))
+            elif block.get_type() == PyType.get_type('Type'):
+                result.append(ClassScope(self.pycore, block))
+            else:
+                result.append(GlobalScope(self.pycore, block))
+        return result
 
-class _GlobalVisitor(object):
+    def get_lineno(self):
+        return self.pyname._get_ast().lineno
+
+    def get_kind(self):
+        pass
+
+
+class GlobalScope(Scope):
+
+    def __init__(self, pycore, module):
+        super(GlobalScope, self).__init__(pycore, module)
+
+    def get_lineno(self):
+        return 1
+
+    def get_kind(self):
+        return 'Module'
+
+class FunctionScope(Scope):
+    
+    def __init__(self, pycore, pyname):
+        super(FunctionScope, self).__init__(pycore, pyname)
+    
+    def get_names(self):
+        new_visitor = _FunctionVisitor(self.pycore)
+        for n in self.pyname._get_ast().getChildNodes():
+            compiler.walk(n, new_visitor)
+        return new_visitor.names
+
+    def get_scopes(self):
+        new_visitor = _FunctionVisitor(self.pycore)
+        for n in self.pyname._get_ast().getChildNodes():
+            compiler.walk(n, new_visitor)
+        return []
+
+    def get_kind(self):
+        return 'Function'
+
+
+class ClassScope(Scope):
+
+    def get_names(self):
+        return {}
+
+    def get_kind(self):
+        return 'Class'
+
+
+class _ScopeVisitor(object):
 
     def __init__(self, pycore):
         self.names = {}
         self.pycore = pycore
     
     def visitClass(self, node):
-        self.names[node.name] = PyName(_ClassVisitor.make_class(node))
+        self.names[node.name] = PyName(_ClassVisitor.make_class(self.pycore, node), node)
 
     def visitFunction(self, node):
-        self.names[node.name] = PyName(PyObject(PyType.get_type('Function')))
+        self.names[node.name] = PyName(PyObject(PyType.get_type('Function')), node)
 
     def visitAssName(self, node):
         self.names[node.name] = PyName()
                     self.names[imported] = PyName()
 
 
-class _ClassVisitor(object):
+class _GlobalVisitor(_ScopeVisitor):
 
-    def __init__(self):
-        self.names = {}
+    def __init__(self, pycore):
+        super(_GlobalVisitor, self).__init__(pycore)
+    
+
+class _ClassVisitor(_ScopeVisitor):
+
+    def __init__(self, pycore):
+        super(_ClassVisitor, self).__init__(pycore)
 
     def visitFunction(self, node):
-        self.names[node.name] = PyName(PyObject(PyType.get_type('Function')))
+        self.names[node.name] = PyName(PyObject(PyType.get_type('Function')), node)
         if node.name == '__init__':
             new_visitor = _ClassInitVisitor()
             compiler.walk(node, new_visitor)
         self.names[node.name] = PyName()
 
     def visitClass(self, node):
-        self.names[node.name] = PyName(_ClassVisitor.make_class(node))
+        self.names[node.name] = PyName(_ClassVisitor.make_class(self.pycore, node), node)
 
     @staticmethod
-    def make_class(node):
-        new_visitor = _ClassVisitor()
+    def make_class(pycore, node):
+        new_visitor = _ClassVisitor(pycore)
         for n in node.getChildNodes():
             compiler.walk(n, new_visitor)
         return PyType(new_visitor.names)
 
 
+class _FunctionVisitor(_ScopeVisitor):
+
+    def __init__(self, pycore):
+        super(_FunctionVisitor, self).__init__(pycore)
+
+
 class _ClassInitVisitor(object):
 
     def __init__(self):

ropetest/pycoretest.py

         mod = self.pycore.get_string_module('from doesnotexist import nestedmod\n')
         self.assertTrue('nestedmod' in mod.attributes)
 
+    def test_from_import_function(self):
+        scope = self.pycore.get_string_scope('def f():\n    from samplemod import SampleClass\n')
+        self.assertEquals(PyType.get_type('Type'), 
+                          scope.get_scopes()[0].get_names()['SampleClass'].get_type())
+
 
 class PyCoreScopesTest(unittest.TestCase):
 
 
     def test_simple_scope(self):
         scope = self.pycore.get_string_scope('def sample_func():\n    pass\n')
-        self.assertTrue('sample_func' in scope.get_names())
+        sample_func = scope.get_names()['sample_func']
+        self.assertEquals(PyType.get_type('Function'), sample_func.get_type())
 
-    # 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)
+    def test_simple_function_scope(self):
+        scope = self.pycore.get_string_scope('def sample_func():\n    a = 10\n')
+        self.assertEquals(1, len(scope.get_scopes()))
+        sample_func_scope = scope.get_scopes()[0]
+        self.assertEquals(1, len(sample_func_scope.get_names()))
+        self.assertEquals(0, len(sample_func_scope.get_scopes()))
 
-    # 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)
+    def test_classes_inside_function_scopes(self):
+        scope = self.pycore.get_string_scope('def sample_func():\n' +
+                                             '    class SampleClass(object):\n        pass\n')
+        self.assertEquals(1, len(scope.get_scopes()))
+        sample_func_scope = scope.get_scopes()[0]
+        self.assertEquals(PyType.get_type('Type'), 
+                          scope.get_scopes()[0].get_names()['SampleClass'].get_type())
 
+    def test_simple_class_scope(self):
+        scope = self.pycore.get_string_scope('class SampleClass(object):\n' +
+                                             '    def f(self):\n        var = 10\n')
+        self.assertEquals(1, len(scope.get_scopes()))
+        sample_class_scope = scope.get_scopes()[0]
+        self.assertEquals(0, len(sample_class_scope.get_names()))
+        self.assertEquals(1, len(sample_class_scope.get_scopes()))
+        f_in_class = sample_class_scope.get_scopes()[0]
+        self.assertTrue('var' in f_in_class.get_names())
+
+    def test_get_lineno(self):
+        scope = self.pycore.get_string_scope('\ndef sample_func():\n    a = 10\n')
+        self.assertEquals(1, len(scope.get_scopes()))
+        sample_func_scope = scope.get_scopes()[0]
+        self.assertEquals(1, scope.get_lineno())
+        self.assertEquals(2, sample_func_scope.get_lineno())
+
+    def test_scope_kind(self):
+        scope = self.pycore.get_string_scope('class SampleClass(object):\n    pass\n' +
+                                             'def sample_func():\n    pass\n')
+        sample_class_scope = scope.get_scopes()[0]
+        sample_func_scope = scope.get_scopes()[1]
+        self.assertEquals('Module', scope.get_kind())
+        self.assertEquals('Class', sample_class_scope.get_kind())
+        self.assertEquals('Function', sample_func_scope.get_kind())
 
 def suite():
     result = unittest.TestSuite()