[svn r37922] Made that properties (class attributes) are displayed, fixed the links in the
menubar. --HG-- branch : trunk
This commit is contained in:
parent
a128ecb8cf
commit
16f9103a0a
|
@ -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):
|
||||||
|
|
|
@ -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) """
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"'
|
||||||
|
|
||||||
|
|
|
@ -55,3 +55,12 @@ def test_enumerate_and_color():
|
||||||
' <span class="string">"bar"</span>\n'
|
' <span class="string">"bar"</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__')
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue