[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