"""
Outputs web.py docs as html
version 2.0: documents all code, and indents nicely.
By Colin Rothwell (TheBoff)
"""
import inspect
import sys
import markdown
from web.net import websafe
sys.path.insert(0, "..")
ALL_MODULES = [
"web.application",
"web.contrib.template",
"web.db",
"web.debugerror",
"web.form",
"web.http",
"web.httpserver",
"web.net",
"web.session",
"web.template",
"web.utils",
"web.webapi",
"web.wsgi",
]
item_start = ''
item_end = "
"
indent_amount = 30
doc_these = ( # These are the types of object that should be docced
"module",
"classobj",
"instancemethod",
"function",
"type",
"property",
)
not_these_names = ( # Any particular object names that shouldn't be doced
"fget",
"fset",
"fdel",
"storage", # These stop the lower case versions getting docced
"memoize",
"iterbetter",
"capturesstdout",
"profile",
"threadeddict",
"d", # Don't know what this is, but only only conclude it shouldn't be doc'd
)
css = """
"""
indent_start = '
'
indent_end = "
"
header = """
"""
def type_string(ob):
return str(type(ob)).split("'")[1]
def ts_css(text):
"""applies nice css to the type string"""
return '%s' % text
def arg_string(func):
"""Returns a nice argstring for a function or method"""
return inspect.formatargspec(*inspect.getargspec(func))
def recurse_over(ob, name, indent_level=0):
ts = type_string(ob)
if ts not in doc_these:
return # stos what shouldn't be docced getting docced
if indent_level > 0 and ts == "module":
return # Stops it getting into the stdlib
if name in not_these_names:
return # Stops things we don't want getting docced
indent = indent_level * indent_amount # Indents nicely
ds_indent = indent + (indent_amount / 2)
if indent_level > 0:
print(indent_start % indent)
argstr = ""
if ts.endswith(("function", "method")):
argstr = arg_string(ob)
elif ts in {"classobj", "type"}:
if ts == "classobj":
ts = "class"
if hasattr(ob, "__init__"):
if type_string(ob.__init__) == "instancemethod":
argstr = arg_string(ob.__init__)
else:
argstr = "(self)"
if ts == "instancemethod":
ts = "method" # looks much nicer
ds = inspect.getdoc(ob)
if ds is None:
ds = ""
ds = markdown.Markdown(ds)
mlink = '' % name if ts == "module" else ""
mend = "" if ts == "module" else ""
print(
"".join(
(
"
",
ts_css(ts),
item_start % ts,
" ",
mlink,
name,
websafe(argstr),
mend,
item_end,
"
",
)
)
)
print("".join((indent_start % ds_indent, ds, indent_end, "
")))
# Although ''.join looks weird, it's a lot faster is string addition
members = ""
if hasattr(ob, "__all__"):
members = ob.__all__
else:
members = [item for item in dir(ob) if not item.startswith("_")]
if "im_class" not in members:
for name in members:
recurse_over(getattr(ob, name), name, indent_level + 1)
if indent_level > 0:
print(indent_end)
def main(modules=None):
modules = modules or ALL_MODULES
print("") # Stops markdown vandalising my html.
print(css)
print(header)
print("
")
for name in modules:
print('- {name}
'.format(**dict(name=name)))
print("
")
for name in modules:
try:
mod = __import__(name, {}, {}, "x")
recurse_over(mod, name)
except ImportError as e:
print(f"Unable to import module {name} (Error: {e})", file=sys.stderr)
pass
print("
")
if __name__ == "__main__":
main(sys.argv[1:])