︙ | | |
99
100
101
102
103
104
105
106
107
108
109
| 99
100
101
102
103
104
105
106
107
108
109
|
-
+
| <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
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
| 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
238
239
240
|
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
-
+
-
+
-
-
-
+
+
-
-
+
-
-
-
-
+
-
+
| 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
----------
| Parameters | | |
|-------------|---------|----------------------------|
filename : str
filename in pyz or bundle
| filename | str | filename in pyz or bundle |
decode : bool
text file decoding utf-8
| decode | bool | text file decoding utf-8 |
gzip : bool
automatic gzdecode
| gzip | bool | automatic gzdecode |
file_root : list
alternative base module (application or pyz root)
| file_root | list | alternative base module (application or pyz root) |
Returns
-------
str : file contents
| **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)
log.warning("get_data() didn't find '%s' in '%s'", filename, file_root)
pass
# Plugin name lookup
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
def module_list(extra_paths=None):
"""
Search through ./plugins/ (and other configured plugin_base
names → paths) and get module basenames.
Parameters
----------
| Parameter | | |
|-------------|---------|---------------------------------|
extra_paths : list
in addition to plugin_base list
| extra_paths | list | in addition to plugin_base list |
Returns
-------
list : names of found plugins
| **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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
| 249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
|
-
-
-
+
+
+
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
-
+
-
+
-
+
| """
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()
}
# Plugin meta data extraction
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
@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
----------
| Parameters | | |
|-------------|---------|-------------------------------------------------|
filename : str
Read literal files, or .pyz contents.
| filename | str | Read literal files, or .pyz contents. |
src : str
From already uncovered script code.
| src | str | From already uncovered script code. |
module : str
Lookup per pkgutil, from plugin_base or top-level modules.
| module | str | Lookup per pkgutil, relative to plugin_base |
frame : int
Extract comment header of caller (default).
| frame | int | Extract comment header of caller (default). |
extra_base : list
Additional search directories.
| extra_base | list | Additional search directories. |
max_length : list
Maximum size to read from files (6K default).
| max_length | list | Maximum size to read from files (6K default). |
Returns
-------
dict : Extracted comment fields, with config: preparsed
| **Returns** | dict | Extracted comment fields, with config: preparsed|
The result dictionary has fields accessible as e.g. `pmd["title"]`
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
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
| 329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
|
-
-
+
+
-
-
+
-
-
+
-
-
+
+
| """
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
----------
| Parameters | | |
|-------------|---------|---------------------------------|
src : str
from existing source code
| src | str | from existing source code |
filename : str
set filename attribute
| filename | str | set filename attribute |
literls : bool
just split comment from doc
| literls | bool | just split comment from doc |
| **Returns** | dict | fields |
"""
# Defaults
meta = {
"id": os.path.splitext(os.path.basename(filename or ""))[0],
|
︙ | | |
380
381
382
383
384
385
386
387
388
389
390
| 357
358
359
360
361
362
363
364
365
366
367
|
-
+
| # 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
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
| 418
419
420
421
422
423
424
425
426
427
428
429
430
431
|
-
-
+
+
-
-
+
-
-
-
-
+
| Stubs out name, value, type, description if absent.
# config:
{ name: 'var1', type: text, value: "default, ..." }
{ name=option2, type=boolean, $value=1, etc. }
Parameters
----------
| Parameters | | |
|-------------|---------|--------------------------------------|
src : str
unprocessed config: field
| src | str | unprocessed config: field |
Returns
-------
list : of option dictionaries
| **Returns** | list | of option dictionaries |
"""
config = []
for entry in rx.config.findall(src):
entry = entry[0] or entry[1]
|
︙ | | |
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
| 555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
|
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
+
-
+
| """
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
----------
| Parameters | | |
|-------------|---------|--------------------------------------|
conf_options : dict : input/output
storage for amassed options
|conf_options | dict 🔁 | storage for amassed options |
conf_plugins : dict : input/output
enable status based on plugin state/priority:
|conf_plugins | dict 🔁 | enable status based on plugin state/priority: |
meta : dict
input plugin meta data (invoke once per plugin)
|meta | dict | input plugin meta data (invoke once per plugin)|
module : str
basename of meta: blocks plugin file
|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
|
︙ | | |