Index: html/bind.html ================================================================== --- html/bind.html +++ html/bind.html @@ -69,77 +69,160 @@ <dt id="pluginconf.bind.base"><code class="name flex"> <span>def <span class="ident">base</span></span>(<span>module, path=None)</span> </code></dt> <dd> <div class="desc"><p>Register module as package/plugin_base. Or expand its search path 🛠 .</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>module</code></strong> : <code>module/str</code></dt> -<dd>The package basename to later load plugins from (must be a package, -like <code>plugins/__init__.py</code>, or be tied to a path= or zip). Ideally -this module was already imported in main. But parameter may be a string.</dd> -<dt><strong><code>path</code></strong> : <code>str</code></dt> -<dd>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 <code>__path__</code> in the -base <code>package/__init__.py</code>.)</dd> -</dl></div> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>module</td> +<td>module/str</td> +<td>Package basename to later load plugins from</td> +</tr> +<tr> +<td>path</td> +<td>str</td> +<td>Bind directory or pyz/zip bundle to plugin_base.</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>None</td> +<td>-</td> +</tr> +</tbody> +</table> +<p>Module should be a package, as in a directory and init <code>plugins/__init__.py</code>. +Ideally this module was already imported in main. But parameter may be a string.</p> +<p>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 <code>__path__</code> in the <code>package/__init__.py</code>.</p></div> </dd> <dt id="pluginconf.bind.defaults"><code class="name flex"> <span>def <span class="ident">defaults</span></span>(<span>conf)</span> </code></dt> <dd> <div class="desc"><p>Traverse installed plugins and expand config dict with presets 🧩 🧾</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>conf</code></strong> : <code>dict 🔁</code></dt> -<dd>Expands the top-level config dict with preset values from any plugins.</dd> -</dl></div> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>conf</td> +<td>dict 🔁</td> +<td>Expands the conf dict with preset values from any plugins.</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>None</td> +<td>-</td> +</tr> +</tbody> +</table></div> </dd> <dt id="pluginconf.bind.find"><code class="name flex"> <span>def <span class="ident">find</span></span>(<span>**kwargs)</span> </code></dt> <dd> -<div class="desc"><p>Find plugins by e.g. type= or category= 🧩</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>type</code></strong> : <code>str</code></dt> -<dd>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.)</dd> -</dl> -<h2 id="returns">Returns</h2> -<dl> -<dt><strong><code>dict</code></strong> : <code>basename → PluginMeta dict</code></dt> -<dd> </dd> -</dl></div> +<div class="desc"><p>Find plugins by any combination of e.g. type= or category= 🧩</p> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>type</td> +<td>str</td> +<td>Search by type: in plugins</td> +</tr> +<tr> +<td>api</td> +<td>str</td> +<td>Matching api: designator</td> +</tr> +<tr> +<td>category</td> +<td>str</td> +<td>Or a menu/category or other attributes</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>dict</td> +<td>basename → <code>PluginMeta</code> dict of matches</td> +</tr> +</tbody> +</table></div> </dd> <dt id="pluginconf.bind.load"><code class="name flex"> <span>def <span class="ident">load</span></span>(<span>name)</span> </code></dt> <dd> -<div class="desc"><p>Import individual plugin from any of the base paths 🚐</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>name</code></strong> : <code>str</code></dt> -<dd>Plugin name in any of the registered plugin_base´s. (The whole -namespace is assumed to be flat, and identifiers to be unique.)</dd> -</dl></div> +<div class="desc"><p>Import individual plugin from any of the base paths 🚐 +(The whole namespace is assumed to be flat, and identifiers to be unique.)</p> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>name</td> +<td>str</td> +<td>Plugin name in any of the registered plugin_base´s.</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>module</td> +<td>Imported module</td> +</tr> +</tbody> +</table></div> </dd> <dt id="pluginconf.bind.load_enabled"><code class="name flex"> <span>def <span class="ident">load_enabled</span></span>(<span>conf)</span> </code></dt> <dd> <div class="desc"><p>Import modules that are enabled in conf[plugins]={name:True,…} 🧾 🚐</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>conf</code></strong> : <code>dict</code></dt> -<dd>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.</dd> -</dl></div> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>conf</td> +<td>dict</td> +<td>Should contain conf["plugins"] activation states</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>generator</td> +<td>Of loaded modules</td> +</tr> +</tbody> +</table></div> </dd> </dl> </section> <section> <h2 class="section-title" id="header-classes">Classes</h2> Index: html/index.html ================================================================== --- html/index.html +++ html/index.html @@ -30,11 +30,11 @@ <li> Main function <a href="#pluginconf.plugin_meta">plugin_meta()</a> unpacks meta fields into dictionaries. <li> Other utility code is about module listing, relative to <a href="#pluginconf.plugin_base">plugin_base</a> anchors. <li> <a href="https://pypi.org/project/pluginconf/">//pypi.org/project/pluginconf/</a> -<li> <a href="https://fossil.include-once.org/pluginspec/">//fossil.include-once.org/pluginspec/</a> +<li><a href="https://fossil.include-once.org/pluginspec/">//fossil.include-once.org/pluginspec/</a> </td></tr></table> </section> <section> <h2 class="section-title" id="header-submodules">Sub-modules</h2> <dl> @@ -91,105 +91,198 @@ </code></dt> <dd> <div class="desc"><p>Utility function which collect defaults from plugin meta data to a config store. Which in the case of streamtuner2 is really just a dictionary <code>conf{}</code> and a plugin list in <code>conf.plugins{}</code>.</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>conf_options</code></strong> : <code>dict : input/output</code></dt> -<dd>storage for amassed options</dd> -<dt><strong><code>conf_plugins</code></strong> : <code>dict : input/output</code></dt> -<dd>enable status based on plugin state/priority:</dd> -<dt><strong><code>meta</code></strong> : <code>dict</code></dt> -<dd>input plugin meta data (invoke once per plugin)</dd> -<dt><strong><code>module</code></strong> : <code>str</code></dt> -<dd>basename of meta: blocks plugin file</dd> -</dl></div> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>conf_options</td> +<td>dict 🔁</td> +<td>storage for amassed options</td> +</tr> +<tr> +<td>conf_plugins</td> +<td>dict 🔁</td> +<td>enable status based on plugin state/priority:</td> +</tr> +<tr> +<td>meta</td> +<td>dict</td> +<td>input plugin meta data (invoke once per plugin)</td> +</tr> +<tr> +<td>module</td> +<td>str</td> +<td>basename of meta: blocks plugin file</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>None</td> +<td>-</td> +</tr> +</tbody> +</table></div> </dd> <dt id="pluginconf.all_plugin_meta"><code class="name flex"> <span>def <span class="ident">all_plugin_meta</span></span>(<span>)</span> </code></dt> <dd> <div class="desc"><p>This is a trivial wrapper to assemble a complete dictionary of available/installed plugins. It associates each plugin name with a its meta{} fields.</p> -<h2 id="returns">Returns</h2> -<dl> -<dt><strong><code>dict</code></strong> : <code>names to meta data dict</code></dt> -<dd> </dd> -</dl></div> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td><strong>Returns</strong></td> +<td>dict</td> +<td>names to meta data dict</td> +</tr> +</tbody> +</table></div> </dd> <dt id="pluginconf.get_data"><code class="name flex"> <span>def <span class="ident">get_data</span></span>(<span>filename, decode=False, gzip=False, file_root=None)</span> </code></dt> <dd> <div class="desc"><p>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.</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>filename</code></strong> : <code> str</code></dt> -<dd>filename in pyz or bundle</dd> -<dt><strong><code>decode</code></strong> : <code>bool</code></dt> -<dd>text file decoding utf-8</dd> -<dt><strong><code>gzip</code></strong> : <code>bool</code></dt> -<dd>automatic gzdecode</dd> -<dt><strong><code>file_root</code></strong> : <code>list</code></dt> -<dd>alternative base module (application or pyz root)</dd> -</dl> -<h2 id="returns">Returns</h2> -<dl> -<dt><strong><code>str</code></strong> : <code>file contents</code></dt> -<dd> </dd> -</dl></div> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>filename</td> +<td>str</td> +<td>filename in pyz or bundle</td> +</tr> +<tr> +<td>decode</td> +<td>bool</td> +<td>text file decoding utf-8</td> +</tr> +<tr> +<td>gzip</td> +<td>bool</td> +<td>automatic gzdecode</td> +</tr> +<tr> +<td>file_root</td> +<td>list</td> +<td>alternative base module (application or pyz root)</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>str</td> +<td>file contents</td> +</tr> +</tbody> +</table></div> </dd> <dt id="pluginconf.module_list"><code class="name flex"> <span>def <span class="ident">module_list</span></span>(<span>extra_paths=None)</span> </code></dt> <dd> <div class="desc"><p>Search through ./plugins/ (and other configured plugin_base names → paths) and get module basenames.</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>extra_paths</code></strong> : <code>list</code></dt> -<dd>in addition to plugin_base list</dd> -</dl> -<h2 id="returns">Returns</h2> -<dl> -<dt><strong><code>list</code></strong> : <code>names</code> of <code>found plugins</code></dt> -<dd> </dd> -</dl></div> +<table> +<thead> +<tr> +<th>Parameter</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>extra_paths</td> +<td>list</td> +<td>in addition to plugin_base list</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>list</td> +<td>names of found plugins</td> +</tr> +</tbody> +</table></div> </dd> <dt id="pluginconf.plugin_meta"><code class="name flex"> <span>def <span class="ident">plugin_meta</span></span>(<span>filename=None, src=None, module=None, frame=1, **kwargs)</span> </code></dt> <dd> <div class="desc"><p>Extract plugin meta data block from specified source.</p> -<h2 id="parameters">Parameters</h2> -<dl> -<dt><strong><code>filename</code></strong> : <code>str</code></dt> -<dd>Read literal files, or .pyz contents.</dd> -<dt><strong><code>src</code></strong> : <code>str</code></dt> -<dd>From already uncovered script code.</dd> -<dt><strong><code>module</code></strong> : <code>str</code></dt> -<dd>Lookup per pkgutil, from plugin_base or top-level modules.</dd> -<dt><strong><code>frame</code></strong> : <code>int</code></dt> -<dd>Extract comment header of caller (default).</dd> -<dt><strong><code>extra_base</code></strong> : <code>list</code></dt> -<dd>Additional search directories.</dd> -<dt><strong><code>max_length</code></strong> : <code>list</code></dt> -<dd>Maximum size to read from files (6K default).</dd> -</dl> -<h2 id="returns">Returns</h2> -<dl> -<dt><strong><code>dict</code></strong> : <code>Extracted comment fields, with config: preparsed</code></dt> -<dd> </dd> -</dl> -<p>The result dictionary has fields accessible as e.g. <code>pmd["title"]</code> +<table> +<thead> +<tr> +<th>Parameters</th> +<th></th> +<th></th> +</tr> +</thead> +<tbody> +<tr> +<td>filename</td> +<td>str</td> +<td>Read literal files, or .pyz contents.</td> +</tr> +<tr> +<td>src</td> +<td>str</td> +<td>From already uncovered script code.</td> +</tr> +<tr> +<td>module</td> +<td>str</td> +<td>Lookup per pkgutil, relative to plugin_base</td> +</tr> +<tr> +<td>frame</td> +<td>int</td> +<td>Extract comment header of caller (default).</td> +</tr> +<tr> +<td>extra_base</td> +<td>list</td> +<td>Additional search directories.</td> +</tr> +<tr> +<td>max_length</td> +<td>list</td> +<td>Maximum size to read from files (6K default).</td> +</tr> +<tr> +<td><strong>Returns</strong></td> +<td>dict</td> +<td>Extracted comment fields, with config: preparsed</td> +</tr> +</tbody> +</table> +<p>The result dictionary (<code><a title="pluginconf.PluginMeta" href="#pluginconf.PluginMeta">PluginMeta</a></code>) has fields accessible as e.g. <code>pmd["title"]</code> or <code>pmd.version</code>. The documentation block after all fields: is called -["doc"]<code>. And </code>pmd.config` already parsed as a list of dictionaries.</p></div> +<code>["doc"]</code>. And <code>pmd.config</code> already parsed as a list (<code><a title="pluginconf.OptionList" href="#pluginconf.OptionList">OptionList</a></code>) of dictionaries.</p></div> </dd> </dl> </section> <section> <h2 class="section-title" id="header-classes">Classes</h2> Index: pluginconf/__init__.py ================================================================== --- pluginconf/__init__.py +++ pluginconf/__init__.py @@ -99,11 +99,11 @@ <li> Main function <a href="#pluginconf.plugin_meta">plugin_meta()</a> unpacks meta fields into dictionaries. <li> Other utility code is about module listing, relative to <a href="#pluginconf.plugin_base">plugin_base</a> anchors. <li> <a href="https://pypi.org/project/pluginconf/">//pypi.org/project/pluginconf/</a> - <li> <a href="https://fossil.include-once.org/pluginspec/">//fossil.include-once.org/pluginspec/</a> +<li><a href="https://fossil.include-once.org/pluginspec/">//fossil.include-once.org/pluginspec/</a> </td></tr></table> """ 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__ != []