Check-in [1eea3140f8]
Overview
Comment: | Move argv initialization to conf.apply_args(). Document config: format for argparse conversion. Enable file=sys.stderr for __print__/debug messages. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
1eea3140f86b5cfbbc17719027dc5793 |
User & Date: | mario on 2015-04-07 05:51:36 |
Other Links: | manifest | tags |
Context
2015-04-07
| ||
05:53 | Fix a few CLI bugs (doesn't work yet with dynamic module list), stub_parent() implementations for non-GUI mode should be merged. check-in: a7c3f7336a user: mario tags: trunk | |
05:51 | Move argv initialization to conf.apply_args(). Document config: format for argparse conversion. Enable file=sys.stderr for __print__/debug messages. check-in: 1eea3140f8 user: mario tags: trunk | |
2015-04-06
| ||
18:55 | Add workaround for ArgumentParser, which tries to map config: descriptors onto AP.add_argument(*yikes) params. check-in: 24a5fe69a1 user: mario tags: trunk | |
Changes
Makefile became executable with contents [d3f05bad3b].
︙ | ︙ |
Modified config.py from [af23ce772a] to [ca9c88608a].
1 2 3 4 5 6 7 | # # encoding: UTF-8 # api: streamtuner2 # type: class # title: global config object # description: reads ~/.config/streamtuner/*.json files # config: | | > | | | | > > | | 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 |
︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 95 96 | # store defaults in file else: self.save("settings") self.firstrun = 1 # add argv self.args = self.init_args(argparse.ArgumentParser()) # some defaults def defaults(self): self.play = { "audio/mpeg": self.find_player(), "audio/ogg": self.find_player(), | > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | # store defaults in file else: self.save("settings") self.firstrun = 1 # add argv self.args = self.init_args(argparse.ArgumentParser()) self.apply_args(self.args) # some defaults def defaults(self): self.play = { "audio/mpeg": self.find_player(), "audio/ogg": self.find_player(), |
︙ | ︙ | |||
167 168 169 170 171 172 173 | 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): | | > > | 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 | netrc = parser(self.xdg() + "/netrc").hosts except: pass for server in varhosts: if server in netrc: return netrc[server] | > | > | | < < < | > > > > > > > > > > > > | > > > > > > > > > > > > | | > > > > | | | | | | | > > > > > > > | 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 | # wrapper for all print statements def __print__(*args): if "debug" in conf and conf.debug or args[0] == dbg.ERR: | | | 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 |
︙ | ︙ |
Modified st2.py from [2915a6cb3f] to [cbc6a632be].
︙ | ︙ | |||
487 488 489 490 491 492 493 | # startup procedure def main(): | < < < < < < < < < | | | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | # startup procedure def main(): # graphical if not len(conf.args.action): # prepare for threading in Gtk+ callbacks gobject.threads_init() # prepare main window main = StreamTunerTwo() # first invocation if (conf.get("firstrun")): main.configwin.open(None) del conf.firstrun # run gtk.main() __print__(dbg.PROC, r"[31m gtk_main_quit [0m") # invoke command-line interface else: import cli cli.StreamTunerCLI(conf.args.action) # run if __name__ == "__main__": main() |