Internet radio browser GUI for music/video streams from various directory services.

⌈⌋ ⎇ branch:  streamtuner2


Check-in [a8ede6f518]

Overview
Comment:Updated to 0.7.3
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a8ede6f5181fcb66535b7efc7c0161f32569668c
User & Date: mario on 2020-12-12 15:10:20
Other Links: manifest | tags
Context
2020-12-12
15:11
Update configwin for select:{} being preparsed by pluginconf now check-in: 798a7746aa user: mario tags: trunk
15:10
Updated to 0.7.3 check-in: a8ede6f518 user: mario tags: trunk
15:10
Add uikit.get_bg_color() for TreeView search, but keep #ffffff for Gtk2 check-in: 2956305120 user: mario tags: trunk
Changes

Modified pluginconf.py from [8d185cdf67] to [d31c994508].

1
2
3
4
5
6
7



8
9
10
11
12
13
14
# encoding: UTF-8
# api: python
# type: extract
# category: io
# title: Plugin configuration
# description: Read meta data, pyz/package contents, module locating
# version: 0.7.1



# priority: core
# docs: https://fossil.include-once.org/pluginspec/
# url: http://fossil.include-once.org/streamtuner2/wiki/plugin+meta+data
# config: -
#
# Provides plugin lookup and meta data extraction utility functions.
# It's used to abstract module+option management in applications.
|


|


|
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# encoding: utf-8
# api: python
# type: extract
# category: config
# title: Plugin configuration
# description: Read meta data, pyz/package contents, module locating
# version: 0.7.3
# state: stable
# classifiers: documentation
# license: PD
# priority: core
# docs: https://fossil.include-once.org/pluginspec/
# url: http://fossil.include-once.org/streamtuner2/wiki/plugin+meta+data
# config: -
#
# Provides plugin lookup and meta data extraction utility functions.
# It's used to abstract module+option management in applications.
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128


# Injectables
# ‾‾‾‾‾‾‾‾‾‾‾
log_ERR = lambda *x: None

# File lookup relation for get_data(), should name a top-level package.
module_base = "config"

# Package/module names for module_list() and plugin_meta() lookups.
# All associated paths will be scanned for module/plugin basenames.
plugin_base = ["channels"]


# Resource retrieval
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Fetches file content from install path or from within PYZ
# archive. This is just an alias and convenience wrapper for
# pkgutil.get_data().







|



|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131


# Injectables
# ‾‾‾‾‾‾‾‾‾‾‾
log_ERR = lambda *x: None

# File lookup relation for get_data(), should name a top-level package.
module_base = "config"         # equivalent PluginBase(package=…)

# Package/module names for module_list() and plugin_meta() lookups.
# All associated paths will be scanned for module/plugin basenames.
plugin_base = ["channels"]     # equivalent to `searchpath` in PluginBase


# Resource retrieval
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Fetches file content from install path or from within PYZ
# archive. This is just an alias and convenience wrapper for
# pkgutil.get_data().
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# split up `select: 1=on|2=more|3=title` or `select: foo|bar|lists`
def config_opt_parse_select(s):
    if re.search("([=:])", s):
        return dict(rx.select_dict.findall(s))
    else:
        return dict([(v, v) for v in rx.select_list.findall(s)])

# normalize type:names to `str`, `bool`, `int`, `select`, `dict`
config_opt_type_map = dict(
    text="str", string="str", boolean="bool", checkbox="bool", integer="int", number="int",
    choice="select", options="select", table="dict", array="dict"
)


# Comment extraction regexps
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Pretty crude comment splitting approach. But works







|

|







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# split up `select: 1=on|2=more|3=title` or `select: foo|bar|lists`
def config_opt_parse_select(s):
    if re.search("([=:])", s):
        return dict(rx.select_dict.findall(s))
    else:
        return dict([(v, v) for v in rx.select_list.findall(s)])

# normalize type:names to `str`, `text`, `bool`, `int`, `select`, `dict`
config_opt_type_map = dict(
    longstr="text", string="str", boolean="bool", checkbox="bool", integer="int", number="int",
    choice="select", options="select", table="dict", array="dict"
)


# Comment extraction regexps
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Pretty crude comment splitting approach. But works
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
        ["':$]?   (\w*)  ["']?                 # key or ":key" or '$key'
        \s* [:=] \s*                           # "=" or ":"
     (?:  "  ([^"]*)  "
       |  '  ([^']*)  '                        #  "quoted" or 'singl' values
       |     ([^,]*)                           #  or unquoted literals
     )
    """, re.X)
    select_dict = re.compile("(\w+)\s*[=:>]+\s*([^=,|:]+)")
    select_list = re.compile("\s*([^,|;]+)\s*")



# ArgumentParser options conversion
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# As variation of in-application config: options, this method converts
# cmdline argument specifiers.







|
|







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
        ["':$]?   (\w*)  ["']?                 # key or ":key" or '$key'
        \s* [:=] \s*                           # "=" or ":"
     (?:  "  ([^"]*)  "
       |  '  ([^']*)  '                        #  "quoted" or 'singl' values
       |     ([^,]*)                           #  or unquoted literals
     )
    """, re.X)
    select_dict = re.compile(r"(\w+)\s*[=:>]+\s*([^=,|:]+)")
    select_list = re.compile(r"\s*([^,|;]+)\s*")



