[py-svn] r37540 - in py/trunk/py/apigen: . testing tracer

guido at codespeak.net guido at codespeak.net
Mon Jan 29 15:20:33 CET 2007


Author: guido
Date: Mon Jan 29 15:20:31 2007
New Revision: 37540

Modified:
   py/trunk/py/apigen/htmlgen.py
   py/trunk/py/apigen/testing/test_apigen_functional.py
   py/trunk/py/apigen/testing/test_htmlgen.py
   py/trunk/py/apigen/tracer/description.py
Log:
Nicer formatting of docstrings (de-indented and such), fixed problem getting
to frame source (IOError that popped up when building the py lib's api docs)
in description.py.


Modified: py/trunk/py/apigen/htmlgen.py
==============================================================================
--- py/trunk/py/apigen/htmlgen.py	(original)
+++ py/trunk/py/apigen/htmlgen.py	Mon Jan 29 15:20:31 2007
@@ -12,6 +12,41 @@
 html = py.xml.html
 raw = py.xml.raw
 
+def deindent(str, linesep=os.linesep):
+    """ de-indent string
+
+        can be used to de-indent Python docstrings, it de-indents the first
+        line to the side always, and determines the indentation of the rest
+        of the text by taking that of the least indented (filled) line
+    """
+    lines = str.split(linesep)
+    normalized = []
+    deindent = None
+    normalized.append(lines[0].strip())
+    for line in lines[1:]:
+        if not line.strip():
+            normalized.append('')
+        else:
+            line = line.rstrip()
+            line = line.replace('\t', '     ')
+            indent = 0
+            for c in line:
+                if c != ' ':
+                    break
+                indent += 1
+            if deindent is None or indent < deindent:
+                deindent = indent
+            normalized.append(line)
+    while normalized[-1] == '':
+        normalized.pop()
+    ret = [normalized[0]]
+    for line in normalized[1:]:
+        if not line:
+            ret.append(line)
+        else:
+            ret.append(line[deindent:])
+    return '%s\n' % (linesep.join(ret),)
+
 # HTML related stuff
 class H(html):
     class Content(html.div):
@@ -50,8 +85,9 @@
     class ParameterDescription(html.div):
         pass
 
-    class Docstring(html.div):
-        style = html.Style(white_space='pre', min_height='3em')
+    class Docstring(html.pre):
+        #style = html.Style(white_space='pre', min_height='3em')
+        pass
 
     class Navigation(html.div):
         style = html.Style(min_height='99%', float='left', margin_top='1.2em',
@@ -309,7 +345,9 @@
         """ build the html for a class method """
         # XXX we may want to have seperate
         func = self.dsa.get_obj(dotted_name)
-        docstring = func.__doc__
+        docstring = func.__doc__ 
+        if docstring:
+            docstring = deindent(docstring)
         localname = func.__name__
         argdesc = get_param_htmldesc(self.linker, func)
         valuedesc = self.build_callable_signature_description(dotted_name)
@@ -343,7 +381,7 @@
         )
         snippet = H.FunctionDescription(
             H.FunctionDef(localname, argdesc),
-            H.Docstring(docstring or H.em('no docstring available')),
+            H.Docstring(docstring or '*no docstring available*'),
             H.div(H.a('show/hide info',
                       href='#',
                       onclick=('showhideel(getnextsibling(this));'
@@ -372,6 +410,8 @@
                     href=self.linker.get_lazyhref(sourcefile)))
 
         docstring = cls.__doc__
+        if docstring:
+            docstring = deindent(docstring)
         methods = self.dsa.get_class_methods(dotted_name)
         basehtml = []
         bases = self.dsa.get_possible_base_classes(dotted_name)
@@ -394,7 +434,7 @@
         snippet = H.ClassDescription(
             # XXX bases HTML
             H.ClassDef('%s(' % (clsname,), *basehtml),
-            H.Docstring(docstring or H.em('no docstring available')),
+            H.Docstring(docstring or '*no docstring available*'),
             sourcelink,
         )
         if methods:
@@ -413,9 +453,11 @@
             docstring = None
         else:
             docstring = obj.__doc__
+            if docstring:
+                docstring = deindent(docstring)
         snippet = H.NamespaceDescription(
             H.NamespaceDef(namespace_dotted_name),
-            H.Docstring(docstring or H.em('no docstring available'))
+            H.Docstring(docstring or '*no docstring available*')
         )
         for dotted_name in sorted(item_dotted_names):
             itemname = dotted_name.split('.')[-1]

Modified: py/trunk/py/apigen/testing/test_apigen_functional.py
==============================================================================
--- py/trunk/py/apigen/testing/test_apigen_functional.py	(original)
+++ py/trunk/py/apigen/testing/test_apigen_functional.py	Mon Jan 29 15:20:31 2007
@@ -69,6 +69,13 @@
             assert pak.main.sub.func(20) is None
             s = pak.main.func(pak.main.SomeTestClass, 10)
             assert isinstance(s, pak.main.SomeTestClass)
+
+            # some nice things to confuse the tracer/storage
+            source = py.code.Source('''\
+                pak.main.sub.func(10)
+            ''')
+            c = compile(str(source), '<test>', 'exec')
+            exec c in globals()
     """))
     return temp, 'pak'
 

Modified: py/trunk/py/apigen/testing/test_htmlgen.py
==============================================================================
--- py/trunk/py/apigen/testing/test_htmlgen.py	(original)
+++ py/trunk/py/apigen/testing/test_htmlgen.py	Mon Jan 29 15:20:31 2007
@@ -43,3 +43,12 @@
     assert dirnames == ['sub']
     assert filenames == ['file1.py', 'file3.c']
 
+def test_deindent():
+    assert htmlgen.deindent('foo\n\n    bar\n    ') == 'foo\n\nbar\n'
+    assert htmlgen.deindent(' foo\n\n    bar\n    ') == 'foo\n\nbar\n'
+    assert htmlgen.deindent('foo\n\n    bar\n    baz') == 'foo\n\nbar\nbaz\n'
+    assert htmlgen.deindent(' foo\n\n    bar\n      baz\n') == (
+        'foo\n\nbar\n  baz\n')
+    assert htmlgen.deindent('foo\n\n      bar\n    baz\n') == (
+        'foo\n\n  bar\nbaz\n')
+

Modified: py/trunk/py/apigen/tracer/description.py
==============================================================================
--- py/trunk/py/apigen/tracer/description.py	(original)
+++ py/trunk/py/apigen/tracer/description.py	Mon Jan 29 15:20:31 2007
@@ -19,7 +19,10 @@
         self.filename = frame.code.raw.co_filename
         self.lineno = frame.lineno
         self.firstlineno = frame.code.firstlineno
-        self.source = getsource(frame.code.raw)
+        try:
+            self.source = getsource(frame.code.raw)
+        except IOError:
+            self.source = "could not get to source"
 
     def _getval(self):
         return (self.filename, self.lineno)



More information about the pytest-commit mailing list