[svn r37922] Made that properties (class attributes) are displayed, fixed the links in the

menubar.

--HG--
branch : trunk
This commit is contained in:
guido 2007-02-04 16:47:33 +01:00
parent a128ecb8cf
commit 16f9103a0a
7 changed files with 107 additions and 26 deletions

View File

@ -48,11 +48,20 @@ class H(html):
H.Hideable('funcinfo', 'funcinfo', valuedesc, csource, H.Hideable('funcinfo', 'funcinfo', valuedesc, csource,
callstack)) callstack))
class PropertyDescription(html.div):
def __init__(self, name, value):
if type(value) not in [str, unicode]:
value = str(value)
if len(value) > 100:
value = value[:100] + '...'
super(H.PropertyDescription, self).__init__(H.strong(name), ': ',
H.em(value),
class_='property')
class ParameterDescription(html.div): class ParameterDescription(html.div):
pass pass
class Docstring(html.pre): class Docstring(html.pre):
style = html.Style(width='100%')
pass pass
class Navigation(html.div): class Navigation(html.div):

View File

@ -17,6 +17,17 @@ raw = py.xml.raw
def is_navigateable(name): def is_navigateable(name):
return (not is_private(name) and name != '__doc__') return (not is_private(name) and name != '__doc__')
def show_property(name):
if not name.startswith('_'):
return True
if name.startswith('__') and name.endswith('__'):
# XXX do we need to skip more manually here?
if (name not in dir(object) and
name not in ['__doc__', '__dict__', '__name__', '__module__',
'__weakref__']):
return True
return False
def deindent(str, linesep='\n'): def deindent(str, linesep='\n'):
""" de-indent string """ de-indent string
@ -351,7 +362,24 @@ class ApiPageBuilder(AbstractPageBuilder):
docstring = cls.__doc__ docstring = cls.__doc__
if docstring: if docstring:
docstring = deindent(docstring) docstring = deindent(docstring)
methods = self.dsa.get_class_methods(dotted_name) if not hasattr(cls, '__name__'):
clsname = 'instance of %s' % (cls.__class__.__name__,)
else:
clsname = cls.__name__
bases = self.build_bases(dotted_name)
properties = self.build_properties(cls)
methods = self.build_methods(dotted_name)
snippet = H.ClassDescription(
# XXX bases HTML
H.ClassDef('%s(' % (clsname,), *bases),
H.Docstring(docstring or '*no docstring available*'),
sourcelink,
*(properties+methods)
)
return snippet
def build_bases(self, dotted_name):
basehtml = [] basehtml = []
bases = self.dsa.get_possible_base_classes(dotted_name) bases = self.dsa.get_possible_base_classes(dotted_name)
for base in bases: for base in bases:
@ -366,23 +394,33 @@ class ApiPageBuilder(AbstractPageBuilder):
if basehtml: if basehtml:
basehtml.pop() basehtml.pop()
basehtml.append('):') basehtml.append('):')
if not hasattr(cls, '__name__'): return basehtml
clsname = 'instance of %s' % (cls.__class__.__name__,)
else: def build_properties(self, cls):
clsname = cls.__name__ properties = []
snippet = H.ClassDescription( for attr in dir(cls):
# XXX bases HTML val = getattr(cls, attr)
H.ClassDef('%s(' % (clsname,), *basehtml), if show_property(attr) and not callable(val):
H.Docstring(docstring or '*no docstring available*'), if isinstance(val, property):
sourcelink, val = '<property object (dynamically calculated value)>'
) properties.append((attr, val))
properties.sort(key=lambda a: a[0]) # sort on name
ret = []
if properties:
ret.append(H.h2('properties:'))
for name, val in properties:
ret.append(H.PropertyDescription(name, val))
return ret
def build_methods(self, dotted_name):
ret = []
methods = self.dsa.get_class_methods(dotted_name)
if methods: if methods:
snippet.append(H.h2('methods:')) ret.append(H.h2('methods:'))
for method in methods: for method in methods:
snippet += self.build_callable_view('%s.%s' % (dotted_name, ret += self.build_callable_view('%s.%s' % (dotted_name,
method)) method))
# XXX properties return ret
return snippet
def build_namespace_view(self, namespace_dotted_name, item_dotted_names): def build_namespace_view(self, namespace_dotted_name, item_dotted_names):
""" build the html for a namespace (module) """ """ build the html for a namespace (module) """

View File

@ -26,9 +26,17 @@ class LayoutPage(confrest.PyPage):
def fill(self): def fill(self):
super(LayoutPage, self).fill() super(LayoutPage, self).fill()
#self.menubar[:] = [] self.update_menubar_links(self.menubar)
self.body.insert(0, self.nav) self.body.insert(0, self.nav)
def update_menubar_links(self, node):
for item in node:
if not isinstance(item, py.xml.Tag):
continue
if (item.__class__.__name__ == 'a' and hasattr(item.attr, 'href')
and not item.attr.href.startswith('http://')):
item.attr.href = self.relpath + '../py/doc/' + item.attr.href
def setup_scripts_styles(self, copyto=None): def setup_scripts_styles(self, copyto=None):
for path, name in self.stylesheets: for path, name in self.stylesheets:
if copyto: if copyto:

