Index: html/bind.html
==================================================================
--- html/bind.html
+++ html/bind.html
@@ -69,77 +69,160 @@
def base(module, path=None)
Register module as package/plugin_base. Or expand its search path 🛠 .
-
Parameters
-
-module
: module/str
-- The package basename to later load plugins from (must be a package,
-like
plugins/__init__.py
, or be tied to a path= or zip). Ideally
-this module was already imported in main. But parameter may be a string.
-path
: str
-- Add a directory or pyz/zip bundle to registered plugin_base. Could
-be invoked multiple times =./contrib/, =/usr/share/app/extenstions/,
-=~/.config/app/userplug/ (same as declaring the
__path__
in the
-base package/__init__.py
.)
-
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+module |
+module/str |
+Package basename to later load plugins from |
+
+
+path |
+str |
+Bind directory or pyz/zip bundle to plugin_base. |
+
+
+Returns |
+None |
+- |
+
+
+
+Module should be a package, as in a directory and init plugins/__init__.py
.
+Ideally this module was already imported in main. But parameter may be a string.
+This could be invoked multiple times for the package name to append further
+path= arguments (=./contrib/, =/usr/share/app/extenstions/, or a .pyz). Which
+is functionally identical to delcaring __path__
in the package/__init__.py
.
def defaults(conf)
Traverse installed plugins and expand config dict with presets 🧩 🧾
-
Parameters
-
-conf
: dict 🔁
-- Expands the top-level config dict with preset values from any plugins.
-
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+conf |
+dict 🔁 |
+Expands the conf dict with preset values from any plugins. |
+
+
+Returns |
+None |
+- |
+
+
+
def find(**kwargs)
-Find plugins by e.g. type= or category= 🧩
-
Parameters
-
-type
: str
-- Usually you'd search on a designated plugin categorization, like type=
-and api=, or slot=, or class= or whatever is most consistent. Multiple
-attributes can be filtered on. (Version/title probably not useful here.)
-
-
Returns
-
-dict
: basename → PluginMeta dict
--
-
+Find plugins by any combination of e.g. type= or category= 🧩
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+type |
+str |
+Search by type: in plugins |
+
+
+api |
+str |
+Matching api: designator |
+
+
+category |
+str |
+Or a menu/category or other attributes |
+
+
+Returns |
+dict |
+basename → PluginMeta dict of matches |
+
+
+
def load(name)
-Import individual plugin from any of the base paths 🚐
-
Parameters
-
-name
: str
-- Plugin name in any of the registered plugin_base´s. (The whole
-namespace is assumed to be flat, and identifiers to be unique.)
-
+Import individual plugin from any of the base paths 🚐
+(The whole namespace is assumed to be flat, and identifiers to be unique.)
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+name |
+str |
+Plugin name in any of the registered plugin_base´s. |
+
+
+Returns |
+module |
+Imported module |
+
+
+
def load_enabled(conf)
Import modules that are enabled in conf[plugins]={name:True,…} 🧾 🚐
-
Parameters
-
-conf
: dict
-- Simple options-value dictionary, but with one conf["plugins"] = {} subdict,
-which holds plugin activation states. The config dict doesn't have to match
-the available plugin options (defaults can be added), but should focus on
-essential presets. Differentiation only might become relevant for storage.
-
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+conf |
+dict |
+Should contain conf["plugins"] activation states |
+
+
+Returns |
+generator |
+Of loaded modules |
+
+
+
@@ -91,105 +91,198 @@
-
Utility function which collect defaults from plugin meta data to
a config store. Which in the case of streamtuner2 is really just a
dictionary conf{}
and a plugin list in conf.plugins{}
.
-
Parameters
-
-conf_options
: dict : input/output
-- storage for amassed options
-conf_plugins
: dict : input/output
-- enable status based on plugin state/priority:
-meta
: dict
-- input plugin meta data (invoke once per plugin)
-module
: str
-- basename of meta: blocks plugin file
-
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+conf_options |
+dict 🔁 |
+storage for amassed options |
+
+
+conf_plugins |
+dict 🔁 |
+enable status based on plugin state/priority: |
+
+
+meta |
+dict |
+input plugin meta data (invoke once per plugin) |
+
+
+module |
+str |
+basename of meta: blocks plugin file |
+
+
+Returns |
+None |
+- |
+
+
+
def all_plugin_meta()
-
This is a trivial wrapper to assemble a complete dictionary
of available/installed plugins. It associates each plugin name
with a its meta{} fields.
-
Returns
-
-dict
: names to meta data dict
--
-
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+Returns |
+dict |
+names to meta data dict |
+
+
+
def get_data(filename, decode=False, gzip=False, file_root=None)
-
Fetches file content from install path or from within PYZ
archive. This is just an alias and convenience wrapper for
pkgutil.get_data().
Utilizes the data_root as top-level reference.
-
Parameters
-
-filename
: str
-- filename in pyz or bundle
-decode
: bool
-- text file decoding utf-8
-gzip
: bool
-- automatic gzdecode
-file_root
: list
-- alternative base module (application or pyz root)
-
-
Returns
-
-str
: file contents
--
-
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+filename |
+str |
+filename in pyz or bundle |
+
+
+decode |
+bool |
+text file decoding utf-8 |
+
+
+gzip |
+bool |
+automatic gzdecode |
+
+
+file_root |
+list |
+alternative base module (application or pyz root) |
+
+
+Returns |
+str |
+file contents |
+
+
+
def module_list(extra_paths=None)
-
Search through ./plugins/ (and other configured plugin_base
names → paths) and get module basenames.
-
Parameters
-
-extra_paths
: list
-- in addition to plugin_base list
-
-
Returns
-
-list
: names
of found plugins
--
-
+
+
+
+Parameter |
+ |
+ |
+
+
+
+
+extra_paths |
+list |
+in addition to plugin_base list |
+
+
+Returns |
+list |
+names of found plugins |
+
+
+
def plugin_meta(filename=None, src=None, module=None, frame=1, **kwargs)
-
Extract plugin meta data block from specified source.
-
Parameters
-
-filename
: str
-- Read literal files, or .pyz contents.
-src
: str
-- From already uncovered script code.
-module
: str
-- Lookup per pkgutil, from plugin_base or top-level modules.
-frame
: int
-- Extract comment header of caller (default).
-extra_base
: list
-- Additional search directories.
-max_length
: list
-- Maximum size to read from files (6K default).
-
-
Returns
-
-dict
: Extracted comment fields, with config: preparsed
--
-
-
The result dictionary has fields accessible as e.g. pmd["title"]
+
+
+
+Parameters |
+ |
+ |
+
+
+
+
+filename |
+str |
+Read literal files, or .pyz contents. |
+
+
+src |
+str |
+From already uncovered script code. |
+
+
+module |
+str |
+Lookup per pkgutil, relative to plugin_base |
+
+
+frame |
+int |
+Extract comment header of caller (default). |
+
+
+extra_base |
+list |
+Additional search directories. |
+
+
+max_length |
+list |
+Maximum size to read from files (6K default). |
+
+
+Returns |
+dict |
+Extracted comment fields, with config: preparsed |
+
+
+
+
The result dictionary (PluginMeta
) has fields accessible as e.g. pmd["title"]
or pmd.version
. The documentation block after all fields: is called
-["doc"]. And
pmd.config` already parsed as a list of dictionaries.
+["doc"]
. And pmd.config
already parsed as a list (OptionList
) of dictionaries.
Index: pluginconf/__init__.py
==================================================================
--- pluginconf/__init__.py
+++ pluginconf/__init__.py
@@ -99,11 +99,11 @@
Main function plugin_meta() unpacks meta fields
into dictionaries.
Other utility code is about module listing, relative to
plugin_base anchors.
//pypi.org/project/pluginconf/
- //fossil.include-once.org/pluginspec/
+//fossil.include-once.org/pluginspec/
"""
import sys
@@ -191,62 +191,50 @@
Fetches file content from install path or from within PYZ
archive. This is just an alias and convenience wrapper for
pkgutil.get_data().
Utilizes the data_root as top-level reference.
- Parameters
- ----------
- filename : str
- filename in pyz or bundle
- decode : bool
- text file decoding utf-8
- gzip : bool
- automatic gzdecode
- file_root : list
- alternative base module (application or pyz root)
-
- Returns
- -------
- str : file contents
+ | Parameters | | |
+ |-------------|---------|----------------------------|
+ | filename | str | filename in pyz or bundle |
+ | decode | bool | text file decoding utf-8 |
+ | gzip | bool | automatic gzdecode |
+ | file_root | list | alternative base module (application or pyz root) |
+ | **Returns** | str | file contents |
"""
try:
data = pkgutil.get_data(file_root or data_root, filename)
if gzip:
data = gzip_decode(data)
if decode:
return data.decode("utf-8", errors='ignore')
return str(data)
except: #(FileNotFoundError, IOError, OSError, ImportError, gzip.BadGzipFile):
- log.error("get_data() didn't find '%s' in '%s'", filename, file_root)
- pass
+ log.warning("get_data() didn't find '%s' in '%s'", filename, file_root)
# Plugin name lookup
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
def module_list(extra_paths=None):
"""
Search through ./plugins/ (and other configured plugin_base
names → paths) and get module basenames.
- Parameters
- ----------
- extra_paths : list
- in addition to plugin_base list
-
- Returns
- -------
- list : names of found plugins
+ | Parameter | | |
+ |-------------|---------|---------------------------------|
+ | extra_paths | list | in addition to plugin_base list |
+ | **Returns** | list | names of found plugins |
"""
# Convert plugin_base package names into paths for iter_modules
paths = []
for module_or_path in plugin_base:
if sys.modules.get(module_or_path):
try:
paths += sys.modules[module_or_path].__path__
except AttributeError:
- paths += os.path.dirname(os.path.realname(
+ paths += os.path.dirname(os.path.realpath(
sys.modules[module_or_path]
))
elif os.path.exists(module_or_path):
paths.append(module_or_path)
@@ -261,13 +249,13 @@
"""
This is a trivial wrapper to assemble a complete dictionary
of available/installed plugins. It associates each plugin name
with a its meta{} fields.
- Returns
- -------
- dict : names to meta data dict
+ | Parameters | | |
+ |-------------|---------|---------------------------------|
+ | **Returns** | dict | names to meta data dict |
"""
return {
name: plugin_meta(module=name) for name in module_list()
}
@@ -277,32 +265,23 @@
@renamed_arguments({"fn": "filename"})
def plugin_meta(filename=None, src=None, module=None, frame=1, **kwargs):
"""
Extract plugin meta data block from specified source.
- Parameters
- ----------
- filename : str
- Read literal files, or .pyz contents.
- src : str
- From already uncovered script code.
- module : str
- Lookup per pkgutil, from plugin_base or top-level modules.
- frame : int
- Extract comment header of caller (default).
- extra_base : list
- Additional search directories.
- max_length : list
- Maximum size to read from files (6K default).
-
- Returns
- -------
- dict : Extracted comment fields, with config: preparsed
-
- The result dictionary has fields accessible as e.g. `pmd["title"]`
+ | Parameters | | |
+ |-------------|---------|-------------------------------------------------|
+ | filename | str | Read literal files, or .pyz contents. |
+ | src | str | From already uncovered script code. |
+ | module | str | Lookup per pkgutil, relative to plugin_base |
+ | frame | int | Extract comment header of caller (default). |
+ | extra_base | list | Additional search directories. |
+ | max_length | list | Maximum size to read from files (6K default). |
+ | **Returns** | dict | Extracted comment fields, with config: preparsed|
+
+ The result dictionary (`PluginMeta`) has fields accessible as e.g. `pmd["title"]`
or `pmd.version`. The documentation block after all fields: is called
- ["doc"]`. And `pmd.config` already parsed as a list of dictionaries.
+ `["doc"]`. And `pmd.config` already parsed as a list (`OptionList`) of dictionaries.
"""
# Try via pkgutil first,
# find any plugins.* modules, or main packages
if module:
@@ -350,18 +329,16 @@
"""
Finds the first comment block. Splits key:value header
fields from comment. Turns everything into an dict, with
some stub fields if absent. Dashes substituted for underscores.
- Parameters
- ----------
- src : str
- from existing source code
- filename : str
- set filename attribute
- literls : bool
- just split comment from doc
+ | Parameters | | |
+ |-------------|---------|---------------------------------|
+ | src | str | from existing source code |
+ | filename | str | set filename attribute |
+ | literls | bool | just split comment from doc |
+ | **Returns** | dict | fields |
"""
# Defaults
meta = {
"id": os.path.splitext(os.path.basename(filename or ""))[0],
@@ -380,11 +357,11 @@
# Extract coherent comment block
src = src.replace("\r", "")
if not literal:
src = rx.comment.search(src)
if not src:
- log.warn("Couldn't read source meta information: %s", filename)
+ log.warning("Couldn't read source meta information: %s", filename)
return meta
src = src.group(0)
src = rx.hash.sub("", src).strip()
# Split comment block
@@ -441,18 +418,14 @@
Stubs out name, value, type, description if absent.
# config:
{ name: 'var1', type: text, value: "default, ..." }
{ name=option2, type=boolean, $value=1, etc. }
- Parameters
- ----------
- src : str
- unprocessed config: field
-
- Returns
- -------
- list : of option dictionaries
+ | Parameters | | |
+ |-------------|---------|--------------------------------------|
+ | src | str | unprocessed config: field |
+ | **Returns** | list | of option dictionaries |
"""
config = []
for entry in rx.config.findall(src):
entry = entry[0] or entry[1]
@@ -582,27 +555,24 @@
"""
Utility function which collect defaults from plugin meta data to
a config store. Which in the case of streamtuner2 is really just a
dictionary `conf{}` and a plugin list in `conf.plugins{}`.
- Parameters
- ----------
- conf_options : dict : input/output
- storage for amassed options
- conf_plugins : dict : input/output
- enable status based on plugin state/priority:
- meta : dict
- input plugin meta data (invoke once per plugin)
- module : str
- basename of meta: blocks plugin file
+ | Parameters | | |
+ |-------------|---------|--------------------------------------|
+ |conf_options | dict 🔁 | storage for amassed options |
+ |conf_plugins | dict 🔁 | enable status based on plugin state/priority: |
+ |meta | dict | input plugin meta data (invoke once per plugin)|
+ |module | str | basename of meta: blocks plugin file |
+ | **Returns** | None | - |
"""
# Option defaults, if not yet defined
for opt in meta.get("config", []):
if "name" not in opt or "value" not in opt:
continue
- _value = opt.get("value", "")
+ _value = opt.get("value") or ""
_name = opt.get("name")
_type = opt.get("type")
if _name in conf_options:
continue
# typemap
Index: pluginconf/bind.py
==================================================================
--- pluginconf/bind.py
+++ pluginconf/bind.py
@@ -118,16 +118,16 @@
def load(name):
"""
Import individual plugin from any of the base paths 🚐
+ (The whole namespace is assumed to be flat, and identifiers to be unique.)
- Parameters
- ----------
- name : str
- Plugin name in any of the registered plugin_base´s. (The whole
- namespace is assumed to be flat, and identifiers to be unique.)
+ | Parameters | | |
+ |-------------|--------|-------------------------------|
+ | name | str | Plugin name in any of the registered plugin_base´s. |
+ | **Returns** | module | Imported module |
"""
for package in pluginconf.plugin_base:
if package in ("", "."):
continue
@@ -142,21 +142,22 @@
def base(module, path=None):
"""
Register module as package/plugin_base. Or expand its search path 🛠 .
- Parameters
- ----------
- module : module/str
- The package basename to later load plugins from (must be a package,
- like `plugins/__init__.py`, or be tied to a path= or zip). Ideally
- this module was already imported in main. But parameter may be a string.
- path : str
- Add a directory or pyz/zip bundle to registered plugin_base. Could
- be invoked multiple times =./contrib/, =/usr/share/app/extenstions/,
- =~/.config/app/userplug/ (same as declaring the `__path__` in the
- base `package/__init__.py`.)
+ | Parameters | | |
+ |-------------|------------|-------------------------------|
+ | module | module/str | Package basename to later load plugins from |
+ | path | str | Bind directory or pyz/zip bundle to plugin_base. |
+ | **Returns** | None | - |
+
+ Module should be a package, as in a directory and init `plugins/__init__.py`.
+ Ideally this module was already imported in main. But parameter may be a string.
+
+ This could be invoked multiple times for the package name to append further
+ path= arguments (=./contrib/, =/usr/share/app/extenstions/, or a .pyz). Which
+ is functionally identical to delcaring `__path__` in the `package/__init__.py`.
"""
# if supplied as string, instead of active module
if isinstance(module, str):
module = sys.modules.get(module) or __import__(module)
@@ -172,22 +173,18 @@
module.__path__.append(_dirname(path))
def find(**kwargs):
"""
- Find plugins by e.g. type= or category= 🧩
-
- Parameters
- ----------
- type : str
- Usually you'd search on a designated plugin categorization, like type=
- and api=, or slot=, or class= or whatever is most consistent. Multiple
- attributes can be filtered on. (Version/title probably not useful here.)
-
- Returns
- ----------
- dict : basename → PluginMeta dict
+ Find plugins by any combination of e.g. type= or category= 🧩
+
+ | Parameters | | |
+ |-------------|-----------|-------------------------------------------|
+ | type | str | Search by type: in plugins |
+ | api | str | Matching api: designator |
+ | category | str | Or a menu/category or other attributes |
+ | **Returns** | dict | basename → `PluginMeta` dict of matches |
"""
def has_all(pmd):
for key, dep in kwargs.items():
if not pmd.get(key) == dep:
@@ -202,17 +199,14 @@
def load_enabled(conf):
"""
Import modules that are enabled in conf[plugins]={name:True,…} 🧾 🚐
- Parameters
- ----------
- conf : dict
- Simple options-value dictionary, but with one conf["plugins"] = {} subdict,
- which holds plugin activation states. The config dict doesn't have to match
- the available plugin options (defaults can be added), but should focus on
- essential presets. Differentiation only might become relevant for storage.
+ | Parameters | | |
+ |-------------|-----------|-------------------------------------------|
+ | conf | dict | Should contain conf["plugins"] activation states |
+ | **Returns** | generator | Of loaded modules |
"""
for name, state in conf.get("plugins", conf).items():
if not state:
continue
if name.startswith("_"):
@@ -222,14 +216,14 @@
def defaults(conf):
"""
Traverse installed plugins and expand config dict with presets 🧩 🧾
- Parameters
- ----------
- conf : dict 🔁
- Expands the top-level config dict with preset values from any plugins.
+ | Parameters | | |
+ |-------------|-----------|-------------------------------------------|
+ | conf | dict 🔁 | Expands the conf dict with preset values from any plugins. |
+ | **Returns** | None | - |
"""
for name, pmd in pluginconf.all_plugin_meta().items():
pluginconf.add_plugin_defaults(conf, conf["plugins"], pmd, name)
Index: test/bind.py
==================================================================
--- test/bind.py
+++ test/bind.py
@@ -12,11 +12,11 @@
import pluginconf
print(pluginconf.plugin_base)
import pluginconf.bind
-def init(reset):
+def init():
# pluginconf.plugin_base = []
import test.plugins
pluginconf.bind.base(test.plugins)
assert "test.plugins" in pluginconf.plugin_base
assert test.plugins.__path__ != []