# ArgumentParser options conversion
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# As variation of in-application config: options, this method converts
# cmdline argument specifiers.
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# meta['config'][] options to convert them.
#
def argparse_map(opt):
    if not ("arg" in opt and opt["name"] and opt["type"]):
        return {}

    # Extract --flag names
    args = opt["arg"].split() + re.findall("-+\w+", opt["name"])

    # Prepare mapping options
    typing = re.findall("bool|str|\[\]|const|false|true", opt["type"])
    naming = re.findall("\[\]", opt["name"])
    name = re.findall("(?<!-)\\b\\w+", opt["name"])
    nargs = re.findall("\\b\d+\\b|[\?\*\+]", opt["type"]) or [None]
    is_arr = "[]" in (naming + typing) and nargs == [None]
    is_bool = "bool" in typing
    false_b = "false" in typing or opt["value"] in ("0", "false")
    # print("\nname=", name, "is_arr=", is_arr, "is_bool=", is_bool,
    # "bool_d=", false_b, "naming=", naming, "typing=", typing)

    # Populate combination as far as ArgumentParser permits







|


|
|
|
|







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# meta['config'][] options to convert them.
#
def argparse_map(opt):
    if not ("arg" in opt and opt["name"] and opt["type"]):
        return {}

    # Extract --flag names
    args = opt["arg"].split() + re.findall(r"-+\w+", opt["name"])

    # Prepare mapping options
    typing = re.findall(r"bool|str|\[\]|const|false|true", opt["type"])
    naming = re.findall(r"\[\]", opt["name"])
    name = re.findall(r"(?<!-)\b\w+", opt["name"])
    nargs = re.findall(r"\b\d+\b|[\?\*\+]", opt["type"]) or [None]
    is_arr = "[]" in (naming + typing) and nargs == [None]
    is_bool = "bool" in typing
    false_b = "false" in typing or opt["value"] in ("0", "false")
    # print("\nname=", name, "is_arr=", is_arr, "is_bool=", is_bool,
    # "bool_d=", false_b, "naming=", naming, "typing=", typing)

    # Populate combination as far as ArgumentParser permits
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
        self.have.update(all_plugin_meta())
        # add core modules
        for name in core:
            self.have[name] = plugin_meta(module=name, extra_base=["config"])
        # aliases
        for name, meta in self.have.copy().items():
            if meta.get("alias"):
                for alias in re.split("\s*[,;]\s*", meta["alias"]):
                    self.have[alias] = self.have[name]

    # basic plugin pre-screening (skip __init__, filter by api:,
    # exclude installed & same-version plugins)
    def valid(self, newpl, _log=lambda *x:0):
        id = newpl.get("$name", "__invalid")
        have_ver = self.have.get(id, {}).get("version", "0")







|







452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
        self.have.update(all_plugin_meta())
        # add core modules
        for name in core:
            self.have[name] = plugin_meta(module=name, extra_base=["config"])
        # aliases
        for name, meta in self.have.copy().items():
            if meta.get("alias"):
                for alias in re.split(r"\s*[,;]\s*", meta["alias"]):
                    self.have[alias] = self.have[name]

    # basic plugin pre-screening (skip __init__, filter by api:,
    # exclude installed & same-version plugins)
    def valid(self, newpl, _log=lambda *x:0):
        id = newpl.get("$name", "__invalid")
        have_ver = self.have.get(id, {}).get("version", "0")
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
    # Option defaults, if not yet defined
    for opt in meta.get("config", []):
        if "name" in opt and "value" in opt:
            _value = opt.get("value", "")
            _name = opt.get("name")
            _type = opt.get("type")
            if _name not in conf_options:
                # typemap "bool" and "int" here
                if _type in ("bool", "boolean"):
                    val = _value.lower() in ("1", "true", "yes", "on")
                elif _type in ("int", "integer", "numeric"):
                    val = int(_value)
                elif _type in ("array", "table", "list"):
                    val = [ re.split("\s*[,;]\s*", s.strip()) for s in re.split("\s[|]\s*", _value) ]
                elif _type in ("dict"):
                    val = dict([ re.split("\s*(?:=>+|==*|-+>|:=+)\s*", s.strip()) for s in re.split("\s*[|;,]\s*", _value) ])
                else:
                    val = str(_value)
                conf_options[_name] = val

    # Initial plugin activation status
    if module and module not in conf_plugins:
        conf_plugins[module] = meta.get("priority") in (
            "core", "builtin", "always", "default", "standard"
        )









|
|

|

|
|
|
|











567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
    # Option defaults, if not yet defined
    for opt in meta.get("config", []):
        if "name" in opt and "value" in opt:
            _value = opt.get("value", "")
            _name = opt.get("name")
            _type = opt.get("type")
            if _name not in conf_options:
                # typemap
                if _type == "bool":
                    val = _value.lower() in ("1", "true", "yes", "on")
                elif _type == "int":
                    val = int(_value)
                elif _type in ("table", "list"):
                    val = [ re.split(r"\s*[,;]\s*", s.strip()) for s in re.split(r"\s*[|]\s*", _value) ]
                elif _type == "dict":
                    val = dict([ re.split(r"\s*(?:=>+|==*|-+>|:=+)\s*", s.strip(), 1) for s in re.split(r"\s*[|;,]\s*", _value) ])
                else:
                    val = str(_value)
                conf_options[_name] = val

    # Initial plugin activation status
    if module and module not in conf_plugins:
        conf_plugins[module] = meta.get("priority") in (
            "core", "builtin", "always", "default", "standard"
        )