[py-svn] r33839 - in py/dist/py: apigen/rest apigen/rest/testing apigen/tracer apigen/tracer/testing code documentation misc
fijal at codespeak.net
fijal at codespeak.net
Sat Oct 28 22:17:20 CEST 2006
Author: fijal
Date: Sat Oct 28 22:17:16 2006
New Revision: 33839
Modified:
py/dist/py/apigen/rest/genrest.py
py/dist/py/apigen/rest/testing/test_rest.py
py/dist/py/apigen/tracer/description.py
py/dist/py/apigen/tracer/docstorage.py
py/dist/py/apigen/tracer/testing/test_docgen.py
py/dist/py/apigen/tracer/testing/test_magic.py
py/dist/py/apigen/tracer/tracer.py
py/dist/py/code/code.py
py/dist/py/code/traceback2.py
py/dist/py/documentation/conftest.py
py/dist/py/misc/rest.py
Log:
Added various improvements to traceback generation for call sites.
Modified: py/dist/py/apigen/rest/genrest.py
==============================================================================
--- py/dist/py/apigen/rest/genrest.py (original)
+++ py/dist/py/apigen/rest/genrest.py Sat Oct 28 22:17:16 2006
@@ -120,6 +120,7 @@
self.dsa = DocStorageAccessor(ds)
self.linkgen = linkgen
self.writer = writer
+ self.traceback_no = 0
def write(self):
"""write the data to the writer"""
@@ -348,34 +349,50 @@
# call sites..
call_site_title = Title("Call sites:", belowchar='+')
lst.append(call_site_title)
- call_sites = lst
- for call_site, frame in self.dsa.get_function_callpoints(functionname):
- link_str = "File %s:%s" % (call_site.filename,
- call_site.lineno)
- link_str, link_target = self.linkgen.getlink(call_site.filename,
- call_site.lineno)
- if link_target: # otherwise it's just inline text
- call_sites.append(Paragraph(Link(link_str, link_target)))
- else:
- call_sites.append(Paragraph(link_str))
- #call_sites.append(LiteralBlock(call_site.source))
- # XXX: For now, we just paste here the filename of that
- #call_sites.append(Paragraph(link_str))
- try:
- source = frame.code.source()
- except KeyboardInterrupt, SystemError:
- raise
- except:
- source = "*Cannot get source*"
- lines = []
- for num, line in enumerate(source):
- if num == call_site.lineno - frame.code.firstlineno - 1:
- m = re.match("^( *)(.*)", line)
- lines.append(">%s%s" % ("-" * len(m.group(1)), m.group(2)))
- else:
- lines.append(" " + line)
- call_sites.append(LiteralBlock("\n".join(lines)))
+ # we have to think differently here. I would go for:
+ # 1. A quick'n'dirty statement where call has appeared first (topmost)
+ # 2. Link to short traceback
+ # 3. Link to long traceback
+ for call_site, _ in self.dsa.get_function_callpoints(functionname):
+ self.write_call_site_link(call_site, lst)
+## for call_site, frame in self.dsa.get_function_callpoints(functionname):
+## link_str = "File %s:%s" % (call_site.filename,
+## call_site.lineno)
+## link_str, link_target = self.linkgen.getlink(call_site.filename,
+## call_site.lineno)
+## if link_target: # otherwise it's just inline text
+## call_sites.append(Paragraph(Link(link_str, link_target)))
+## else:
+## call_sites.append(Paragraph(link_str))
+## #call_sites.append(LiteralBlock(call_site.source))
+## # XXX: For now, we just paste here the filename of that
+## #call_sites.append(Paragraph(link_str))
+## try:
+## source = frame.code.source()
+## except KeyboardInterrupt, SystemError:
+## raise
+## except:
+## source = "*Cannot get source*"
+## lines = []
+## for num, line in enumerate(source):
+## if num == call_site.lineno - frame.code.firstlineno - 1:
+## m = re.match("^( *)(.*)", line)
+## lines.append(">%s%s" % ("-" * len(m.group(1)), m.group(2)))
+## else:
+## lines.append(" " + line)
+## call_sites.append(LiteralBlock("\n".join(lines)))
return lst
+ def write_call_site_link(self, call_site, lst):
+ name = self.gen_traceback(call_site)
+ lst.append(Paragraph("Called in %s" % call_site[0].code.filename, Link\
+ ("Full %s" % name, name + '.html')))
+
+ def gen_traceback(self, call_site):
+ name = "traceback_%d" % self.traceback_no
+ self.traceback_no += 1
+ print name
+ self.writer.write_section(name, Rest(*[Title("Random traceback here")]).text())
+ return name
Modified: py/dist/py/apigen/rest/testing/test_rest.py
==============================================================================
--- py/dist/py/apigen/rest/testing/test_rest.py (original)
+++ py/dist/py/apigen/rest/testing/test_rest.py Sat Oct 28 22:17:16 2006
@@ -12,6 +12,8 @@
from py.__.apigen.tracer.docstorage import DocStorage
from py.__.apigen.tracer.testing.runtest import cut_pyc
+from py.__.documentation.conftest import genlinkchecks
+# XXX: UUuuuuuuuuuuuuuuuuuuuuuuu, dangerous import
def setup_module(mod):
mod.temppath = py.test.ensuretemp('restgen')
@@ -157,6 +159,9 @@
from py.__.misc import rest
for path in tempdir.listdir('*.txt'):
rest.process(path)
+ for path in tempdir.listdir('*.txt'):
+ for item, arg1, arg2, arg3 in genlinkchecks(path):
+ item(arg1, arg2, arg3)
def test_generation_simple_api(self):
ds = self.get_filled_docstorage()
@@ -175,6 +180,11 @@
'method_SomeSubClass.__init__.txt',
'method_SomeSubClass.method.txt',
'module_Unknown module.txt',
+ 'traceback_0.txt',
+ 'traceback_1.txt',
+ 'traceback_2.txt',
+ 'traceback_3.txt',
+ 'traceback_4.txt',
]
# now we check out...
self.check_rest(tempdir)
@@ -200,6 +210,11 @@
'module_Unknown module.txt',
'module_somemodule.txt',
'module_someothermodule.txt',
+ 'traceback_0.txt',
+ 'traceback_1.txt',
+ 'traceback_2.txt',
+ 'traceback_3.txt',
+ 'traceback_4.txt',
]
assert sorted(basenames) == expected
Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py (original)
+++ py/dist/py/apigen/tracer/description.py Sat Oct 28 22:17:16 2006
@@ -1,35 +1,82 @@
+import py
from py.__.apigen.tracer import model
import types
+import inspect
-class CallSite(object):
- def __init__(self, filename, lineno):
- self.filename = filename
- self.lineno = lineno
+class CallStack(object):
+ def __init__(self, tb):
+ if isinstance(tb, py.code.Traceback):
+ self.tb = tb
+ else:
+ self.tb = py.code.Traceback(tb)
- def get_tuple(self):
- return self.filename, self.lineno
+ def _getval(self):
+ return [(frame.code.raw.co_filename, frame.lineno+1) for frame
+ in self]
def __hash__(self):
- return hash((self.filename, self.lineno))
+ return hash(tuple(self._getval()))
def __eq__(self, other):
- return (self.filename, self.lineno) == (other.filename, other.lineno)
+ return self._getval() == other._getval()
def __ne__(self, other):
return not self == other
+ def __getattr__(self, attr):
+ return getattr(self.tb, attr)
+
+ def __iter__(self):
+ return iter(self.tb)
+
+ def __getitem__(self, item):
+ return self.tb[item]
+
+ def __len__(self):
+ return len(self.tb)
+
def __cmp__(self, other):
- if self.filename < other.filename:
- return -1
- if self.filename > other.filename:
- return 1
- if self.lineno < other.lineno:
- return -1
- if self.lineno > other.lineno:
- return 1
- return 0
+ return cmp(self._getval(), other._getval())
+
+def cut_stack(stack, frame, upward_frame=None):
+ if hasattr(frame, 'raw'):
+ frame = frame.raw
+ if upward_frame:
+ if hasattr(upward_frame, 'raw'):
+ upward_frame = upward_frame.raw
+ return CallStack([py.code.Frame(i) for i in stack[stack.index(frame):\
+ stack.index(upward_frame)+1]])
+ return CallStack([py.code.Frame(i) for i in stack[stack.index(frame):]])
+
+##class CallSite(object):
+## def __init__(self, filename, lineno):
+## self.filename = filename
+## self.lineno = lineno
+##
+## def get_tuple(self):
+## return self.filename, self.lineno
+##
+## def __hash__(self):
+## return hash((self.filename, self.lineno))
+##
+## def __eq__(self, other):
+## return (self.filename, self.lineno) == (other.filename, other.lineno)
+##
+## def __ne__(self, other):
+## return not self == other
+##
+## def __cmp__(self, other):
+## if self.filename < other.filename:
+## return -1
+## if self.filename > other.filename:
+## return 1
+## if self.lineno < other.lineno:
+## return -1
+## if self.lineno > other.lineno:
+## return 1
+## return 0
class NonHashableObject(object):
def __init__(self, cls):
@@ -77,16 +124,11 @@
for cell_num, cell in enumerate(inputcells):
self.inputcells[cell_num] = model.unionof(cell, self.inputcells[cell_num])
- def consider_call_site(self, frame):
- cs = CallSite(frame.code.raw.co_filename, frame.lineno+1)
- if self.keep_frames:
- if cs in self.call_sites:
- self.call_sites[cs].append(self.frame_copier(frame))
- else:
- self.call_sites[cs] = [self.frame_copier(frame)]
- else:
- # frame copier makes no sense if we want to keep only one
- self.call_sites[cs] = frame
+ def consider_call_site(self, frame, cut_frame):
+ stack = [i[0] for i in inspect.stack()]
+ cs = cut_stack(stack, frame, cut_frame)
+ print cs, hash(cs), cs._getval()
+ self.call_sites[cs] = cs
def get_call_sites(self):
# convinient accessor for various data which we keep there
@@ -148,8 +190,8 @@
def consider_return(self, arg):
pass # we *know* what return value we do have
- def consider_call_site(self, frame):
- self.fields['__init__'].consider_call_site(frame)
+ def consider_call_site(self, frame, cut_frame):
+ self.fields['__init__'].consider_call_site(frame, cut_frame)
def add_method_desc(self, name, methoddesc):
self.fields[name] = methoddesc
Modified: py/dist/py/apigen/tracer/docstorage.py
==============================================================================
--- py/dist/py/apigen/tracer/docstorage.py (original)
+++ py/dist/py/apigen/tracer/docstorage.py Sat Oct 28 22:17:16 2006
@@ -15,12 +15,12 @@
class DocStorage(object):
""" Class storing info about API
"""
- def consider_call(self, frame, caller_frame):
+ def consider_call(self, frame, caller_frame, upward_cut_frame=None):
assert isinstance(frame, py.code.Frame)
desc = self.find_desc(frame.code)
if desc:
self.generalize_args(desc, frame)
- desc.consider_call_site(caller_frame)
+ desc.consider_call_site(caller_frame, upward_cut_frame)
def generalize_args(self, desc, frame):
args = [arg for key, arg in frame.getargs()]
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 Sat Oct 28 22:17:16 2006
@@ -41,10 +41,13 @@
cs = sorted(desc.call_sites.keys())
assert len(cs) == 2
f_name = cut_pyc(__file__)
- assert cs[0].filename == f_name
- assert cs[0].lineno == test_basic.func_code.co_firstlineno + 5
- assert cs[1].filename == f_name
- assert cs[1].lineno == test_basic.func_code.co_firstlineno + 6
+ assert len(cs[0]) == 1
+ assert len(cs[1]) == 1
+ assert cs[0][0].code.filename == f_name
+ # lines are counted from 0
+ assert cs[0][0].lineno == test_basic.func_code.co_firstlineno + 4
+ assert cs[1][0].code.filename == f_name
+ assert cs[1][0].lineno == test_basic.func_code.co_firstlineno + 5
class AClass(object):
""" Class docstring
@@ -82,8 +85,9 @@
f_name = f_name[:-1]
cs = sorted(desc.fields['__init__'].call_sites.keys())
assert len(cs) == 1
- assert cs[0].filename == f_name
- assert cs[0].lineno == test_class.func_code.co_firstlineno + 5
+ assert len(cs[0]) == 1
+ assert cs[0][0].code.filename == f_name
+ assert cs[0][0].lineno == test_class.func_code.co_firstlineno + 4
# method check
assert sorted(desc.getfields()) == ['__init__', 'exposed_method']
inputcells = desc.fields['exposed_method'].inputcells
@@ -120,7 +124,7 @@
t.end_tracing()
desc = ds.descs["other_fun"]
assert len(desc.call_sites.keys()) == 1
- assert isinstance(desc.call_sites.values()[0], py.code.Frame)
+ assert isinstance(desc.call_sites.values()[0][0], py.code.Frame)
class A(object):
def method(self, x):
Modified: py/dist/py/apigen/tracer/testing/test_magic.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_magic.py (original)
+++ py/dist/py/apigen/tracer/testing/test_magic.py Sat Oct 28 22:17:16 2006
@@ -2,6 +2,9 @@
""" test magic abilities of tracer
"""
+import py
+py.test.skip("These features has been disabled")
+
from py.__.apigen.tracer.magic import trace, get_storage, stack_copier, \
DocStorageKeeper
from py.__.apigen.tracer.docstorage import DocStorage
Modified: py/dist/py/apigen/tracer/tracer.py
==============================================================================
--- py/dist/py/apigen/tracer/tracer.py (original)
+++ py/dist/py/apigen/tracer/tracer.py Sat Oct 28 22:17:16 2006
@@ -26,7 +26,7 @@
frame = py.code.Frame(frame)
if event == 'call':
assert arg is None
- self.docstorage.consider_call(frame, py.code.Frame(sys._getframe(2)))
+ self.docstorage.consider_call(frame, py.code.Frame(sys._getframe(2)), self.frame)
elif event == 'return':
self.docstorage.consider_return(frame, arg)
@@ -36,6 +36,7 @@
if self.tracing:
return
self.tracing = True
+ self.frame = py.code.Frame(sys._getframe(1))
sys.settrace(self._tracer)
def end_tracing(self):
Modified: py/dist/py/code/code.py
==============================================================================
--- py/dist/py/code/code.py (original)
+++ py/dist/py/code/code.py Sat Oct 28 22:17:16 2006
@@ -5,6 +5,7 @@
rawcode = getattr(rawcode, 'im_func', rawcode)
rawcode = getattr(rawcode, 'func_code', rawcode)
self.raw = rawcode
+ self.filename = rawcode.co_filename
try:
self.firstlineno = rawcode.co_firstlineno - 1
except AttributeError:
Modified: py/dist/py/code/traceback2.py
==============================================================================
--- py/dist/py/code/traceback2.py (original)
+++ py/dist/py/code/traceback2.py Sat Oct 28 22:17:16 2006
@@ -133,7 +133,7 @@
return i
l.append(entry.frame.f_locals)
return None
-
+
# def __str__(self):
# for x in self
# l = []
Modified: py/dist/py/documentation/conftest.py
==============================================================================
--- py/dist/py/documentation/conftest.py (original)
+++ py/dist/py/documentation/conftest.py Sat Oct 28 22:17:16 2006
@@ -108,7 +108,7 @@
pass
def teardown(self):
pass
- def run(self):
+ def run(self):
return [self.fspath.basename, 'checklinks', 'doctest']
def join(self, name):
if name == self.fspath.basename:
Modified: py/dist/py/misc/rest.py
==============================================================================
--- py/dist/py/misc/rest.py (original)
+++ py/dist/py/misc/rest.py Sat Oct 28 22:17:16 2006
@@ -39,8 +39,8 @@
def process(txtpath, encoding='latin1'):
""" process a textfile """
- log("processing %s" % txtpath)
- assert txtpath.check(ext='.txt')
+ log("processing %s" % txtpath)
+ assert txtpath.check(ext='.txt')
if isinstance(txtpath, py.path.svnwc):
txtpath = txtpath.localpath
htmlpath = txtpath.new(ext='.html')
@@ -48,12 +48,12 @@
style = txtpath.dirpath('style.css')
if style.check():
- stylesheet = style.basename
+ stylesheet = style.basename
else:
stylesheet = None
content = unicode(txtpath.read(), encoding)
- doc = convert_rest_html(content, txtpath, stylesheet=stylesheet, encoding=encoding)
- htmlpath.write(doc)
+ doc = convert_rest_html(content, txtpath, stylesheet=stylesheet, encoding=encoding)
+ htmlpath.write(doc)
#log("wrote %r" % htmlpath)
#if txtpath.check(svnwc=1, versioned=1):
# info = txtpath.info()
More information about the pytest-commit
mailing list