platypush/generate_missing_docs.py

175 lines
4.3 KiB
Python
Raw Permalink Normal View History

import importlib
import inspect
2019-12-30 10:16:55 +01:00
import os
import sys
2023-04-03 00:44:29 +02:00
from typing import Iterable, Optional
2019-12-30 10:16:55 +01:00
import pkgutil
from platypush.backend import Backend
from platypush.message.event import Event
from platypush.message.response import Response
from platypush.plugins import Plugin
from platypush.utils.manifest import Manifests
from platypush.utils.mock import auto_mocks
2019-12-30 10:16:55 +01:00
def get_all_plugins():
return sorted([mf.component_name for mf in Manifests.by_base_class(Plugin)])
2019-12-30 10:16:55 +01:00
def get_all_backends():
return sorted([mf.component_name for mf in Manifests.by_base_class(Backend)])
2019-12-30 10:16:55 +01:00
2019-12-30 18:50:01 +01:00
def get_all_events():
return _get_modules(Event)
2019-12-30 18:50:01 +01:00
def get_all_responses():
return _get_modules(Response)
def _get_modules(base_type: type):
ret = set()
base_dir = os.path.dirname(inspect.getfile(base_type))
package = base_type.__module__
for _, mod_name, _ in pkgutil.walk_packages([base_dir], prefix=package + '.'):
try:
module = importlib.import_module(mod_name)
except Exception:
print('Could not import module', mod_name, file=sys.stderr)
continue
for _, obj_type in inspect.getmembers(module):
if (
inspect.isclass(obj_type)
and issubclass(obj_type, base_type)
# Exclude the base_type itself
and obj_type != base_type
):
ret.add(obj_type.__module__.replace(package + '.', '', 1))
return list(ret)
2023-04-03 00:44:29 +02:00
def _generate_components_doc(
index_name: str,
package_name: str,
components: Iterable[str],
doc_dir: Optional[str] = None,
):
if not doc_dir:
doc_dir = index_name
index_file = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'docs',
'source',
2023-04-03 00:44:29 +02:00
f'{index_name}.rst',
)
2023-04-03 00:44:29 +02:00
docs_dir = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'docs',
'source',
'platypush',
2023-04-03 00:44:29 +02:00
doc_dir,
)
2019-12-30 10:16:55 +01:00
2023-04-03 00:44:29 +02:00
for comp in components:
comp_file = os.path.join(docs_dir, comp + '.rst')
if not os.path.exists(comp_file):
comp = f'platypush.{package_name}.{comp}'
header = '``' + '.'.join(comp.split('.')[2:]) + '``'
2019-12-30 10:16:55 +01:00
divider = '=' * len(header)
2023-04-03 00:44:29 +02:00
body = f'\n.. automodule:: {comp}\n :members:\n'
2019-12-30 10:16:55 +01:00
out = '\n'.join([header, divider, body])
2023-04-03 00:44:29 +02:00
with open(comp_file, 'w') as f:
2019-12-30 10:16:55 +01:00
f.write(out)
2023-04-03 00:44:29 +02:00
with open(index_file, 'w') as f:
f.write(
2023-04-03 00:44:29 +02:00
f'''
{index_name.title()}
{''.join(['='] * len(index_name))}
2019-12-30 10:16:55 +01:00
.. toctree::
:maxdepth: 1
2023-04-03 00:44:29 +02:00
:caption: {index_name.title()}:
2019-12-30 10:16:55 +01:00
'''
)
2019-12-30 10:16:55 +01:00
2023-04-03 00:44:29 +02:00
for comp in components:
f.write(f' platypush/{doc_dir}/{comp}.rst\n')
2019-12-30 18:50:01 +01:00
2023-04-03 00:44:29 +02:00
_cleanup_removed_components_docs(docs_dir, components)
2019-12-30 18:50:01 +01:00
2023-04-03 00:44:29 +02:00
def _cleanup_removed_components_docs(docs_dir: str, components: Iterable[str]):
new_components = set(components)
existing_files = {
os.path.join(root, file)
for root, _, files in os.walk(docs_dir)
for file in files
if file.endswith('.rst')
}
2019-12-30 18:50:01 +01:00
2023-04-03 00:44:29 +02:00
files_to_remove = {
file
for file in existing_files
if os.path.basename(file).removesuffix('.rst') not in new_components
}
2019-12-30 18:50:01 +01:00
2023-04-03 00:44:29 +02:00
for file in files_to_remove:
print(f'Removing unlinked component {file}')
os.unlink(file)
2019-12-30 18:50:01 +01:00
2023-04-03 00:44:29 +02:00
def generate_plugins_doc():
_generate_components_doc(
index_name='plugins', package_name='plugins', components=get_all_plugins()
)
2019-12-30 18:50:01 +01:00
2023-04-03 00:44:29 +02:00
def generate_backends_doc():
_generate_components_doc(
index_name='backends',
package_name='backend',
components=get_all_backends(),
doc_dir='backend',
)
2023-04-03 00:44:29 +02:00
def generate_events_doc():
_generate_components_doc(
index_name='events',
package_name='message.event',
components=sorted(event for event in get_all_events() if event),
2023-04-03 00:44:29 +02:00
)
2023-04-03 00:44:29 +02:00
def generate_responses_doc():
_generate_components_doc(
index_name='responses',
package_name='message.response',
components=sorted(response for response in get_all_responses() if response),
2023-04-03 00:44:29 +02:00
)
2023-04-03 00:44:29 +02:00
def main():
with auto_mocks():
generate_plugins_doc()
generate_backends_doc()
generate_events_doc()
generate_responses_doc()
2023-04-03 00:44:29 +02:00
if __name__ == '__main__':
main()
2019-12-30 10:16:55 +01:00
# vim:sw=4:ts=4:et: