129 lines
3.6 KiB
Python
Executable File
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")
|