Better auto-generated documentation and fixed docstring warnings
This commit is contained in:
parent
7c9e9d284d
commit
fdf6d8fb4e
12 changed files with 85 additions and 58 deletions
|
@ -1,5 +1,5 @@
|
|||
``platypush.message.event.chat.slack``
|
||||
======================================
|
||||
``chat.slack``
|
||||
==============
|
||||
|
||||
.. automodule:: platypush.message.event.chat.slack
|
||||
:members:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
``platypush.message.event.dbus``
|
||||
================================
|
||||
``dbus``
|
||||
========
|
||||
|
||||
.. automodule:: platypush.message.event.dbus
|
||||
:members:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
``platypush.message.event.gotify``
|
||||
==================================
|
||||
``gotify``
|
||||
==========
|
||||
|
||||
.. automodule:: platypush.message.event.gotify
|
||||
:members:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
``platypush.message.event.irc``
|
||||
===============================
|
||||
``irc``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.message.event.irc
|
||||
:members:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
``platypush.message.event.ngrok``
|
||||
=================================
|
||||
``ngrok``
|
||||
=========
|
||||
|
||||
.. automodule:: platypush.message.event.ngrok
|
||||
:members:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
``platypush.message.event.rss``
|
||||
===============================
|
||||
``rss``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.message.event.rss
|
||||
:members:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
``platypush.message.event.sun``
|
||||
===============================
|
||||
``sun``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.message.event.sun
|
||||
:members:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
``media.jellyfin``
|
||||
================================
|
||||
==================
|
||||
|
||||
.. automodule:: platypush.plugins.media.jellyfin
|
||||
:members:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import inspect
|
||||
import os
|
||||
|
||||
from platypush.backend import Backend
|
||||
|
@ -6,11 +7,17 @@ from platypush.plugins import Plugin
|
|||
from platypush.utils.manifest import get_manifests
|
||||
|
||||
|
||||
def _get_inspect_plugin():
|
||||
p = get_plugin('inspect')
|
||||
assert p, 'Could not load the `inspect` plugin'
|
||||
return p
|
||||
|
||||
|
||||
def get_all_plugins():
|
||||
manifests = {mf.component_name for mf in get_manifests(Plugin)}
|
||||
return {
|
||||
plugin_name: plugin_info
|
||||
for plugin_name, plugin_info in get_plugin('inspect').get_all_plugins().output.items()
|
||||
for plugin_name, plugin_info in _get_inspect_plugin().get_all_plugins().output.items()
|
||||
if plugin_name in manifests
|
||||
}
|
||||
|
||||
|
@ -19,17 +26,17 @@ def get_all_backends():
|
|||
manifests = {mf.component_name for mf in get_manifests(Backend)}
|
||||
return {
|
||||
backend_name: backend_info
|
||||
for backend_name, backend_info in get_plugin('inspect').get_all_backends().output.items()
|
||||
for backend_name, backend_info in _get_inspect_plugin().get_all_backends().output.items()
|
||||
if backend_name in manifests
|
||||
}
|
||||
|
||||
|
||||
def get_all_events():
|
||||
return get_plugin('inspect').get_all_events().output
|
||||
return _get_inspect_plugin().get_all_events().output
|
||||
|
||||
|
||||
def get_all_responses():
|
||||
return get_plugin('inspect').get_all_responses().output
|
||||
return _get_inspect_plugin().get_all_responses().output
|
||||
|
||||
|
||||
# noinspection DuplicatedCode
|
||||
|
@ -100,16 +107,17 @@ Backends
|
|||
|
||||
# noinspection DuplicatedCode
|
||||
def generate_events_doc():
|
||||
from platypush.message import event as event_module
|
||||
events_index = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'events.rst')
|
||||
events_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'platypush', 'events')
|
||||
all_events = sorted(event for event in get_all_events().keys())
|
||||
all_events = sorted(event for event in get_all_events().keys() if event)
|
||||
|
||||
for event in all_events:
|
||||
event_file = os.path.join(events_dir, event[len('platypush.message.event.'):] + '.rst')
|
||||
event_file = os.path.join(events_dir, event + '.rst')
|
||||
if not os.path.exists(event_file):
|
||||
header = '``{}``'.format(event)
|
||||
divider = '=' * len(header)
|
||||
body = '\n.. automodule:: {}\n :members:\n'.format(event)
|
||||
body = '\n.. automodule:: {}.{}\n :members:\n'.format(event_module.__name__, event)
|
||||
out = '\n'.join([header, divider, body])
|
||||
|
||||
with open(event_file, 'w') as f:
|
||||
|
@ -127,21 +135,22 @@ Events
|
|||
''')
|
||||
|
||||
for event in all_events:
|
||||
f.write(' platypush/events/' + event[len('platypush.message.event.'):] + '.rst\n')
|
||||
f.write(' platypush/events/' + event + '.rst\n')
|
||||
|
||||
|
||||
# noinspection DuplicatedCode
|
||||
def generate_responses_doc():
|
||||
from platypush.message import response as response_module
|
||||
responses_index = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'responses.rst')
|
||||
responses_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'platypush', 'responses')
|
||||
all_responses = sorted(response for response in get_all_responses().keys())
|
||||
all_responses = sorted(response for response in get_all_responses().keys() if response)
|
||||
|
||||
for response in all_responses:
|
||||
response_file = os.path.join(responses_dir, response[len('platypush.message.response.'):] + '.rst')
|
||||
response_file = os.path.join(responses_dir, response + '.rst')
|
||||
if not os.path.exists(response_file):
|
||||
header = '``{}``'.format(response)
|
||||
divider = '=' * len(header)
|
||||
body = '\n.. automodule:: {}\n :members:\n'.format(response)
|
||||
body = '\n.. automodule:: {}.{}\n :members:\n'.format(response_module.__name__, response)
|
||||
out = '\n'.join([header, divider, body])
|
||||
|
||||
with open(response_file, 'w') as f:
|
||||
|
@ -159,7 +168,7 @@ Responses
|
|||
''')
|
||||
|
||||
for response in all_responses:
|
||||
f.write(' platypush/responses/' + response[len('platypush.message.response.'):] + '.rst\n')
|
||||
f.write(' platypush/responses/' + response + '.rst\n')
|
||||
|
||||
|
||||
generate_plugins_doc()
|
||||
|
|
|
@ -71,7 +71,7 @@ class Message(object):
|
|||
logger.warning('Could not serialize object type {}: {}: {}'.format(
|
||||
type(obj), str(e), obj))
|
||||
|
||||
def __init__(self, timestamp=None, *args, **kwargs):
|
||||
def __init__(self, timestamp=None, *_, **__):
|
||||
self.timestamp = timestamp or time.time()
|
||||
|
||||
def __str__(self):
|
||||
|
@ -98,9 +98,9 @@ class Message(object):
|
|||
def parse(cls, msg):
|
||||
"""
|
||||
Parse a generic message into a key-value dictionary
|
||||
Params:
|
||||
msg -- Original message - can be a dictionary, a Message,
|
||||
or a string/bytearray, as long as it's valid UTF-8 JSON
|
||||
|
||||
:param msg: Original message. It can be a dictionary, a Message,
|
||||
or a string/bytearray, as long as it's valid UTF-8 JSON
|
||||
"""
|
||||
|
||||
if isinstance(msg, cls):
|
||||
|
@ -124,8 +124,8 @@ class Message(object):
|
|||
def build(cls, msg):
|
||||
"""
|
||||
Builds a Message object from a dictionary.
|
||||
Params:
|
||||
msg -- The message as a key-value dictionary, Message object or JSON string
|
||||
|
||||
:param msg: The message as a key-value dictionary, Message object or JSON string
|
||||
"""
|
||||
from platypush.utils import get_message_class_by_type
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import json
|
|||
import pkgutil
|
||||
import re
|
||||
import threading
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
import platypush.backend # lgtm [py/import-and-import-from]
|
||||
|
@ -19,8 +20,7 @@ from platypush.message.response import Response
|
|||
from platypush.utils import get_decorators
|
||||
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
class Model:
|
||||
class Model(ABC):
|
||||
def __str__(self):
|
||||
return json.dumps(dict(self), indent=2, sort_keys=True)
|
||||
|
||||
|
@ -37,6 +37,10 @@ class Model:
|
|||
|
||||
return docutils.core.publish_parts(doc, writer_name='html')['html_body']
|
||||
|
||||
@abstractmethod
|
||||
def __iter__(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ProcedureEncoder(json.JSONEncoder):
|
||||
def default(self, o):
|
||||
|
@ -49,7 +53,7 @@ class ProcedureEncoder(json.JSONEncoder):
|
|||
|
||||
|
||||
class BackendModel(Model):
|
||||
def __init__(self, backend, prefix='', html_doc: bool = False):
|
||||
def __init__(self, backend, prefix='', html_doc: Optional[bool] = False):
|
||||
self.name = backend.__module__[len(prefix):]
|
||||
self.html_doc = html_doc
|
||||
self.doc = self.to_html(backend.__doc__) if html_doc and backend.__doc__ else backend.__doc__
|
||||
|
@ -60,11 +64,11 @@ class BackendModel(Model):
|
|||
|
||||
|
||||
class PluginModel(Model):
|
||||
def __init__(self, plugin, prefix='', html_doc: bool = False):
|
||||
def __init__(self, plugin, prefix='', html_doc: Optional[bool] = False):
|
||||
self.name = plugin.__module__[len(prefix):]
|
||||
self.html_doc = html_doc
|
||||
self.doc = self.to_html(plugin.__doc__) if html_doc and plugin.__doc__ else plugin.__doc__
|
||||
self.actions = {action_name: ActionModel(getattr(plugin, action_name), html_doc=html_doc)
|
||||
self.actions = {action_name: ActionModel(getattr(plugin, action_name), html_doc=html_doc or False)
|
||||
for action_name in get_decorators(plugin, climb_class_hierarchy=True).get('action', [])}
|
||||
|
||||
def __iter__(self):
|
||||
|
@ -77,8 +81,8 @@ class PluginModel(Model):
|
|||
|
||||
|
||||
class EventModel(Model):
|
||||
def __init__(self, event, html_doc: bool = False):
|
||||
self.package = event.__module__
|
||||
def __init__(self, event, prefix='', html_doc: Optional[bool] = False):
|
||||
self.package = event.__module__[len(prefix):]
|
||||
self.name = event.__name__
|
||||
self.html_doc = html_doc
|
||||
self.doc = self.to_html(event.__doc__) if html_doc and event.__doc__ else event.__doc__
|
||||
|
@ -89,8 +93,8 @@ class EventModel(Model):
|
|||
|
||||
|
||||
class ResponseModel(Model):
|
||||
def __init__(self, response, html_doc: bool = False):
|
||||
self.package = response.__module__
|
||||
def __init__(self, response, prefix='', html_doc: Optional[bool] = False):
|
||||
self.package = response.__module__[len(prefix):]
|
||||
self.name = response.__name__
|
||||
self.html_doc = html_doc
|
||||
self.doc = self.to_html(response.__doc__) if html_doc and response.__doc__ else response.__doc__
|
||||
|
@ -187,7 +191,7 @@ class InspectPlugin(Plugin):
|
|||
|
||||
for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
|
||||
prefix=prefix,
|
||||
onerror=lambda x: None):
|
||||
onerror=lambda _: None):
|
||||
try:
|
||||
module = importlib.import_module(modname)
|
||||
except Exception as e:
|
||||
|
@ -207,7 +211,7 @@ class InspectPlugin(Plugin):
|
|||
|
||||
for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
|
||||
prefix=prefix,
|
||||
onerror=lambda x: None):
|
||||
onerror=lambda _: None):
|
||||
try:
|
||||
module = importlib.import_module(modname)
|
||||
except Exception as e:
|
||||
|
@ -226,7 +230,7 @@ class InspectPlugin(Plugin):
|
|||
|
||||
for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
|
||||
prefix=prefix,
|
||||
onerror=lambda x: None):
|
||||
onerror=lambda _: None):
|
||||
try:
|
||||
module = importlib.import_module(modname)
|
||||
except Exception as e:
|
||||
|
@ -238,7 +242,7 @@ class InspectPlugin(Plugin):
|
|||
continue
|
||||
|
||||
if inspect.isclass(obj) and issubclass(obj, Event) and obj != Event:
|
||||
event = EventModel(event=obj, html_doc=self._html_doc)
|
||||
event = EventModel(event=obj, html_doc=self._html_doc, prefix=prefix)
|
||||
if event.package not in self._events:
|
||||
self._events[event.package] = {event.name: event}
|
||||
else:
|
||||
|
@ -250,7 +254,7 @@ class InspectPlugin(Plugin):
|
|||
|
||||
for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
|
||||
prefix=prefix,
|
||||
onerror=lambda x: None):
|
||||
onerror=lambda _: None):
|
||||
try:
|
||||
module = importlib.import_module(modname)
|
||||
except Exception as e:
|
||||
|
@ -262,14 +266,14 @@ class InspectPlugin(Plugin):
|
|||
continue
|
||||
|
||||
if inspect.isclass(obj) and issubclass(obj, Response) and obj != Response:
|
||||
response = ResponseModel(response=obj, html_doc=self._html_doc)
|
||||
response = ResponseModel(response=obj, html_doc=self._html_doc, prefix=prefix)
|
||||
if response.package not in self._responses:
|
||||
self._responses[response.package] = {response.name: response}
|
||||
else:
|
||||
self._responses[response.package][response.name] = response
|
||||
|
||||
@action
|
||||
def get_all_plugins(self, html_doc: bool = None):
|
||||
def get_all_plugins(self, html_doc: Optional[bool] = None):
|
||||
"""
|
||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
||||
"""
|
||||
|
@ -284,7 +288,7 @@ class InspectPlugin(Plugin):
|
|||
})
|
||||
|
||||
@action
|
||||
def get_all_backends(self, html_doc: bool = None):
|
||||
def get_all_backends(self, html_doc: Optional[bool] = None):
|
||||
"""
|
||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
||||
"""
|
||||
|
@ -299,7 +303,7 @@ class InspectPlugin(Plugin):
|
|||
})
|
||||
|
||||
@action
|
||||
def get_all_events(self, html_doc: bool = None):
|
||||
def get_all_events(self, html_doc: Optional[bool] = None):
|
||||
"""
|
||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
||||
"""
|
||||
|
@ -311,13 +315,13 @@ class InspectPlugin(Plugin):
|
|||
return json.dumps({
|
||||
package: {
|
||||
name: dict(event)
|
||||
for name, event in self._events[package].items()
|
||||
for name, event in events.items()
|
||||
}
|
||||
for package, events in self._events.items()
|
||||
})
|
||||
|
||||
@action
|
||||
def get_all_responses(self, html_doc: bool = None):
|
||||
def get_all_responses(self, html_doc: Optional[bool] = None):
|
||||
"""
|
||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
||||
"""
|
||||
|
@ -329,9 +333,9 @@ class InspectPlugin(Plugin):
|
|||
return json.dumps({
|
||||
package: {
|
||||
name: dict(event)
|
||||
for name, event in self._responses[package].items()
|
||||
for name, event in responses.items()
|
||||
}
|
||||
for package, events in self._responses.items()
|
||||
for package, responses in self._responses.items()
|
||||
})
|
||||
|
||||
@action
|
||||
|
@ -342,7 +346,7 @@ class InspectPlugin(Plugin):
|
|||
return json.loads(json.dumps(Config.get_procedures(), cls=ProcedureEncoder))
|
||||
|
||||
@action
|
||||
def get_config(self, entry: Optional[str] = None) -> dict:
|
||||
def get_config(self, entry: Optional[str] = None) -> Optional[dict]:
|
||||
"""
|
||||
Return the configuration of the application or of a section.
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ class MediaJellyfinPlugin(Plugin):
|
|||
:param genres: Filter results by (a list of) genres.
|
||||
:param tags: Filter results by (a list of) tags.
|
||||
:param years: Filter results by (a list of) years.
|
||||
:return: .. schema:: jellyfin.JellyfinArtistSchema(many=True)
|
||||
:return: .. schema:: media.jellyfin.JellyfinArtistSchema(many=True)
|
||||
"""
|
||||
return self._query(
|
||||
'/Artists', schema_class=JellyfinArtistSchema,
|
||||
|
@ -196,7 +196,7 @@ class MediaJellyfinPlugin(Plugin):
|
|||
"""
|
||||
Get the list of collections associated to the user on the server (Movies, Series, Channels etc.)
|
||||
|
||||
:return: .. schema:: jellyfin.JellyfinCollectionSchema(many=True)
|
||||
:return: .. schema:: media.jellyfin.JellyfinCollectionSchema(many=True)
|
||||
"""
|
||||
return self._query(
|
||||
f'/Users/{self._user_id}/Items',
|
||||
|
@ -242,6 +242,20 @@ class MediaJellyfinPlugin(Plugin):
|
|||
:param genres: Filter results by (a list of) genres.
|
||||
:param tags: Filter results by (a list of) tags.
|
||||
:param years: Filter results by (a list of) years.
|
||||
:return: The list of matching results.
|
||||
|
||||
Schema for artists:
|
||||
.. schema:: media.jellyfin.JellyfinArtistSchema
|
||||
|
||||
Schema for collections:
|
||||
.. schema:: media.jellyfin.JellyfinCollectionSchema
|
||||
|
||||
Schema for movies:
|
||||
.. schema:: media.jellyfin.JellyfinMovieSchema
|
||||
|
||||
Schema for episodes:
|
||||
.. schema:: media.jellyfin.JellyfinEpisodeSchema
|
||||
|
||||
"""
|
||||
if collection:
|
||||
collections = self.get_collections().output # type: ignore
|
||||
|
|
Loading…
Reference in a new issue