Index: pluginconf/__init__.py ================================================================== --- pluginconf/__init__.py +++ pluginconf/__init__.py @@ -294,19 +294,24 @@ try: #log.debug(f"mod={base} fn={filename}.py") src = get_data(filename=module+sfx, decode=True, file_root=base, warn=False) if src: break - except (IOError, OSError, FileNotFoundError): + except (IOError, OSError, FileNotFoundError, UnicodeDecodeError) as exc: + log.debug("base=%s module=%s sfx=%s, exception=%s", base, module, sfx, exc) continue # plugin_meta_extract() will print a notice later else: log.warning("Found no source candidate for '%s'", module) filename = module # Real filename/path elif filename and os.path.exists(filename): - src = open(filename).read(kwargs.get("max_length", 6144)) + try: + with open(filename, "r", encoding="utf-8") as read: + src = read.read(kwargs.get("max_length", 6144)) + except UnicodeDecodeError as exc: + log.error("read/decode error %s for %s", exc, filename) # Else get source directly from caller elif not src and not filename: module = inspect.getmodule(sys._getframe(frame+1)) # decorator+1 filename = inspect.getsourcefile(module) @@ -348,11 +353,11 @@ | literal | bool | just split comment from doc | | **Returns** | dict | fields | """ # Defaults - meta = { + meta = PluginMeta({ "id": os.path.splitext(os.path.basename(filename or ""))[0], "fn": filename, "api": "python", "type": "module", "category": None, @@ -360,11 +365,11 @@ "version": "0", "title": filename, "description": "no description", "config": [], "doc": "" - } + }) # Extract coherent comment block src = src.replace("\r", "") if not literal: src = rx.header.sub("", src) @@ -382,11 +387,11 @@ # Turn key:value lines into dictionary for field in rx.keyval.findall(src): meta[field[0].replace("-", "_").lower()] = field[1].strip() meta["config"] = plugin_meta_config(meta.get("config") or "") - return PluginMeta(meta) + return meta # Dict/list wrappers # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ class PluginMeta(dict):