View File

@ -18,7 +18,6 @@ div.sidebar .selected a {
#content { #content {
border: 0px; border: 0px;
height: 95%; height: 95%;
width: 100%;
} }
ul { ul {
@ -76,6 +75,10 @@ ul li {
background-color: white; background-color: white;
} }
.property {
font-size: 1.2em;
}
.callstackitem { .callstackitem {
border: 1px solid black; border: 1px solid black;
margin-bottom: 1em; margin-bottom: 1em;

View File

@ -19,6 +19,7 @@ def setup_fs_project(name):
temp.ensure('pak/sometestclass.py').write(py.code.Source("""\ temp.ensure('pak/sometestclass.py').write(py.code.Source("""\
class SomeTestClass(object): class SomeTestClass(object):
" docstring sometestclass " " docstring sometestclass "
someattr = 'somevalue'
def __init__(self, somevar): def __init__(self, somevar):
self.somevar = somevar self.somevar = somevar
@ -129,12 +130,10 @@ def test_apigen_functional():
sometestclass_api = apidir.join('main.SomeTestClass.html') sometestclass_api = apidir.join('main.SomeTestClass.html')
assert sometestclass_api.check(file=True) assert sometestclass_api.check(file=True)
html = sometestclass_api.read() html = sometestclass_api.read()
print html
assert '<a href="main.SomeTestClass.html">SomeTestClass</a>' in html assert '<a href="main.SomeTestClass.html">SomeTestClass</a>' in html
# XXX not linking to method files anymore assert '<strong>someattr</strong>: <em>somevalue</em>' in html
#sometestclass_init_api = apidir.join('main.SomeTestClass.__init__.html')
#assert sometestclass_init_api.check(file=True)
#assert sometestclass_init_api.read().find(
# '<a href="main.SomeTestClass.__init__.html">__init__</a>') > -1
namespace_api = apidir.join('main.html') namespace_api = apidir.join('main.html')
assert namespace_api.check(file=True) assert namespace_api.check(file=True)
html = namespace_api.read() html = namespace_api.read()
@ -156,4 +155,5 @@ def test_apigen_functional():
html = index.read() html = index.read()
print html print html
assert '<a href="test/index.html">test</a>' in html assert '<a href="test/index.html">test</a>' in html
assert 'href="../../py/doc/home.html"'

View File

@ -55,3 +55,12 @@ def test_enumerate_and_color():
' <span class="string">&quot;bar&quot;</span>\n' ' <span class="string">&quot;bar&quot;</span>\n'
'</div>') '</div>')
def test_show_property():
assert htmlgen.show_property('foo')
assert not htmlgen.show_property('_foo')
assert htmlgen.show_property('__foo__')
assert not htmlgen.show_property('__doc__')
assert not htmlgen.show_property('__dict__')
assert not htmlgen.show_property('__name__')
assert not htmlgen.show_property('__class__')

View File

@ -1,5 +1,7 @@
* format docstrings more nicely (with tests) - DONE I guess * format docstrings more nicely (with tests)
DONE I guess
* have the API function view be as informative as possible * have the API function view be as informative as possible
without having to go to the "single method" view without having to go to the "single method" view
@ -10,10 +12,12 @@
viewed. method views (when navigating there through viewed. method views (when navigating there through
the class view) should also have the source there the class view) should also have the source there
DONE I think DONE I think, single method view is gone
* have class-level attributes be displayed * have class-level attributes be displayed
DONE
* use "inherited" doc strings, i.e. for * use "inherited" doc strings, i.e. for
class A: class A:
def meth(self): def meth(self):
@ -25,8 +29,12 @@
B.meth should display the A.meth docstring, probably B.meth should display the A.meth docstring, probably
with special formatting (italics or so). with special formatting (italics or so).
NOT YET DONE (later?)
* factor out some common code in the build_* functions * factor out some common code in the build_* functions
(mostly) DONE
* refactor the apigen/rsession interaction to become * refactor the apigen/rsession interaction to become
cleaner (e.g. apigen's get_documentable_items should cleaner (e.g. apigen's get_documentable_items should
be separately tested and the caller should not need be separately tested and the caller should not need
@ -76,9 +84,15 @@
* add syntax coloring for Python source snippets * add syntax coloring for Python source snippets
DONE
* remove py.test/apigen cruft from stack traces * remove py.test/apigen cruft from stack traces
DONE, thanks to fijal
* fix non-ascii source encoding support * fix non-ascii source encoding support
DONE
* XXX * XXX