Index: action.py ================================================================== --- action.py +++ action.py @@ -62,23 +62,23 @@ "url/youtube": "href", "url/http": "href", "audio/x-pn-realaudio": "ram", "application/json": "json", "application/smil": "smil", - "application/vnd.ms-wpl":"smil", + "application/vnd.ms-wpl": "smil", "audio/x-ms-wax": "asx", "video/x-ms-asf": "asx", - "x-urn/st2-script": "script", # unused + "x-urn/st2-script": "script", # unused "application/x-shockwave-flash": "href", # fallback } # Audio type MIME map mediafmt_t = { "audio/mpeg": "mp3", "audio/ogg": "ogg", - "audio/aac" : "aac", - "audio/aacp" : "aac", + "audio/aac": "aac", + "audio/aacp": "aac", "audio/midi": "midi", "audio/mod": "mod", "audio/it+zip": "mod", "audio/s3+zip": "mod", "audio/xm+zip": "mod", Index: pluginconf.py ================================================================== --- pluginconf.py +++ pluginconf.py @@ -4,11 +4,11 @@ # category: io # title: Plugin configuration # description: Read meta data, pyz/package contents, module locating # version: 0.6 # priority: core -# doc: http://fossil.include-once.org/streamtuner2/wiki/plugin+meta+data +# docs: 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. # For consolidating internal use and external/tool accessibility. @@ -23,11 +23,11 @@ # up meta infos. # This approach avoids in-code values/inspection, externalized meta # descriptors, and any hodgepodge or premature module loading just to # uncover module description fields. # -# plugin_meta() +# plugin_meta() # ‾‾‾‾‾‾‾‾‾‾‾‾‾ # Is the primary function to extract a meta dictionary from files. # It either reads from a given module= name, a literal fn=, or just # src= code, and as fallback inspects the last stack frame= else. # @@ -74,36 +74,38 @@ # Plugin loading thus becomes as simple as __import__("ext.local"). # The attachaed plugin_state config dictionary in most cases can just # list module basenames, if there's only one set to manage. - import sys import os import re import pkgutil import inspect -try: from compat2and3 import gzip_decode -except: from gzip import decompress as gzip_decode # Py3 only +try: + from compat2and3 import gzip_decode +except: + from gzip import decompress as gzip_decode # Py3 only import zipfile import argparse -__all__ = ["get_data", "module_list", "plugin_meta", "dependency", "add_plugin_defaults"] - +__all__ = [ + "get_data", "module_list", "plugin_meta", + "dependency", "add_plugin_defaults" +] # Injectables # ‾‾‾‾‾‾‾‾‾‾‾ -log_ERR = lambda *x:None +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 @@ -119,12 +121,12 @@ if decode: return bin.decode("utf-8", errors='ignore') else: return str(bin) except: - pass#log_ERR("get_data() didn't find:", fn, "in", file_base) - + # log_ERR("get_data() didn't find:", fn, "in", file_base) + pass # Plugin name lookup # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Search through ./plugins/ (and other configured plugin_base @@ -140,12 +142,11 @@ elif os.path.exists(mp): paths.append(mp) # Should list plugins within zips as well as local paths ls = pkgutil.iter_modules(paths + extra_paths) - return [name for loader,name,ispkg in ls] - + return [name for loader, name, ispkg in ls] # Plugin => meta dict # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # This is a trivial wrapper to assemble a complete dictionary @@ -154,11 +155,10 @@ # def all_plugin_meta(): return { name: plugin_meta(module=name) for name in module_list() } - # Plugin meta data extraction # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Can fetch infos from different sources: @@ -176,17 +176,18 @@ def plugin_meta(fn=None, src=None, module=None, frame=1, extra_base=[]): # Try via pkgutil first, # find any plugins.* modules, or main packages if module: - fn = module - for base in plugin_base + extra_base: - try: - src = get_data(fn=fn+".py", decode=True, file_base=base) - if src: break - except: - continue # plugin_meta_extract() will print a notice later + fn = module + for base in plugin_base + extra_base: + try: + src = get_data(fn=fn+".py", decode=True, file_base=base) + if src: + break + except: + continue # plugin_meta_extract() will print a notice later # Real filename/path elif fn and os.path.exists(fn): src = open(fn).read(4096) @@ -209,11 +210,10 @@ if not src: src = "" if not isinstance(src, str): src = src.decode("utf-8", errors='replace') return plugin_meta_extract(src, fn) - # Comment and field extraction logic # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Finds the first comment block. Splits key:value header @@ -243,11 +243,11 @@ if not src: log_ERR("Couldn't read source meta information:", fn) return meta src = src.group(0) src = rx.hash.sub("", src).strip() - + # Split comment block if src.find("\n\n") > 0: src, meta["doc"] = src.split("\n\n", 1) # Turn key:value lines into dictionary @@ -254,11 +254,10 @@ 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 # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Further breaks up the meta['config'] descriptor. @@ -283,35 +282,33 @@ opt[field[0]] = (field[1] or field[2] or field[3] or "").strip() config.append(opt) return config - # Comment extraction regexps # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Pretty crude comment splitting approach. But works # well enough already. Technically a YAML parser would # do better; but is likely overkill. # class rx: comment = re.compile(r"""(^ {0,4}#.*\n)+""", re.M) - hash = re.compile(r"""(^ {0,4}# *)""", re.M) - keyval = re.compile(r""" + 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""" + """, 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) - # ArgumentParser options conversion # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # As variation of in-application config: options, this method converts @@ -349,31 +346,35 @@ 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("(?= newpl.get("version", "0.0"): + pass + else: + return True # Split trivial "pkg, mod >= 1, uikit < 4.0" list def deps(self, dep_str): d = [] for dep in re.split(r"\s*[,;]+\s*", dep_str): # skip deb:pkg-name, rpm:name, bin:name etc. if not len(dep) or dep.find(":") >= 0: continue # find comparison and version num - m = re.search(r"([\w.-]+)\s*([>== 0") + dep += " >= 0" + m = re.search(r"([\w.-]+)\s*([>==": curr >= ver, - "<=": curr <= ver, - "==": curr == ver, - ">": curr > ver, - "<": curr < ver, - "!=": curr != ver, + ">=": curr >= ver, + "<=": curr <= ver, + "==": curr == ver, + ">": curr > ver, + "<": curr < ver, + "!=": curr != ver, } r &= tbl.get(op, True) return r - # Add plugin defaults to conf.* store # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Utility function which applies plugin meta data to a config @@ -468,19 +475,21 @@ # Option defaults, if not yet defined for opt in meta.get("config", []): if "name" in opt and "value" in opt: if opt["name"] not in conf_options: - # typemap "bool" and "int" here - if opt["type"] in ("bool", "boolean"): - val = bool(opt["value"]) - elif opt["type"] in ("int", "integer", "numeric"): - val = int(opt["value"]) - else: - val = str(opt["value"]) - conf_options[opt["name"]] = val + # typemap "bool" and "int" here + if opt["type"] in ("bool", "boolean"): + val = bool(opt["value"]) + elif opt["type"] in ("int", "integer", "numeric"): + val = int(opt["value"]) + else: + val = str(opt["value"]) + conf_options[opt["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") + conf_plugins[module] = meta.get("priority") in ( + "core", "builtin", "always", "default", "standard" + )