forked from platypush/platypush
Improved rendering of actions/arguments documentation.
The frontend now calls `utils.rst_to_html` to render the docstrings as HTML instead of dumping them as raw text. Also, actions and arguments are now cached to improve performance.
This commit is contained in:
parent
5f2d6dfeb5
commit
8447f9a854
5 changed files with 106 additions and 160 deletions
|
@ -30,8 +30,10 @@
|
||||||
Action documentation
|
Action documentation
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="doc html" v-html="selectedDoc" v-if="htmlDoc" />
|
<div class="doc html">
|
||||||
<div class="doc raw" v-text="selectedDoc" v-else />
|
<Loading v-if="docLoading" />
|
||||||
|
<span v-html="selectedDoc" v-else />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="options" v-if="action.name in actions && (Object.keys(action.args).length ||
|
<div class="options" v-if="action.name in actions && (Object.keys(action.args).length ||
|
||||||
|
@ -51,8 +53,10 @@
|
||||||
Attribute: <div class="attr-name" v-text="selectedAttr" />
|
Attribute: <div class="attr-name" v-text="selectedAttr" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="doc html" v-html="selectedAttrDoc" v-if="htmlDoc" />
|
<div class="doc html">
|
||||||
<div class="doc raw" v-text="selectedAttrDoc" v-else />
|
<Loading v-if="docLoading" />
|
||||||
|
<span v-html="selectedAttrDoc" v-else />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -87,8 +91,11 @@
|
||||||
Attribute: <div class="attr-name" v-text="selectedAttr" />
|
Attribute: <div class="attr-name" v-text="selectedAttr" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="doc html" v-html="selectedAttrDoc" v-if="htmlDoc" />
|
<div class="doc html">
|
||||||
<div class="doc raw" v-text="selectedAttrDoc" v-else />
|
<Loading v-if="docLoading" />
|
||||||
|
<span v-html="selectedAttrDoc" v-else />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="output-container">
|
<div class="output-container">
|
||||||
|
@ -97,7 +104,6 @@
|
||||||
<div class="error" v-html="error" v-else-if="error != null" />
|
<div class="error" v-html="error" v-else-if="error != null" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="request raw-request" :class="structuredInput ? 'hidden' : ''">
|
<div class="request raw-request" :class="structuredInput ? 'hidden' : ''">
|
||||||
<div class="first-row">
|
<div class="first-row">
|
||||||
|
@ -163,6 +169,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
running: false,
|
running: false,
|
||||||
|
docLoading: false,
|
||||||
structuredInput: true,
|
structuredInput: true,
|
||||||
actionChanged: false,
|
actionChanged: false,
|
||||||
selectedDoc: undefined,
|
selectedDoc: undefined,
|
||||||
|
@ -175,11 +182,11 @@ export default {
|
||||||
|
|
||||||
response: undefined,
|
response: undefined,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
htmlDoc: false,
|
|
||||||
rawRequest: undefined,
|
rawRequest: undefined,
|
||||||
actions: {},
|
actions: {},
|
||||||
plugins: {},
|
plugins: {},
|
||||||
procedures: {},
|
procedures: {},
|
||||||
|
actionDocsCache: {},
|
||||||
action: {
|
action: {
|
||||||
name: undefined,
|
name: undefined,
|
||||||
args: {},
|
args: {},
|
||||||
|
@ -195,15 +202,12 @@ export default {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.procedures = await this.request('inspect.get_procedures')
|
this.procedures = await this.request('inspect.get_procedures')
|
||||||
this.plugins = await this.request('inspect.get_all_plugins', {html_doc: false})
|
this.plugins = await this.request('inspect.get_all_plugins')
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const plugin of Object.values(this.plugins)) {
|
for (const plugin of Object.values(this.plugins)) {
|
||||||
if (plugin.html_doc)
|
|
||||||
this.htmlDoc = true
|
|
||||||
|
|
||||||
for (const action of Object.values(plugin.actions)) {
|
for (const action of Object.values(plugin.actions)) {
|
||||||
action.name = plugin.name + '.' + action.name
|
action.name = plugin.name + '.' + action.name
|
||||||
action.supportsExtraArgs = !!action.has_kwargs
|
action.supportsExtraArgs = !!action.has_kwargs
|
||||||
|
@ -213,20 +217,20 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
const self = this
|
const self = this
|
||||||
autocomplete(this.$refs.actionName, Object.keys(this.actions).sort(), (evt, value) => {
|
autocomplete(this.$refs.actionName, Object.keys(this.actions).sort(), (_, value) => {
|
||||||
this.action.name = value
|
this.action.name = value
|
||||||
self.updateAction()
|
self.updateAction()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
updateAction() {
|
async updateAction() {
|
||||||
if (!(this.action.name in this.actions))
|
if (!(this.action.name in this.actions))
|
||||||
this.selectedDoc = undefined
|
this.selectedDoc = undefined
|
||||||
|
|
||||||
if (!this.actionChanged || !(this.action.name in this.actions))
|
if (!this.actionChanged || !(this.action.name in this.actions))
|
||||||
return
|
return
|
||||||
|
|
||||||
this.loading = true
|
this.docLoading = true
|
||||||
try {
|
try {
|
||||||
this.action = {
|
this.action = {
|
||||||
...this.actions[this.action.name],
|
...this.actions[this.action.name],
|
||||||
|
@ -241,32 +245,27 @@ export default {
|
||||||
extraArgs: [],
|
extraArgs: [],
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.docLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectedDoc = this.parseDoc(this.action.doc)
|
this.selectedDoc =
|
||||||
|
this.actionDocsCache[this.action.name]?.html ||
|
||||||
|
await this.parseDoc(this.action.doc)
|
||||||
|
|
||||||
|
if (!this.actionDocsCache[this.action.name])
|
||||||
|
this.actionDocsCache[this.action.name] = {}
|
||||||
|
this.actionDocsCache[this.action.name].html = this.selectedDoc
|
||||||
|
|
||||||
this.actionChanged = false
|
this.actionChanged = false
|
||||||
this.response = undefined
|
this.response = undefined
|
||||||
this.error = undefined
|
this.error = undefined
|
||||||
},
|
},
|
||||||
|
|
||||||
parseDoc(docString) {
|
async parseDoc(docString) {
|
||||||
if (!docString?.length || this.htmlDoc)
|
if (!docString?.length)
|
||||||
return docString
|
return docString
|
||||||
|
|
||||||
let lineNo = 0
|
return await this.request('utils.rst_to_html', {text: docString})
|
||||||
let trailingSpaces = 0
|
|
||||||
|
|
||||||
return docString.split('\n').reduce((doc, line) => {
|
|
||||||
if (++lineNo === 2)
|
|
||||||
trailingSpaces = line.match(/^(\s*)/)[1].length
|
|
||||||
|
|
||||||
if (line.trim().startsWith('.. code-block'))
|
|
||||||
return doc
|
|
||||||
|
|
||||||
doc += line.slice(trailingSpaces).replaceAll('``', '') + '\n'
|
|
||||||
return doc
|
|
||||||
}, '')
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateProcedure(name, event) {
|
updateProcedure(name, event) {
|
||||||
|
@ -308,11 +307,16 @@ export default {
|
||||||
this.action.extraArgs.pop(i)
|
this.action.extraArgs.pop(i)
|
||||||
},
|
},
|
||||||
|
|
||||||
selectAttrDoc(name) {
|
async selectAttrDoc(name) {
|
||||||
this.response = undefined
|
|
||||||
this.error = undefined
|
|
||||||
this.selectedAttr = name
|
this.selectedAttr = name
|
||||||
this.selectedAttrDoc = this.parseDoc(this.action.args[name].doc)
|
this.selectedAttrDoc =
|
||||||
|
this.actionDocsCache[this.action.name]?.[name]?.html ||
|
||||||
|
await this.parseDoc(this.action.args[name].doc)
|
||||||
|
|
||||||
|
if (!this.actionDocsCache[this.action.name])
|
||||||
|
this.actionDocsCache[this.action.name] = {}
|
||||||
|
|
||||||
|
this.actionDocsCache[this.action.name][name] = {html: this.selectedAttrDoc}
|
||||||
},
|
},
|
||||||
|
|
||||||
resetAttrDoc() {
|
resetAttrDoc() {
|
||||||
|
@ -450,6 +454,7 @@ $params-tablet-width: 20em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-form {
|
.action-form {
|
||||||
|
background: $default-bg-2;
|
||||||
padding: 1em .5em;
|
padding: 1em .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,12 +549,26 @@ $params-tablet-width: 20em;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: .5em;
|
margin-bottom: .5em;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-left: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
justify-content: right;
|
||||||
|
}
|
||||||
|
|
||||||
.action-extra-param-del {
|
.action-extra-param-del {
|
||||||
border: 0;
|
border: 0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 0 .5em;
|
padding: 0 .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=text] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -569,11 +588,6 @@ $params-tablet-width: 20em;
|
||||||
.doc-container,
|
.doc-container,
|
||||||
.output-container {
|
.output-container {
|
||||||
margin-top: .5em;
|
margin-top: .5em;
|
||||||
.doc {
|
|
||||||
&.raw {
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.output-container {
|
.output-container {
|
||||||
|
@ -590,7 +604,6 @@ $params-tablet-width: 20em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.doc {
|
.doc {
|
||||||
white-space: pre-line;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
@ -613,11 +626,6 @@ $params-tablet-width: 20em;
|
||||||
.attr-doc-container {
|
.attr-doc-container {
|
||||||
.doc {
|
.doc {
|
||||||
padding: 1em !important;
|
padding: 1em !important;
|
||||||
|
|
||||||
&.raw {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: .8em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,11 +755,14 @@ $params-tablet-width: 20em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.run-btn {
|
.run-btn {
|
||||||
border-radius: 2em;
|
background: none;
|
||||||
padding: .5em .75em;
|
border-radius: .25em;
|
||||||
|
padding: .5em 1.5em;
|
||||||
|
box-shadow: $primary-btn-shadow;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: .8;
|
background: $hover-bg;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ $response-bg: #edfff2;
|
||||||
$response-border: 1px dashed #98ff98;
|
$response-border: 1px dashed #98ff98;
|
||||||
$error-bg: #ffbcbc;
|
$error-bg: #ffbcbc;
|
||||||
$error-border: 1px dashed #ff5353;
|
$error-border: 1px dashed #ff5353;
|
||||||
$doc-bg: #e8feff;
|
$doc-bg: $background-color;
|
||||||
$doc-border: 1px dashed #84f9ff;
|
$doc-border: 1px dashed $border-color-2;
|
||||||
$procedure-submit-btn-bg: #ebffeb;
|
$procedure-submit-btn-bg: #ebffeb;
|
||||||
$section-title-bg: rgba(0, 0, 0, .04);
|
$section-title-bg: rgba(0, 0, 0, .04);
|
||||||
|
|
|
@ -56,6 +56,7 @@ $border-shadow-right: 2.5px 0 4px 0 $default-shadow-color;
|
||||||
$border-shadow-bottom-right: 2.5px 2.5px 3px 0 $default-shadow-color;
|
$border-shadow-bottom-right: 2.5px 2.5px 3px 0 $default-shadow-color;
|
||||||
$header-shadow: 0px 1px 3px 1px #bbb !default;
|
$header-shadow: 0px 1px 3px 1px #bbb !default;
|
||||||
$group-shadow: 3px -2px 6px 1px #98b0a0;
|
$group-shadow: 3px -2px 6px 1px #98b0a0;
|
||||||
|
$primary-btn-shadow: 1px 1px 0.5px 0.75px #32b64640 !default;
|
||||||
|
|
||||||
//// Modals
|
//// Modals
|
||||||
$modal-header-bg: #e0e0e0 !default;
|
$modal-header-bg: #e0e0e0 !default;
|
||||||
|
@ -81,6 +82,7 @@ $default-hover-fg: #35b870 !default;
|
||||||
$default-hover-fg-2: #38cf80 !default;
|
$default-hover-fg-2: #38cf80 !default;
|
||||||
$hover-fg: $default-hover-fg !default;
|
$hover-fg: $default-hover-fg !default;
|
||||||
$hover-bg: linear-gradient(90deg, rgba(190,246,218,1) 0%, rgba(229,251,240,1) 100%) !default;
|
$hover-bg: linear-gradient(90deg, rgba(190,246,218,1) 0%, rgba(229,251,240,1) 100%) !default;
|
||||||
|
$hover-bg-2: rgb(190,246,218) !default;
|
||||||
$active-bg: #8fefb7 !default;
|
$active-bg: #8fefb7 !default;
|
||||||
|
|
||||||
/// Disabled
|
/// Disabled
|
||||||
|
|
|
@ -36,7 +36,6 @@ class InspectPlugin(Plugin):
|
||||||
self._backends_lock = threading.RLock()
|
self._backends_lock = threading.RLock()
|
||||||
self._events_lock = threading.RLock()
|
self._events_lock = threading.RLock()
|
||||||
self._responses_lock = threading.RLock()
|
self._responses_lock = threading.RLock()
|
||||||
self._html_doc = False
|
|
||||||
|
|
||||||
def _get_modules(self, parent_class: type):
|
def _get_modules(self, parent_class: type):
|
||||||
for mf_file in scan_manifests(parent_class):
|
for mf_file in scan_manifests(parent_class):
|
||||||
|
@ -57,9 +56,7 @@ class InspectPlugin(Plugin):
|
||||||
for module in self._get_modules(Plugin):
|
for module in self._get_modules(Plugin):
|
||||||
plugin_name = '.'.join(module.__name__.split('.')[2:])
|
plugin_name = '.'.join(module.__name__.split('.')[2:])
|
||||||
plugin_class = get_plugin_class_by_name(plugin_name)
|
plugin_class = get_plugin_class_by_name(plugin_name)
|
||||||
model = PluginModel(
|
model = PluginModel(plugin=plugin_class, prefix=prefix)
|
||||||
plugin=plugin_class, prefix=prefix, html_doc=self._html_doc
|
|
||||||
)
|
|
||||||
|
|
||||||
if model.name:
|
if model.name:
|
||||||
self._plugins[model.name] = model
|
self._plugins[model.name] = model
|
||||||
|
@ -70,9 +67,7 @@ class InspectPlugin(Plugin):
|
||||||
for module in self._get_modules(Backend):
|
for module in self._get_modules(Backend):
|
||||||
for _, obj in inspect.getmembers(module):
|
for _, obj in inspect.getmembers(module):
|
||||||
if inspect.isclass(obj) and issubclass(obj, Backend):
|
if inspect.isclass(obj) and issubclass(obj, Backend):
|
||||||
model = BackendModel(
|
model = BackendModel(backend=obj, prefix=prefix)
|
||||||
backend=obj, prefix=prefix, html_doc=self._html_doc
|
|
||||||
)
|
|
||||||
if model.name:
|
if model.name:
|
||||||
self._backends[model.name] = model
|
self._backends[model.name] = model
|
||||||
|
|
||||||
|
@ -85,9 +80,7 @@ class InspectPlugin(Plugin):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if inspect.isclass(obj) and issubclass(obj, Event) and obj != Event:
|
if inspect.isclass(obj) and issubclass(obj, Event) and obj != Event:
|
||||||
event = EventModel(
|
event = EventModel(event=obj, prefix=prefix)
|
||||||
event=obj, html_doc=self._html_doc, prefix=prefix
|
|
||||||
)
|
|
||||||
if event.package not in self._events:
|
if event.package not in self._events:
|
||||||
self._events[event.package] = {event.name: event}
|
self._events[event.package] = {event.name: event}
|
||||||
else:
|
else:
|
||||||
|
@ -106,24 +99,19 @@ class InspectPlugin(Plugin):
|
||||||
and issubclass(obj, Response)
|
and issubclass(obj, Response)
|
||||||
and obj != Response
|
and obj != Response
|
||||||
):
|
):
|
||||||
response = ResponseModel(
|
response = ResponseModel(response=obj, prefix=prefix)
|
||||||
response=obj, html_doc=self._html_doc, prefix=prefix
|
|
||||||
)
|
|
||||||
if response.package not in self._responses:
|
if response.package not in self._responses:
|
||||||
self._responses[response.package] = {response.name: response}
|
self._responses[response.package] = {response.name: response}
|
||||||
else:
|
else:
|
||||||
self._responses[response.package][response.name] = response
|
self._responses[response.package][response.name] = response
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_all_plugins(self, html_doc: Optional[bool] = None):
|
def get_all_plugins(self):
|
||||||
"""
|
"""
|
||||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
Get information about all the available plugins.
|
||||||
"""
|
"""
|
||||||
with self._plugins_lock:
|
with self._plugins_lock:
|
||||||
if not self._plugins or (
|
if not self._plugins:
|
||||||
html_doc is not None and html_doc != self._html_doc
|
|
||||||
):
|
|
||||||
self._html_doc = html_doc
|
|
||||||
self._init_plugins()
|
self._init_plugins()
|
||||||
|
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
|
@ -131,15 +119,12 @@ class InspectPlugin(Plugin):
|
||||||
)
|
)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_all_backends(self, html_doc: Optional[bool] = None):
|
def get_all_backends(self):
|
||||||
"""
|
"""
|
||||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
Get information about all the available backends.
|
||||||
"""
|
"""
|
||||||
with self._backends_lock:
|
with self._backends_lock:
|
||||||
if not self._backends or (
|
if not self._backends:
|
||||||
html_doc is not None and html_doc != self._html_doc
|
|
||||||
):
|
|
||||||
self._html_doc = html_doc
|
|
||||||
self._init_backends()
|
self._init_backends()
|
||||||
|
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
|
@ -147,15 +132,12 @@ class InspectPlugin(Plugin):
|
||||||
)
|
)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_all_events(self, html_doc: Optional[bool] = None):
|
def get_all_events(self):
|
||||||
"""
|
"""
|
||||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
Get information about all the available events.
|
||||||
"""
|
"""
|
||||||
with self._events_lock:
|
with self._events_lock:
|
||||||
if not self._events or (
|
if not self._events:
|
||||||
html_doc is not None and html_doc != self._html_doc
|
|
||||||
):
|
|
||||||
self._html_doc = html_doc
|
|
||||||
self._init_events()
|
self._init_events()
|
||||||
|
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
|
@ -166,15 +148,12 @@ class InspectPlugin(Plugin):
|
||||||
)
|
)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_all_responses(self, html_doc: Optional[bool] = None):
|
def get_all_responses(self):
|
||||||
"""
|
"""
|
||||||
:param html_doc: If True then the docstring will be parsed into HTML (default: False)
|
Get information about all the available responses.
|
||||||
"""
|
"""
|
||||||
with self._responses_lock:
|
with self._responses_lock:
|
||||||
if not self._responses or (
|
if not self._responses:
|
||||||
html_doc is not None and html_doc != self._html_doc
|
|
||||||
):
|
|
||||||
self._html_doc = html_doc
|
|
||||||
self._init_responses()
|
self._init_responses()
|
||||||
|
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
|
|
|
@ -2,7 +2,6 @@ from abc import ABC, abstractmethod
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from platypush.utils import get_decorators
|
from platypush.utils import get_decorators
|
||||||
|
|
||||||
|
@ -14,16 +13,6 @@ class Model(ABC):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return json.dumps(dict(self))
|
return json.dumps(dict(self))
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_html(doc):
|
|
||||||
try:
|
|
||||||
import docutils.core # type: ignore
|
|
||||||
except ImportError:
|
|
||||||
# docutils not found
|
|
||||||
return doc
|
|
||||||
|
|
||||||
return docutils.core.publish_parts(doc, writer_name='html')['html_body']
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -40,42 +29,29 @@ class ProcedureEncoder(json.JSONEncoder):
|
||||||
|
|
||||||
|
|
||||||
class BackendModel(Model):
|
class BackendModel(Model):
|
||||||
def __init__(self, backend, prefix='', html_doc: Optional[bool] = False):
|
def __init__(self, backend, prefix=''):
|
||||||
self.name = backend.__module__[len(prefix) :]
|
self.name = backend.__module__[len(prefix) :]
|
||||||
self.html_doc = html_doc
|
self.doc = backend.__doc__
|
||||||
self.doc = (
|
|
||||||
self.to_html(backend.__doc__)
|
|
||||||
if html_doc and backend.__doc__
|
|
||||||
else backend.__doc__
|
|
||||||
)
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for attr in ['name', 'doc', 'html_doc']:
|
for attr in ['name', 'doc']:
|
||||||
yield attr, getattr(self, attr)
|
yield attr, getattr(self, attr)
|
||||||
|
|
||||||
|
|
||||||
class PluginModel(Model):
|
class PluginModel(Model):
|
||||||
def __init__(self, plugin, prefix='', html_doc: Optional[bool] = False):
|
def __init__(self, plugin, prefix=''):
|
||||||
self.name = plugin.__module__[len(prefix) :]
|
self.name = re.sub(r'\._plugin$', '', plugin.__module__[len(prefix) :])
|
||||||
self.html_doc = html_doc
|
self.doc = plugin.__doc__
|
||||||
self.doc = (
|
|
||||||
self.to_html(plugin.__doc__)
|
|
||||||
if html_doc and plugin.__doc__
|
|
||||||
else plugin.__doc__
|
|
||||||
)
|
|
||||||
self.actions = {
|
self.actions = {
|
||||||
action_name: ActionModel(
|
action_name: ActionModel(getattr(plugin, action_name))
|
||||||
getattr(plugin, action_name), html_doc=html_doc or False
|
|
||||||
)
|
|
||||||
for action_name in get_decorators(plugin, climb_class_hierarchy=True).get(
|
for action_name in get_decorators(plugin, climb_class_hierarchy=True).get(
|
||||||
'action', []
|
'action', []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for attr in ['name', 'actions', 'doc', 'html_doc']:
|
for attr in ['name', 'actions', 'doc']:
|
||||||
if attr == 'actions':
|
if attr == 'actions':
|
||||||
# noinspection PyShadowingNames
|
|
||||||
yield attr, {
|
yield attr, {
|
||||||
name: dict(action) for name, action in self.actions.items()
|
name: dict(action) for name, action in self.actions.items()
|
||||||
},
|
},
|
||||||
|
@ -84,40 +60,31 @@ class PluginModel(Model):
|
||||||
|
|
||||||
|
|
||||||
class EventModel(Model):
|
class EventModel(Model):
|
||||||
def __init__(self, event, prefix='', html_doc: Optional[bool] = False):
|
def __init__(self, event, prefix=''):
|
||||||
self.package = event.__module__[len(prefix) :]
|
self.package = event.__module__[len(prefix) :]
|
||||||
self.name = event.__name__
|
self.name = event.__name__
|
||||||
self.html_doc = html_doc
|
self.doc = event.__doc__
|
||||||
self.doc = (
|
|
||||||
self.to_html(event.__doc__) if html_doc and event.__doc__ else event.__doc__
|
|
||||||
)
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for attr in ['name', 'doc', 'html_doc']:
|
for attr in ['name', 'doc']:
|
||||||
yield attr, getattr(self, attr)
|
yield attr, getattr(self, attr)
|
||||||
|
|
||||||
|
|
||||||
class ResponseModel(Model):
|
class ResponseModel(Model):
|
||||||
def __init__(self, response, prefix='', html_doc: Optional[bool] = False):
|
def __init__(self, response, prefix=''):
|
||||||
self.package = response.__module__[len(prefix) :]
|
self.package = response.__module__[len(prefix) :]
|
||||||
self.name = response.__name__
|
self.name = response.__name__
|
||||||
self.html_doc = html_doc
|
self.doc = response.__doc__
|
||||||
self.doc = (
|
|
||||||
self.to_html(response.__doc__)
|
|
||||||
if html_doc and response.__doc__
|
|
||||||
else response.__doc__
|
|
||||||
)
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for attr in ['name', 'doc', 'html_doc']:
|
for attr in ['name', 'doc']:
|
||||||
yield attr, getattr(self, attr)
|
yield attr, getattr(self, attr)
|
||||||
|
|
||||||
|
|
||||||
class ActionModel(Model):
|
class ActionModel(Model):
|
||||||
# noinspection PyShadowingNames
|
def __init__(self, action):
|
||||||
def __init__(self, action, html_doc: bool = False):
|
|
||||||
self.name = action.__name__
|
self.name = action.__name__
|
||||||
self.doc, argsdoc = self._parse_docstring(action.__doc__, html_doc=html_doc)
|
self.doc, argsdoc = self._parse_docstring(action.__doc__)
|
||||||
self.args = {}
|
self.args = {}
|
||||||
self.has_kwargs = False
|
self.has_kwargs = False
|
||||||
|
|
||||||
|
@ -134,7 +101,7 @@ class ActionModel(Model):
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _parse_docstring(cls, docstring: str, html_doc: bool = False):
|
def _parse_docstring(cls, docstring: str):
|
||||||
new_docstring = ''
|
new_docstring = ''
|
||||||
params = {}
|
params = {}
|
||||||
cur_param = None
|
cur_param = None
|
||||||
|
@ -147,11 +114,7 @@ class ActionModel(Model):
|
||||||
m = re.match(r'^\s*:param ([^:]+):\s*(.*)', line)
|
m = re.match(r'^\s*:param ([^:]+):\s*(.*)', line)
|
||||||
if m:
|
if m:
|
||||||
if cur_param:
|
if cur_param:
|
||||||
params[cur_param] = (
|
params[cur_param] = cur_param_docstring
|
||||||
cls.to_html(cur_param_docstring)
|
|
||||||
if html_doc
|
|
||||||
else cur_param_docstring
|
|
||||||
)
|
|
||||||
|
|
||||||
cur_param = m.group(1)
|
cur_param = m.group(1)
|
||||||
cur_param_docstring = m.group(2)
|
cur_param_docstring = m.group(2)
|
||||||
|
@ -160,11 +123,7 @@ class ActionModel(Model):
|
||||||
else:
|
else:
|
||||||
if cur_param:
|
if cur_param:
|
||||||
if not line.strip():
|
if not line.strip():
|
||||||
params[cur_param] = (
|
params[cur_param] = cur_param_docstring
|
||||||
cls.to_html(cur_param_docstring)
|
|
||||||
if html_doc
|
|
||||||
else cur_param_docstring
|
|
||||||
)
|
|
||||||
cur_param = None
|
cur_param = None
|
||||||
cur_param_docstring = ''
|
cur_param_docstring = ''
|
||||||
else:
|
else:
|
||||||
|
@ -173,14 +132,9 @@ class ActionModel(Model):
|
||||||
new_docstring += line.rstrip() + '\n'
|
new_docstring += line.rstrip() + '\n'
|
||||||
|
|
||||||
if cur_param:
|
if cur_param:
|
||||||
params[cur_param] = (
|
params[cur_param] = cur_param_docstring
|
||||||
cls.to_html(cur_param_docstring) if html_doc else cur_param_docstring
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return new_docstring.strip(), params
|
||||||
new_docstring.strip() if not html_doc else cls.to_html(new_docstring),
|
|
||||||
params,
|
|
||||||
)
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for attr in ['name', 'args', 'doc', 'has_kwargs']:
|
for attr in ['name', 'args', 'doc', 'has_kwargs']:
|
||||||
|
|
Loading…
Reference in a new issue