Index: config.py ================================================================== --- config.py +++ config.py @@ -1,9 +1,8 @@ # # encoding: UTF-8 # api: streamtuner2 -# .2 # type: class # title: global config object # description: reads ~/.config/streamtuner/*.json files # config: {type:var, name:z, description:v} # @@ -29,13 +28,14 @@ # export symbols __all__ = ["conf", "__print__", "dbg", "plugin_meta"] - -#-- create a single instance of config object +#-- create a stub instance of config object conf = object() + + #-- global configuration data --------------------------------------------- class ConfigDict(dict): @@ -179,11 +179,11 @@ # decode r = json.load(f) f.close() return r except Exception as e: - print(dbg.ERR, "PSON parsing error (in "+name+")", e) + print(dbg.ERR, "JSON parsing error (in "+name+")", e) # recursive dict update def update(self, with_new_data): for key,value in with_new_data.items(): @@ -210,58 +210,92 @@ # Plugin meta data extraction # # Extremely crude version for Python and streamtuner2 plugin usage. -# Doesn't check top-level comment coherency. -# But supports plugins within python zip archives. -# -rx_zipfn = re.compile(r"""^(.+\.(?:zip|pyz|pyzw|pyzip)(?:\.py)?)/(\w.*)$""") -rx_meta = re.compile(r"""^ {0,4}# *([\w-]+): *(.+(\n *# +(?![\w-]+:).+)*)$""", re.M) # Python comments only -rx_lines = re.compile(r"""\n *# """) # strip multi-line prefixes -rx_config = re.compile(r"""[\{\<](.+?)[\}\>]""") # extract only from JSOL/YAML scheme -rx_fields = re.compile(r"""["']?(\w+)["']?\s*[:=]\s*["']?([^,]+)(? 0: + src, meta["doc"] = src.split("\n\n", 1) + + + # split into dict + for field in rx.keyval.findall(src): + meta[field[0]] = field[1].strip() + meta["config"] = plugin_meta_config(meta.get("config") or "") + return meta - +# unpack config: structures +def plugin_meta_config(str): + config = [] + for entry in rx.config.findall(str): + opt = { "type": None, "name": None, "description": "", "value": None } + for field in rx.options.findall(entry): + opt[field[0]] = (field[1] or field[2] or field[3] or "").strip() + config.append(opt) + return config +# Comment extraction regexps +class rx: + zipfn = re.compile(r""" + ^ (.+ \.(?:zip|pyz|pyzw|pyzip) # zip-wrapping extensions + (?:\.py)? ) /(\w.*) $ + """, re.X) + comment = re.compile(r"""(^ {0,4}#.*\n)+""", re.M) + hash = re.compile(r"""(^ {0,4}# *)""", re.M) + keyval = re.compile(r""" + ^([\w-]+):(.*$(?:\n(?![\w-]+:).+$)*) # plain key:value lines + """, re.M|re.X) + config = re.compile(r""" + [\{\<] (.+?) [\}\>] # JSOL/YAML scheme {...} dicts + """, re.X) + options = re.compile(r""" + ["':$]? (\w+) ["']? # key or ":key" or '$key' + \s* [:=] \s* # "=" or ":" + (?: " ([^"]*) " + | ' ([^']*) ' # "quoted" or 'singl' values + | ([^,]*) # or unquoted literals + ) + """, re.X) # wrapper for all print statements def __print__(*args): - if conf.debug: + if "debug" in conf: print(" ".join([str(a) for a in args])) # error colorization dbg = type('obj', (object,), { @@ -274,12 +308,13 @@ "DATA": r"[DATA]", # cyan DATA "INFO": r"[INFO]", # gray INFO "STAT": r"[STATE]", # gray CONFIG STATE }) + + -#-- actually fill global conf instance + +#-- populate global conf instance conf = ConfigDict() -if conf: - __print__(dbg.PROC, "ConfigDict() initialized") - +__print__(dbg.PROC, "ConfigDict() initialized")