1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | #
# encoding: UTF-8
# api: streamtuner2
# type: class
# title: global config object
# description: reads ~/.config/streamtuner/*.json files
# config:
# { arg: -d, type: str, name: plugin[], description: omit plugin from initialization }
# { arg: --gtk3, type: boolean, name: gtk3, description: use gtk3 interface }
# { arg: -D, type: boolean, name: debug, description: enable debug messages on console }
# { arg: action, type: str*, name: action[], description: commandline actions }
# { arg: -x, type: boolean, name: exit, description: terminate right away }
#
# In the main application or module files which need access
# to a global conf.* object, just import this module as follows:
#
# from config import *
#
# Here conf is already an instantiation of the underlying
# ConfigDoct class.
#
# Also provides the logging function __print__, and basic
# plugin handling code: plugin_meta() and module_list(),
# and the relative get_data() alias (files from pyzip/path).
#
import os
import sys
import json
import gzip
import platform
import re
from compat2and3 import gzip_decode, find_executable |
|
>
|
|
|
|
>
>
|
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 | #
# encoding: UTF-8
# api: streamtuner2
# type: class
# title: global config object
# description: reads ~/.config/streamtuner/*.json files
# config:
# { arg: -d, type: str, name: disable[], description: Omit plugin from initialization. }
# { arg: -e, type: str, name: enable[], description: Add channel plugin. }
# { arg: --gtk3, type: boolean, name: gtk3, description: Start with Gtk3 interface. }
# { arg: -D, type: boolean, name: debug, description: Enable debug messages on console }
# { arg: action, type: str *, name: action[], description: CLI interface commands. }
# { arg: -x, type: boolean, name: exit, hidden: 1 }
# version: 2.5
# priority: core
#
# In the main application or module files which need access
# to a global conf.* object, just import this module as follows:
#
# from config import *
#
# Here conf is already an instantiation of the underlying
# ConfigDoct class.
#
# Also provides the logging function __print__, and basic
# plugin handling code: plugin_meta() and module_list(),
# and the relative get_data() alias (files from pyzip/path).
#
from __future__ import print_function
import os
import sys
import json
import gzip
import platform
import re
from compat2and3 import gzip_decode, find_executable |
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 | os.makedirs(self.dir)
# store some configuration list/dict into a file
def save(self, name="settings", data=None, gz=0, nice=0):
name = name + ".json"
if (data is None):
data = dict(self.__dict__) # ANOTHER WORKAROUND: typecast to plain dict(), else json filter_data sees it as object and str()s it
nice = 1
# check for subdir
if (name.find("/") > 0):
subdir = name[0:name.find("/")]
subdir = self.dir + "/" + subdir
if (not os.path.exists(subdir)):
os.mkdir(subdir) |
|
>
>
| 171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 | os.makedirs(self.dir)
# store some configuration list/dict into a file
def save(self, name="settings", data=None, gz=0, nice=0):
name = name + ".json"
if (data is None):
data = vars(self)
if "args" in data:
data.pop("args")
nice = 1
# check for subdir
if (name.find("/") > 0):
subdir = name[0:name.find("/")]
subdir = self.dir + "/" + subdir
if (not os.path.exists(subdir)):
os.mkdir(subdir) |
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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308 | netrc = parser(self.xdg() + "/netrc").hosts
except:
pass
for server in varhosts:
if server in netrc:
return netrc[server]
# Use config: definitions for argv extraction
def init_args(self, ap):
for opt in plugin_meta(frame=0).get("config"):
kwargs = self.argparse_map(opt)
#print kwargs
if kwargs:
args = kwargs["args"]
del kwargs["args"]
ap.add_argument(*args, **kwargs)
return ap.parse_args()
# Transform config: description into quirky ArgumentParser list
def argparse_map(self, 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|\[\]|store|append|const", opt["type"])
naming = re.findall("\[\]", opt["name"])
name = re.findall("(?<!-)\\b\\w+", opt["name"])
nargs = re.findall("\\b\d+\\b|\?|\*", opt["type"]) or [None]
# Populate partially - ArgumentParser is highly fragile with combinations of named params
kwargs = {
"args": args,
"dest": name[0] if not name[0] in args else None,
"action": "append" if "[]" in (naming+typing) else ("store_true" if "bool" in typing else "store"),
"nargs": nargs[0],
"default": opt["value"],
# "type": int if "int" in typing else bool if "bool" in typing else str,
"choices": opt["select"].split("|") if "select" in opt else None,
# "required": "required" in opt,
"help": opt["description"] or "",
}
return dict((k,w) for k,w in kwargs.items() if w is not None)
# Retrieve content from install path or pyzip archive (alias for pkgutil.get_data)
#
def get_data(fn, decode=False, gz=False, file_base="config"):
try:
bin = pkgutil.get_data(file_base, fn) |
>
|
>
|
|
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
|
|
|
|
|
|
>
>
>
>
>
>
>
| 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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 | netrc = parser(self.xdg() + "/netrc").hosts
except:
pass
for server in varhosts:
if server in netrc:
return netrc[server]
# Use config:-style definitions for argv extraction,
# such as: { arg: -D, name: debug, type: bool }
def init_args(self, ap):
for opt in plugin_meta(frame=0).get("config"):
if [kwargs for kwargs in [self.argparse_map(opt)]]:
#print kwargs
ap.add_argument(*kwargs.pop("args"), **kwargs)
return ap.parse_args()
# Copy args fields into conf. dict
def apply_args(self, args):
self.debug = args.debug
if args.exit:
sys.exit(1)
for p_id in (args.disable or []):
self.plugins[p_id] = 0
for p_id in (args.enable or []):
self.plugins[p_id] = 1
# Transform config: description into quirky ArgumentParser args.
#
# · An option entry requires an arg: parameter - unlike regular plugin options:
# { arg: -i, name: input[], type: str, description: input files }
# · Where list elements are indicated by appending `[]` to names, or `*`onto type
# specifiers (alternatively `?`, `+` or a numeric count).
# · Types `str` or `int` and `bool` are recognized (bool with false/true optionals).
# · Entries can also carry a `hidden: 1` or `required: 1` attribute.
# · And `help:` is an alias to `description:`
# · Same for `default:` instead of the normal `value:`
# · And `type: select` utilizes the `select: a|b|c` format as uaual.
# · ArgParsers const=, metavar= flag, or type=file are not aliased here.
#
def argparse_map(self, 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 partially - ArgumentParser has aversions to many parameter combinations
kwargs = {
"args": args,
"dest": name[0] if not name[0] in args else None,
"action": self.sw( {is_arr: "append"}, {is_bool and false_b: "store_false"}, {is_bool: "store_true"}, {1: "store"} ),
"nargs": nargs[0],
"default": opt.get("default") or opt["value"],
"type": self.sw( {is_bool: None}, {"int" in typing: int}, {"bool" in typing: bool}, {1: str} ),
"choices": opt["select"].split("|") if "select" in opt else None,
"required": "required" in opt or None,
"help": opt["description"] if not "hidden" in opt else argparse.SUPPRESS,
}
return {k:w for k,w in kwargs.items() if w is not None}
# Shorthand switch, returns first value for cond==true from list of {cond:val} arguments
def sw(self, *args):
for pair in args:
[(cond,val)] = pair.items()
if cond:
return val
# Retrieve content from install path or pyzip archive (alias for pkgutil.get_data)
#
def get_data(fn, decode=False, gz=False, file_base="config"):
try:
bin = pkgutil.get_data(file_base, fn) |
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446 |
# wrapper for all print statements
def __print__(*args):
if "debug" in conf and conf.debug or args[0] == dbg.ERR:
print(" ".join([str(a) for a in args]))
# error colorization
dbg = type('obj', (object,), {
"ERR": r"[31m[ERR][0m", # red ERROR
"INIT": r"[31m[INIT][0m", # red INIT ERROR
"PROC": r"[32m[PROC][0m", # green PROCESS |
|
| 472
473
474
475
476
477
478
479
480
481
482
483
484
485
486 |
# wrapper for all print statements
def __print__(*args):
if "debug" in conf and conf.debug or args[0] == dbg.ERR:
print(" ".join([str(a) for a in args]), file=sys.stderr)
# error colorization
dbg = type('obj', (object,), {
"ERR": r"[31m[ERR][0m", # red ERROR
"INIT": r"[31m[INIT][0m", # red INIT ERROR
"PROC": r"[32m[PROC][0m", # green PROCESS |