Anonymous committed 6edca7d


Comments (0)

Files changed (12)

 New Features
+* Enhanced static object inference
+* Holding per name information for builtin containers
+* Change signature for constructors
+* Adding 'rename when unsure' option
+* Enhanced returned object static object inference
+* Supporting generator functions
+* Handling ``*args`` and ``**kwds`` arguments
+* Showing pydoc for some of builtin types and functions
+* Filling paragraphs in text modes; ``M-q``
+* Yanking; ``M-y``
+* Repeating last command; ``C-x z``
+* Enhancing show pydoc to include docs from superclasses
+The most interesting features added in this release are related to
+rope's object inference mechanisms.  I'd rather show some small
+examples than going into to much detail here.
+Enhanced static returned object inference::
+    class C(object):
+        def c_func(self):
+            return ['']
+    def a_func(arg):
+        return arg.c_func()
+    a_var = a_func(C)
+Here rope knows that the type of a_var is a `list` that holds `str`\s.
+Supporting generator functions::
+  class C(object):
+      pass
+  def a_generator():
+      yield C()
+  for c in a_generator():
+      a_var = c
+Here the objects `a_var` and `c` hold are known.
+Another thing that has been added is SOI analysis (Available in
+``Edit`` menu or by using ``C-c x s``).  It analyzes a module for
+finding useful object information.  Currently it is used only when the
+user askes (Just like DOI), but in future that might change.
+Many kinds of information is collected during SOI like per name data
+for builtin container types::
+  l1 = [C()]
+  var1 = l1.pop()
+  l2 = []
+  l2.append(C())
+  var2 = l2.pop()
+Here rope knowns the type of `var1` without doing anything.  But for
+knowing the type of `var2` we need to analyze the items added to `l2`
+which might happen in other modules.  Rope can find out that by
+running SOI analysis on this module.
+You might be wondering is there any reason for using DOI instead of
+SOI.  The answer is that DOI is more accurate and handles complex and
+dynamic situations.  For example in::
+  def f(arg):
+      return eval(arg)
+  a_var = f('C')
+SOI can no way conclude the object `a_var` holds but it is really
+trivial for DOI.  What's more SOI analyzes calls only in one module
+while DOI analyzes any call that happens when running a module.  That
+is for achieving the same result as DOI you might need to run SOI on
+more than one module and more than once (not considering dynamic
+situations.) One advantage of SOI is that it is much faster than DOI.
+Many enhancements to rope's object inference has been planned and till
+``0.5`` release most of them will be implemented.  I'll write more
+about them in future releases.
+'Rename when unsure' option has been added to rename refactoring.  This
+option tells rope to rename when it doesn't know whether it is an exact
+match or not.  For example after renaming `C.a_func` when the
+'rename when unsure' option is set in::
+  class C(object):
+      def a_func(self):
+          pass
+  def a_func(arg):
+      arg.a_func()
+  C().a_func()
+we would have::
+  class C(object):
+      def new_func(self):
+          pass
+  def a_func(arg):
+      arg.new_func()
+  C().new_func()
+Note that the global `a_func` was not renamed because we are sure that
+it is not a match.  But when using this option there might be some
+unexpected renames.  So only use this option when the name is not
+another python defined elements.
 Getting Started
 The main motive for starting this project was the lack of good
-refactoring tools for python language.  Refactoring programs like
-"bicycle repair man" aren't reliable due to type inference problems
-and they support a limited number of refactorings.  *Rope* tries to
-improve these limitations.
+refactoring tools for Python programming language.  Refactoring
+programs like "bicycle repair man" aren't reliable due to type
+inference problems and they support a limited number of refactorings.
+*Rope* tries to improve these limitations.
 * Why an IDE and not a standalone library or program?


+> Public Release 0.5m3 : March 18, 2007
 - Holding per name information for builtin containers : March 17, 2007


 * Supporting templates in text modes
-* Supporting modules without source code
 * Lambdas as functions; consider their parameters
 * Moving `staticmethod`\s
-> Public Release 0.5m3 : March 18, 2007
+> Public Release 0.5m4 : April 1, 2007
+* Supporting modules without source code


-Holding Per Name Information
+Small Stories
-- `list`\s
-- `dict`\s
-- Passing `PyName`\s to `ObjectArguments`
-- ``d.update([(1, 2)])``
-- `set`\s
-- Removing `BuiltinFunction`; using `PerNameFunction` instead
+- Properties and passing arguments
+- Removing args' default for `AbstractFunction.get_returned_value()`
-* Removing args' default for `AbstractFunction.get_returned_value()`
-* Remove duplication in `SOIVisitor`
 * Remove duplication between `Evaluator` and `SOIVisitor`
 * `__setslice__`?
 * Moving `Arguments`, `ObjectArguments` and `_CallContext`;
   `rope.base.args` or `callcontext` module
-* What sins did we make in `staticoi` and `evaluate`
-* Handling slices?
-* Refactor `builtins`
 * Adding an option not to collect per name information
