Loading plugins

This commit is contained in:
Jon Herron 2022-09-09 13:39:56 -04:00
parent 943b97e412
commit 5402b882d2
3 changed files with 172 additions and 2 deletions

79
app.py Normal file
View File

@ -0,0 +1,79 @@
import json
from flask import Flask, Response
app = Flask(__name__)
@app.before_first_request
def load_plugins():
print('load the plugins once here?')
@app.route('/v1/commands')
def list_commands():
def describe_command(plugin_name, command_name, command):
parameters = []
plugin_display_name = PluginService.plugin_display_name(plugin_name)
return { 'id': f'{plugin_display_name}/{command_name}', 'parameters': parameters }
commands_by_plugin = PluginService.available_commands_by_plugin()
descriptions = []
for plugin_name, commands in commands_by_plugin.items():
for command_name, command in commands:
description = describe_command(plugin_name, command_name, command)
descriptions.append(description)
return Response(json.dumps(descriptions), status=200, mimetype='application/json')
# TODO move out to own file
import importlib
import inspect
import pkgutil
import types
class PluginService:
PLUGIN_PREFIX = 'cmd_proxy_'
@staticmethod
def plugin_display_name(plugin_name):
return plugin_name.removeprefix(PluginService.PLUGIN_PREFIX)
@staticmethod
def available_plugins():
return {
name: importlib.import_module(name)
for finder, name, ispkg
in pkgutil.iter_modules()
if name.startswith(PluginService.PLUGIN_PREFIX)
}
@staticmethod
def available_commands_by_plugin():
return {
name: list(PluginService.commands_for_plugin(name, plugin))
for name, plugin
in PluginService.available_plugins().items()
}
@staticmethod
def modules_for_plugin(plugin):
for finder, name, ispkg in pkgutil.iter_modules(plugin.__path__):
if ispkg and name.startswith(PluginService.PLUGIN_PREFIX):
sub_pkg = finder.find_module(name).load_module(name)
yield from PluginService.modules_for_plugin(sub_pkg)
else:
spec = finder.find_spec(name)
if spec is not None and spec.loader is not None:
module = types.ModuleType(spec.name)
spec.loader.exec_module(module)
yield name, module
@staticmethod
def commands_for_plugin(plugin_name, plugin):
for module_name, module in PluginService.modules_for_plugin(plugin):
for member_name, member in inspect.getmembers(module, inspect.isfunction):
if member.__module__ == module_name:
yield member_name, member
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

91
poetry.lock generated
View File

@ -1,3 +1,11 @@
[[package]]
name = "certifi"
version = "2022.6.15.1"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "click"
version = "8.1.3"
@ -9,6 +17,22 @@ python-versions = ">=3.7"
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "cmd-proxy-xero"
version = "0.1.0"
description = ""
category = "main"
optional = false
python-versions = "^3.10"
develop = true
[package.dependencies]
xero-python = "^1.18.0"
[package.source]
type = "directory"
url = "../cmd-proxy_xero"
[[package]]
name = "colorama"
version = "0.4.5"
@ -65,6 +89,38 @@ category = "main"
optional = false
python-versions = ">=3.7"
[[package]]
name = "python-dateutil"
version = "2.8.2"
description = "Extensions to the standard Python datetime module"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
[package.dependencies]
six = ">=1.5"
[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "urllib3"
version = "1.26.12"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "werkzeug"
version = "2.2.2"
@ -79,16 +135,34 @@ MarkupSafe = ">=2.1.1"
[package.extras]
watchdog = ["watchdog"]
[[package]]
name = "xero-python"
version = "1.18.0"
description = "Official Python sdk for Xero API generated by OpenAPI spec for oAuth2"
category = "main"
optional = false
python-versions = ">=3.5"
[package.dependencies]
certifi = "*"
python-dateutil = ">=2.7"
urllib3 = "*"
[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "61c7943ff9f9922433780cd3ac588e35905564ec8f2273ea4b6b08f6a565fb97"
content-hash = "9a7c40a72352b2b41afe787a0b91b0b2ef64da6a0296597978750694355e63c1"
[metadata.files]
certifi = [
{file = "certifi-2022.6.15.1-py3-none-any.whl", hash = "sha256:43dadad18a7f168740e66944e4fa82c6611848ff9056ad910f8f7a3e46ab89e0"},
{file = "certifi-2022.6.15.1.tar.gz", hash = "sha256:cffdcd380919da6137f76633531a5817e3a9f268575c128249fb637e4f9e73fb"},
]
click = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
]
cmd-proxy-xero = []
colorama = [
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
@ -147,7 +221,22 @@ markupsafe = [
{file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"},
{file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"},
]
python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
urllib3 = [
{file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
{file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
]
werkzeug = [
{file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"},
{file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"},
]
xero-python = [
{file = "xero_python-1.18.0.tar.gz", hash = "sha256:99960f6026b4cd3cc182579f34fba6a1b3b8560c4e72f32a3d950ea0b6050f9d"},
]

View File

@ -6,7 +6,9 @@ authors = ["Jon Herron <jon.herron@yahoo.com>"]
[tool.poetry.dependencies]
python = "^3.10"
Flask = "^2.2.2"
Flask = "*"
cmd-proxy_xero = {develop = true, path = "/home/jon/dev/cmd-proxy_xero"}
[tool.poetry.dev-dependencies]