Differences From Artifact [8927125c8f]:

To Artifact [ce733ed382]:


116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150


151

152
153
154

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
#-- reset pluginconf if .bind is used
pluginconf.plugin_base = []


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.)
    """

    for package in pluginconf.plugin_base:
        if package in ("", "."):
            continue
        module_name = package + "." + name
        if module_name in sys.modules:
            return sys.modules[module_name]
        try:
            return importlib.import_module(module_name)
        except ImportError:
            pass


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`.)
    """

    # if supplied as string, instead of active module
    if isinstance(module, str):
        module = sys.modules.get(module) or __import__(module)

    # add to search list
    if module.__name__ not in pluginconf.plugin_base:
        pluginconf.plugin_base.append(module.__name__)

    # enjoin dir or pyz
    if not hasattr(module, "__path__"):
        module.__path__ = [_dirname(module.__file__)]
    if path:
        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
    """

    def has_all(pmd):
        for key, dep in kwargs.items():
            if not pmd.get(key) == dep:
                break
        else:
            return True

    return pluginconf.PluginMeta({
        name: pmd for name, pmd in pluginconf.all_plugin_meta().items() if has_all(pmd)
    })


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.

    """
    for name, state in conf.get("plugins", conf).items():
        if not state:
            continue
        if name.startswith("_"):
            continue
        yield load(name)


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.

    """
    for name, pmd in pluginconf.all_plugin_meta().items():
        pluginconf.add_plugin_defaults(conf, conf["plugins"], pmd, name)


# pylint: disable=invalid-name
class isolated():







>

|
|
<
|
|


















|
|
<
|
>
>
|
>
|
|
<
>
|
<
|



















|

|
|
|
|
<
<
|
<
<
|


















|
|
<
<
|
<
<
>













|
|
<
|
>







116
117
118
119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153
154
155

156
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183


184


185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205


206


207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230
231
#-- reset pluginconf if .bind is used
pluginconf.plugin_base = []


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. |
    | **Returns** | module | Imported module               |
    """

    for package in pluginconf.plugin_base:
        if package in ("", "."):
            continue
        module_name = package + "." + name
        if module_name in sys.modules:
            return sys.modules[module_name]
        try:
            return importlib.import_module(module_name)
        except ImportError:
            pass


def base(module, path=None):
    """
    Register module as package/plugin_base. Or expand its search path 🛠 .

    | 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)

    # add to search list
    if module.__name__ not in pluginconf.plugin_base:
        pluginconf.plugin_base.append(module.__name__)

    # enjoin dir or pyz
    if not hasattr(module, "__path__"):
        module.__path__ = [_dirname(module.__file__)]
    if path:
        module.__path__.append(_dirname(path))


def find(**kwargs):
    """
    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:
                break
        else:
            return True

    return pluginconf.PluginMeta({
        name: pmd for name, pmd in pluginconf.all_plugin_meta().items() if has_all(pmd)
    })


def load_enabled(conf):
    """
    Import modules that are enabled in conf[plugins]={name:True,…} 🧾 🚐

    | 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("_"):
            continue
        yield load(name)


def defaults(conf):
    """
    Traverse installed plugins and expand config dict with presets 🧩 🧾

    | 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)


# pylint: disable=invalid-name
class isolated():