[py-svn] r34652 - in py/dist/py/apigen/tracer: . testing

guido at codespeak.net guido at codespeak.net
Thu Nov 16 10:29:08 CET 2006


Author: guido
Date: Thu Nov 16 10:29:03 2006
New Revision: 34652

Modified:
   py/dist/py/apigen/tracer/description.py
   py/dist/py/apigen/tracer/docstorage.py
   py/dist/py/apigen/tracer/testing/test_desc.py
   py/dist/py/apigen/tracer/testing/test_docgen.py
   py/dist/py/apigen/tracer/tracer.py
Log:
Added support for finding out a method's origin (class on which it was defined
or overriden), improved base classes handling a bit, fixed too long lines.


Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py	(original)
+++ py/dist/py/apigen/tracer/description.py	Thu Nov 16 10:29:03 2006
@@ -235,9 +235,21 @@
     
     def getfields(self):
         # return fields of values that has been used
-        l = [i for i, v in self.fields.iteritems() if (not i.startswith('_') or\
-            i.startswith('__'))]
+        l = [i for i, v in self.fields.iteritems() if (not i.startswith('_')
+             or i.startswith('__'))]
         return l
+
+    def getbases(self):
+        bases = []
+        tovisit = [self.pyobj]
+        while tovisit:
+            current = tovisit.pop()
+            if current is not self.pyobj:
+                bases.append(current)
+            tovisit += [b for b in current.__bases__ if b not in bases]
+        return bases
+    bases = property(getbases)
+    
 ##    def has_code(self, code):
 ##        # check __init__ method
 ##        return self.pyobj.__init__.im_func.func_code is code

Modified: py/dist/py/apigen/tracer/docstorage.py
==============================================================================
--- py/dist/py/apigen/tracer/docstorage.py	(original)
+++ py/dist/py/apigen/tracer/docstorage.py	Thu Nov 16 10:29:03 2006
@@ -7,8 +7,8 @@
 import sys
 import types
 
-from py.__.apigen.tracer.description import FunctionDesc, ClassDesc, MethodDesc, \
-    Desc
+from py.__.apigen.tracer.description import FunctionDesc, ClassDesc, \
+                                            MethodDesc, Desc
 
 from py.__.apigen.tracer import model
 
@@ -179,10 +179,12 @@
         return [i for i, desc in self.ds.descs.iteritems() if filter(i, desc)]
 
     def get_function_names(self):
-        return sorted(self._get_names(lambda i, desc: type(desc) is FunctionDesc))
+        return sorted(self._get_names(lambda i, desc: type(desc) is
+                                                      FunctionDesc))
     
     def get_class_names(self):
-        return sorted(self._get_names(lambda i, desc: isinstance(desc, ClassDesc)))
+        return sorted(self._get_names(lambda i, desc: isinstance(desc,
+                                                                 ClassDesc)))
     
     #def get_function(self, name):
     #    return self.ds.descs[name].pyobj
@@ -199,7 +201,8 @@
     def get_function_signature(self, name):
         desc = self.ds.descs[name]
         # we return pairs of (name, type) here
-        names = desc.pyobj.func_code.co_varnames[:desc.pyobj.func_code.co_argcount]
+        names = desc.pyobj.func_code.co_varnames[
+                    :desc.pyobj.func_code.co_argcount]
         types = desc.inputcells
         return zip(names, types), desc.retval
     
@@ -255,10 +258,38 @@
     def get_function_exceptions(self, name):
         return sorted(self.ds.descs[name].exceptions.keys())
 
-    def get_possible_base_classes(self, cls):
+    def get_method_origin(self, name):
+        method = self.ds.descs[name].pyobj
+        cls = method.im_class
+        if not cls.__bases__:
+            return self.desc_from_pyobj(cls)
+        curr = cls
+        while curr:
+            for base in curr.__bases__:
+                basefunc = getattr(base, method.im_func.func_name, None)
+                if (basefunc is not None and hasattr(basefunc, 'im_func') and
+                        hasattr(basefunc.im_func, 'func_code') and
+                        basefunc.im_func.func_code is
+                            method.im_func.func_code):
+                    curr = base
+                    break
+            else:
+                break
+        return self.desc_from_pyobj(curr)
+
+    def get_possible_base_classes(self, name):
+        cls = self.ds.descs[name].pyobj
+        if not hasattr(cls, '__bases__'):
+            return []
         retval = []
         for base in cls.__bases__:
