Overview
Comment: | pylint fixes for pluginconf.depends |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
3be9f23c5701f8129ae0b491aa3bcd3e |
User & Date: | mario on 2022-10-27 07:44:40 |
Other Links: | manifest | tags |
Context
2022-10-27
| ||
07:47 | update Check check-in: 2568a72ca8 user: mario tags: trunk | |
07:44 | pylint fixes for pluginconf.depends check-in: 3be9f23c57 user: mario tags: trunk | |
05:34 | lots pylint fixes, add documentation check-in: 9c3d295916 user: mario tags: trunk | |
Changes
Modified README.md from [d0883b96e6] to [05362db7a2].
1 2 | Provides meta data extraction and plugin basename lookup. And it’s meant for in-application feature and option management. | | | 1 2 3 4 5 6 7 8 9 10 | Provides meta data extraction and plugin basename lookup. And it’s meant for in-application feature and option management. The [descriptor format](https://fossil.include-once.org/pluginspec/) (*self-contained* atop each script) is basically: # encoding: utf-8 # api: python # type: handler # category: io # title: Plugin configuration |
︙ | ︙ | |||
54 55 56 57 58 59 60 | module_base = "pluginconf" # or any top-level app module Which declares module and plugin basenames, which get used for lookups by just module= names in e.g. `module_list()`. (Works for literal setups and within PYZ bundles). This is unnecessary for plain `plugin_meta(fn=)` extraction. | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | module_base = "pluginconf" # or any top-level app module Which declares module and plugin basenames, which get used for lookups by just module= names in e.g. `module_list()`. (Works for literal setups and within PYZ bundles). This is unnecessary for plain `plugin_meta(fn=)` extraction. #### [plugin_meta](https://fossil.include-once.org/pluginspec/doc/trunk/html/index.html)( module= | filename= | src= | frame= ) Returns a meta data dictionary for the given module name, file, source code, or caller frame: { "title": "Compound★", "description": "...", "version": "0.1", |
︙ | ︙ | |||
180 181 182 183 184 185 186 | requires = ["flit_core", "pluginconf"] build-backend = "pluginconf.flit" [project] name = "projectname" It can be invoked via `python -m pluginconf.flit build` or even | | | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | requires = ["flit_core", "pluginconf"] build-backend = "pluginconf.flit" [project] name = "projectname" It can be invoked via `python -m pluginconf.flit build` or even `flit-pluginconf build`. Field mapping isn't very robust yet. ## other modules * `pluginconf.depends` provides `Check` for .valid() and .depends() probing * argparse_map() might also end up in a separate module. #### Caveats * It’s mostly just an excerpt from streamtuner2. * Might need customization prior use. |
︙ | ︙ |
Modified pluginconf/depends.py from [6e210a4c05] to [f49268879d].
︙ | ︙ | |||
10 11 12 13 14 15 16 | # license: PD # priority: optional # # This is a rather basic depends: checker, mostly for local and # installable modules. It's largely built around streamtuner2 # requirements, and should be customized. # | | | > > | < < < | | 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 38 39 40 41 42 43 44 45 46 47 48 49 50 | # license: PD # priority: optional # # This is a rather basic depends: checker, mostly for local and # installable modules. It's largely built around streamtuner2 # requirements, and should be customized. # # Check().depends()/.valid() # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # Probes a new plugins` depends: list against installed base modules. # Utilizes each version: fields and allows for virtual modules, or # alternatives and honors alias: names. # """ Dependency validation and consistency checker for updates """ import sys import re #import zipfile import logging import pluginconf try: from distutils.spawn import find_executable except ImportError: try: from compat2and3 import find_executable except ImportError: find_executable = lambda name: False # Minimal depends: probing # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ class Check(object): """ Now this definitely requires customization. Each plugin can carry a list of (soft-) dependency names. \# depends: config, appcore >= 2.0, bin:wkhtmltoimage, python < 3.5 Here only in-application modules are honored, system references |
︙ | ︙ | |||
65 66 67 68 69 70 71 | api : list allowed api: identifiers for .valid() stream checks log : logging warning handler have : dict accumulated list of existing/virtual plugins """ | | | | | > > | > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | api : list allowed api: identifiers for .valid() stream checks log : logging warning handler have : dict accumulated list of existing/virtual plugins """ # supported APIs api = ["python", "streamtuner2"] # debugging log = logging.getLogger("pluginconf.dependency") # ignore bin:… or python:… package in depends system_deps = False def __init__(self, add={}, core=["st2", "uikit", "config", "action"]): """ Prepare list of known plugins and versions in self.have={} Parameters ---------- add : dict name to pmd list of existing/core/virtual plugins (can define versions or own dependencies) core : list name list of virtual plugins |
︙ | ︙ | |||
110 111 112 113 114 115 116 | # aliases for name, meta in self.have.copy().items(): if meta.get("alias"): for alias in re.split(r"\s*[,;]\s*", meta["alias"]): self.have[alias] = self.have[name] | < < > > | > > | | | > < | < > > > > > | | | | > | < | | | | < | > | < > < | > > | | | > > | | > | | > < | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | # aliases for name, meta in self.have.copy().items(): if meta.get("alias"): for alias in re.split(r"\s*[,;]\s*", meta["alias"]): self.have[alias] = self.have[name] def valid(self, new_plugin): """ Plugin pre-screening from online repository stream. Fields are $name, $file, $dist, api, id, depends, etc Exclude installed or for newer-version presence. """ if not "$name" in new_plugin: self.log.warning(".valid() checks online plugin lists, requires $name") name = new_plugin.get("$name", "__invalid") have_ver = self.have.get(name, {}).get("version", "0") if name.find("__") == 0: self.log.debug("wrong/no id") elif new_plugin.get("api") not in self.api: self.log.debug("not in allowed APIs") elif {new_plugin.get("status"), new_plugin.get("priority")} & {"obsolete", "broken"}: self.log.debug("wrong status (obsolete/broken)") elif have_ver >= new_plugin.get("version", "0.0"): self.log.debug("newer version already installed") else: return True return False def depends(self, plugin): """ Verify depends: and breaks: against existing plugins/modules """ result = True if plugin.get("depends"): result &= self.and_or(self.split(plugin["depends"]), self.have) if plugin.get("breaks"): result &= self.neither(self.split(plugin["breaks"]), self.have) self.log.debug("plugin '%s' matching requirements: %i", plugin["id"], result) return result def split(self, dep_str): """ Split trivial "pkg | alt, mod>=1, uikit<4.0" string into nested list [ [alt, alt], [dep], [dep] ]; with each entry comprised of (name, operator, version). """ dep_cmp = [] for alt_str in re.split(r"\s*[,;]+\s*", dep_str): alt_cmp = [] # split alternatives | for part in re.split(r"\s*\|+\s*", alt_str): # skip deb:pkg-name, rpm:name, bin:name etc. if not part: continue if part.find(":") >= 0: self.have[part] = {"version": self.module_test(*part.split(":"))} # find comparison and version num part += " >= 0" match = re.search(r"([\w.:-]+)\s*\(?\s*([>=<!~]+)\s*([\d.]+([-~.]\w+)*)", part) if match and match.group(2): alt_cmp.append([match.group(i) for i in (1, 2, 3)]) if alt_cmp: dep_cmp.append(alt_cmp) return dep_cmp def cmp(self, name_op_ver, have, absent=True): """ Single comparison """ name, operator, ver = name_op_ver # absent=True is the relaxed check, will ignore unknown plugins # set absent=False or None for strict check (as in breaks: rule e.g.) if not have.get(name, {}).get("version"): return absent # curr = installed version curr = have[name]["version"] tbl = { ">=": curr >= ver, "<=": curr <= ver, "==": curr == ver, ">": curr > ver, "<": curr < ver, "!=": curr != ver, } result = tbl.get(operator, True) self.log.debug("VERSION_COMPARE: %s → (%s %s %s) == %s", name, curr, operator, ver, result) return result def and_or(self, deps, have, inner_true=True): """ Compare nested structure of [[dep],[alt,alt]] """ #print deps return not False in [ inner_true in [self.cmp(d, have) for d in alternatives] for alternatives in deps ] def neither(self, deps, have): """ Breaks/Conflicts: check [[or],[or]] """ return not True in [ self.cmp(d, have, absent=None) for cnd in deps for d in cnd ] def module_test(self, urn, name): """ Probes "bin:name" or "python:name" dependency URNs """ if not self.system_deps: return "1" if "_" + urn in dir(self): if bool(getattr(self, "_" + urn)(name)): return "1" return "-1" # basically a negative version -v1 @staticmethod def _bin(name): """ `bin:name` lookup """ return find_executable(name) @staticmethod def _python(name): """ `python:module` test """ return __import__("imp").find_module(name) is not None |
Modified test/depends.py from [10d2104189] to [3267defa9d].
︙ | ︙ | |||
13 14 15 16 17 18 19 | import pluginconf.depends import logging logging.basicConfig(level=logging.DEBUG) @pytest.fixture def check(): | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import pluginconf.depends import logging logging.basicConfig(level=logging.DEBUG) @pytest.fixture def check(): deps = pluginconf.depends.Check( add={"core": 2.555, "config": 2.0, "existing": 0.1}, core=["IMPLICIT"], ) deps.api = ["python", "foobar"] return deps @pytest.fixture |
︙ | ︙ |