i3pystatus/i3pystatus/mkdocs.py
2013-03-05 17:26:10 +01:00

129 lines
3.6 KiB
Python
Executable File

#!/usr/bin/env python
import sys
import io
import pkgutil
from collections import namedtuple
import textwrap
import i3pystatus
import i3pystatus.mail
from .core.imputil import ClassFinder
IGNORE = ("__main__", "mkdocs")
MODULE_FORMAT = """
{heading} {name}
{doc}
{settings}
{endstring}\n"""
class Module:
name = ""
doc = ""
endstring = ""
def __init__(self, cls, neighbours, module_name, module, heading):
self.settings = []
self.cls = cls
self.heading = heading
if neighbours == 1:
self.name = module_name
else:
self.name = "{module}.{cls}".format(module=module_name, cls=self.cls.__name__)
self.doc = self.cls.__doc__ or module.__doc__ or ""
if hasattr(self.cls, "_endstring"):
self.endstring = self.cls._endstring
self.read_settings()
def read_settings(self):
for setting in self.cls.settings:
self.settings.append(Setting(self.cls, setting))
def format_settings(self):
return "\n".join(map(str, self.settings))
def __str__(self):
return MODULE_FORMAT.format(
name=self.name,
doc=textwrap.dedent(self.doc),
settings=self.format_settings(),
heading=self.heading,
endstring=self.endstring
)
class Setting:
doc = ""
required = False
default = sentinel = object()
def __init__(self, cls, setting):
if isinstance(setting, tuple):
self.name = setting[0]
self.doc = setting[1]
else:
self.name = setting
if setting in cls.required:
self.required = True
elif hasattr(cls, self.name):
self.default = getattr(cls, self.name)
def __str__(self):
attrs = []
if self.required:
attrs.append("required")
if self.default is not self.sentinel:
attrs.append("default: `{default}`".format(default=self.default))
formatted = "* `{name}` ".format(name=self.name)
if self.doc or attrs:
formatted += ""
if self.doc:
formatted += self.doc
if attrs:
formatted += " ({attrs})".format(attrs=", ".join(attrs))
return formatted
def get_modules(path):
modules = []
for finder, modname, ispkg in pkgutil.iter_modules(path):
if modname not in IGNORE:
modules.append(get_module(finder, modname))
return modules
def get_module(finder, modname):
fullname = "i3pystatus.{modname}".format(modname=modname)
return (modname, finder.find_loader(fullname)[0].load_module(fullname))
def get_all(module_path, heading, finder=None):
mods = []
if not finder:
finder = ClassFinder(i3pystatus.Module)
for name, module in get_modules(module_path):
classes = finder.search_module(module)
for cls in classes:
mods.append(Module(cls, neighbours=len(classes), module_name=name, module=module, heading=heading))
return sorted(mods, key=lambda module: module.name)
def generate_doc_for_module(module_path, heading="###", finder=None):
return "".join(map(str, get_all(module_path, heading, finder)))
with open("README.tpl.md", "r") as template:
tpl = template.read()
tpl = tpl.replace("!!module_doc!!", generate_doc_for_module(i3pystatus.__path__))
finder = ClassFinder(baseclass=i3pystatus.mail.Backend)
tpl = tpl.replace("!!i3pystatus.mail!!", generate_doc_for_module(i3pystatus.mail.__path__, "###", finder).replace("\n", "\n> "))
with open("README.md", "w") as output:
output.write(tpl + "\n")