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
modulemodule/strPackage basename to later load plugins from
pathstrBind directory or pyz/zip bundle to plugin_base.
ReturnsNone-
+

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
confdict 🔁Expands the conf dict with preset values from any plugins.
ReturnsNone-
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
typestrSearch by type: in plugins
apistrMatching api: designator
categorystrOr a menu/category or other attributes
Returnsdictbasename → 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
namestrPlugin name in any of the registered plugin_base´s.
ReturnsmoduleImported 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
confdictShould contain conf["plugins"] activation states
ReturnsgeneratorOf loaded modules

Classes

Index: html/index.html ================================================================== --- html/index.html +++ html/index.html @@ -30,11 +30,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/
  • Sub-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_optionsdict 🔁storage for amassed options
    conf_pluginsdict 🔁enable status based on plugin state/priority:
    metadictinput plugin meta data (invoke once per plugin)
    modulestrbasename of meta: blocks plugin file
    ReturnsNone-
    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
    Returnsdictnames 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
    filenamestrfilename in pyz or bundle
    decodebooltext file decoding utf-8
    gzipboolautomatic gzdecode
    file_rootlistalternative base module (application or pyz root)
    Returnsstrfile 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_pathslistin addition to plugin_base list
    Returnslistnames 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
    filenamestrRead literal files, or .pyz contents.
    srcstrFrom already uncovered script code.
    modulestrLookup per pkgutil, relative to plugin_base
    frameintExtract comment header of caller (default).
    extra_baselistAdditional search directories.
    max_lengthlistMaximum size to read from files (6K default).
    ReturnsdictExtracted 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.

    Classes

    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__ != []