-            for desc in self.ds.descs.values():
-                if isinstance(desc, ClassDesc) and desc.pyobj is base:
-                    retval.append(desc)
+            desc = self.desc_from_pyobj(base)
+            if desc is not None:
+                retval.append(desc)
         return retval
+
+    def desc_from_pyobj(self, pyobj):
+        for desc in self.ds.descs.values():
+            if isinstance(desc, ClassDesc) and desc.pyobj is pyobj:
+                return desc
+

Modified: py/dist/py/apigen/tracer/testing/test_desc.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_desc.py	(original)
+++ py/dist/py/apigen/tracer/testing/test_desc.py	Thu Nov 16 10:29:03 2006
@@ -23,3 +23,7 @@
     assert hash(ClassDesc("b", B).code)
     assert hash(ClassDesc("c", C).code)
     assert hash(ClassDesc("d", D).code)
+
+def test_eq():
+    py.test.skip('fijal, please fix ;)')
+    assert ClassDesc('a', A) == ClassDesc('a', A)

Modified: py/dist/py/apigen/tracer/testing/test_docgen.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_docgen.py	(original)
+++ py/dist/py/apigen/tracer/testing/test_docgen.py	Thu Nov 16 10:29:03 2006
@@ -66,6 +66,11 @@
         """
         return "z"
 
+class ANotherClass(AClass):
+    def another_exposed_method(self, a):
+        # no docstring
+        return a
+
 def test_class():
     descs = {'AClass':AClass}
     ds = DocStorage().from_dict(descs)
@@ -144,8 +149,10 @@
     x.method(3)
     y.method(4)
     t.end_tracing()
-    assert isinstance(ds.descs['A'].fields['method'].inputcells[1], model.SomeInt)
-    assert isinstance(ds.descs['B'].fields['method'].inputcells[1], model.SomeInt)
+    assert isinstance(ds.descs['A'].fields['method'].inputcells[1],
+                      model.SomeInt)
+    assert isinstance(ds.descs['B'].fields['method'].inputcells[1],
+                      model.SomeInt)
 
 def test_local_changes():
     class testclass(object):
@@ -218,6 +225,23 @@
     assert ds.descs['y'].exceptions.keys() == [ZeroDivisionError]
     assert ds.descs['z'].exceptions.keys() == []
 
+def test_subclass():
+    descs = {'ANotherClass': ANotherClass}
+    ds = DocStorage().from_dict(descs)
+    t = Tracer(ds)
+    t.start_tracing()
+    s = ANotherClass('blah blah')
+    s.another_exposed_method(1)
+    t.end_tracing()
+    desc = ds.descs['ANotherClass']
+    assert len(desc.fields) == 4
+    inputcells = desc.fields['__init__'].inputcells
+    assert len(inputcells) == 2
+    inputcells = desc.fields['another_exposed_method'].inputcells
+    assert len(inputcells) == 2
+    bases = desc.bases
+    assert len(bases) == 2
+    
 def test_bases():
     class A:
         pass
@@ -230,4 +254,34 @@
     
     ds = DocStorage().from_dict({'C':C, 'B':B})
     dsa = DocStorageAccessor(ds)
-    assert dsa.get_possible_base_classes(C) == [ds.descs['B']]
+    assert dsa.get_possible_base_classes('C') == [ds.descs['B']]
+
+def test_desc_from_pyobj():
+    class A:
+        pass
+
+    class B(A):
+        pass
+
+    ds = DocStorage().from_dict({'A': A, 'B': B})
+    dsa = DocStorageAccessor(ds)
+    assert dsa.desc_from_pyobj(A) is ds.descs['A']
+
+def test_method_origin():
+    class A:
+        def foo(self):
+            pass
+
+    class B(A):
+        def bar(self):
+            pass
+
+    class C(B):
+        pass
+
+    ds = DocStorage().from_dict({'C': C, 'B': B})
+    dsa = DocStorageAccessor(ds)
+    origin = dsa.get_method_origin('C.bar')
+    assert origin is ds.descs['B']
+    assert dsa.get_method_origin('C.foo') is None
+

Modified: py/dist/py/apigen/tracer/tracer.py
==============================================================================
--- py/dist/py/apigen/tracer/tracer.py	(original)
+++ py/dist/py/apigen/tracer/tracer.py	Thu Nov 16 10:29:03 2006
@@ -52,3 +52,4 @@
     def end_tracing(self):
         self.tracing = False
         sys.settrace(None)
+


More information about the py-svn mailing list