-* Better per object data holding in `callinfo`
+* Better per name data holding in `callinfo`
 * Not overwriting useful per object data in `callinfo`
 * Some `self`\s are unknown!
 * Handling lists in fill paragraph
 * Evaluate function parameter defaults in staticoi?
 * Adding 'do when unsure' to all refactorings?
-* Profiling rope
+* Profiling before ``0.5``
 Remaining Small Stories
 * Object Inference
   * A dynamic object inference approach
-  * A simple static type inference approach
+  * A static object inference approach
   * Handling built-in container types


     def _get_scope_and_pyname(self, pyname):
         if pyname is not None and isinstance(pyname, pynames.AssignedName):
             pymodule, lineno = pyname.get_definition_location()
-            if pymodule is None or lineno is None:
+            if pymodule is None:
                 return None, None
+            if lineno is None:
+                lineno = 1
             scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
             name = None
             while name is None and scope is not None:
     def get_attributes(self):
         return self.attributes
-    def get_returned_object(self, args=None):
+    def get_returned_object(self, args):
         return self.holding
 get_iterator = _create_builtin_getter(Iterator)
     def get_attributes(self):
         return self.attributes
-    def get_returned_object(self, args=None):
+    def get_returned_object(self, args):
         return self.holding
 get_generator = _create_builtin_getter(Generator)
             '__new__': BuiltinName(BuiltinFunction(function=_property_function))}
         super(Property, self).__init__(property, attributes)
-    def get_property_object(self):
+    def get_property_object(self, args):
         if isinstance(self._fget, pyobjects.AbstractFunction):
-            return self._fget.get_returned_object()
+            return self._fget.get_returned_object(args)
 def _property_function(args):
         self.node = node
         self.scope = scope
-    def get_returned_object(self, args=None):
+    def get_returned_object(self, args):
         result = evaluate.get_statement_result(
             self.scope, self.node.code)
         if result is not None:


             if lineno is None:
                 lineno = self._get_lineno_for_node(assign_node)
             holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
-            pyname = evaluate.get_statement_result(holding_scope, assign_node)
+            primary, pyname = evaluate.get_primary_and_result(holding_scope,
+                                                              assign_node)
             if pyname is not None:
                 result = pyname.get_object()
                 if isinstance(result.get_type(), builtins.Property) and \
-                   holding_scope.get_kind() == 'Class':
-                    return result.get_type().get_property_object()
+                   primary and isinstance(primary.get_object().get_type(),
+                                          pyobjects.PyClass):
+                    return result.get_type().get_property_object(
+                        evaluate.ObjectArguments([primary]))
                 return result
         except pyobjects.IsBeingInferredError:


     def get_param_names(self, special_args=True):
         return []
-    def get_returned_object(self, args=None):
+    def get_returned_object(self, args):
         return get_unknown()
     def get_parameter(self, index):
         return self.parameter_pyobjects.get()[index]
-    def get_returned_object(self, args=None):
+    def get_returned_object(self, args):
         return self.returned.get(args)
     def get_name(self):


     core.rebind_action('swap_mark_and_insert', None)
     core.rebind_action('undo', 'C-z')
     core.rebind_action('redo', 'C-y')
-    core.rebind_action('repeat_last_action', 'C-x z')
+    core.rebind_action('repeat_last_action', None)
     core.rebind_action('undo_project', 'C-Z')
     core.rebind_action('redo_project', 'C-Y')
     core.rebind_action('project_history', None)
     core.rebind_action('comment_region', None)
     core.rebind_action('run_module', 'M-X p')
     core.rebind_action('run_unit_tests', 'M-X t')
-    core.rebind_action('run_soi', None)
+    core.rebind_action('run_soi', 'M-X s')
     core.rebind_action('rename', 'M-R')
     core.rebind_action('move', 'M-V')


         a_var = pymod.get_attribute('a_var').get_object()
         self.assertEquals(c_class, a_var.get_type())
+    def test_properties_and_calling_get_property(self):
+        code = 'class C1(object):\n    pass\n' \
+               'class C2(object):\n    c1 = C1()\n' \
+               '    def get_c1(self):\n        return self.c1\n' \
+               '    p = property(get_c1)\nc2 = C2()\na_var = c2.p\n'
+        self.mod.write(code)
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c1_class = pymod.get_attribute('C1').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c1_class, a_var.get_type())
 class DynamicOITest(unittest.TestCase):


 import ropetest.ui.searchertest
 import ropetest.ui.statusbartest
 import ropetest.ui.uihelperstest
+import ropetest.ui.indentertest
 import ropetest.ui.filltest


 import unittest
 from rope.ui.indenter import PythonCodeIndenter, NormalIndenter
-from ropetest.ui.mockeditortest import GraphicalEditorFactory, MockEditorFactory
+from ropetest.ui.mockeditortest import MockEditorFactory
 class PythonCodeIndenterTest(unittest.TestCase):