diff --git a/tools/python/jwutils/ArgsContainer.py b/tools/python/jwutils/ArgsContainer.py index 3adcdb2..7db211f 100644 --- a/tools/python/jwutils/ArgsContainer.py +++ b/tools/python/jwutils/ArgsContainer.py @@ -8,10 +8,10 @@ from jwutils.log import * class ArgsContainer: # export - __args = OrderedDict() - __kwargs = OrderedDict() - __values = {} - __specified_args = list() + __args: OrderedDict[str, str] = OrderedDict() + __kwargs: OrderedDict[str, str] = OrderedDict() + __values: dict[str, str] = {} + __specified_args: list[str] = list() def __getattr__(self, name): values = self.__values @@ -47,12 +47,10 @@ class ArgsContainer: # export def keys(self): return self.__args.keys() - @property - def args(self, name): + def args(self, name) -> str: return self.__args[name] - @property - def kwargs(self, name): + def kwargs(self, name) -> str: return self.__kwargs[name] def dump(self, prio, *args, **kwargs): diff --git a/tools/python/jwutils/Cmd.py b/tools/python/jwutils/Cmd.py index c5f879e..79ce341 100644 --- a/tools/python/jwutils/Cmd.py +++ b/tools/python/jwutils/Cmd.py @@ -48,7 +48,7 @@ class Cmd(abc.ABC): # export return self.child_classes.append(cmd) - # To be overriden by derived class in case the command does take arguments. + # To be overridden by derived class in case the command does take arguments. # Will be called from App base class constructor and set up the parser hierarchy def add_arguments(self, parser: ArgumentParser) -> None: pass diff --git a/tools/python/jwutils/Cmds.py b/tools/python/jwutils/Cmds.py index 7cf7f19..0540157 100644 --- a/tools/python/jwutils/Cmds.py +++ b/tools/python/jwutils/Cmds.py @@ -90,6 +90,10 @@ class Cmds: # export slog(DEBUG, f'Adding top-level command {cmd} to parser') self.__add_cmd_to_parser(cmd, subparsers) + # Run all sub-commands. Overwrite if you want to do anything before or after + async def _run(self, argv=None): + return await self.args.func(self.args) + async def __run(self, argv=None): argcomplete.autocomplete(self.__parser) self.args = self.__parser.parse_args(args=argv) @@ -115,7 +119,7 @@ class Cmds: # export pr.enable() try: - ret = await self.args.func(self.args) + ret = await self._run(self.args) except Exception as e: if hasattr(e, 'message'): slog(ERR, e.message) diff --git a/tools/python/jwutils/Config.py b/tools/python/jwutils/Config.py index f2ac485..e55296a 100644 --- a/tools/python/jwutils/Config.py +++ b/tools/python/jwutils/Config.py @@ -103,7 +103,7 @@ class Config(): # export self.__conf.dump(DEBUG, "superposed configuration") - def __getitem__(self, key: str) -> Optional[str]: + def __getitem__(self, key: str) -> str: ret = self.get(key) if ret is None: raise KeyError(key) diff --git a/tools/python/jwutils/algo/ShuntingYard.py b/tools/python/jwutils/algo/ShuntingYard.py index caaef18..b197eee 100644 --- a/tools/python/jwutils/algo/ShuntingYard.py +++ b/tools/python/jwutils/algo/ShuntingYard.py @@ -5,12 +5,6 @@ from collections import namedtuple from ..log import * -# --- python 2 / 3 compatibility stuff -try: - basestring # type: ignore -except NameError: - basestring = str - L, R = 'Left Right'.split() ARG, KEYW, QUOTED, LPAREN, RPAREN = 'arg kw quoted ( )'.split() @@ -252,7 +246,7 @@ class ShuntingYard(object): # export return vals.pop() def eval(self, infix): - if not isinstance(infix, basestring): + if not isinstance(infix, str): return infix postfix = self.infix_to_postfix(infix) self.debug(f'"{infix}" --> {postfix}') diff --git a/tools/python/jwutils/asyncio/__init__.py b/tools/python/jwutils/asyncio/__init__.py index e94d4d7..632935f 100644 --- a/tools/python/jwutils/asyncio/__init__.py +++ b/tools/python/jwutils/asyncio/__init__.py @@ -1,5 +1,6 @@ -# -*- coding: utf-8 -*- - # >> -------------------------- generated by python-tools.sh >> +from pkgutil import extend_path +from typing import Iterable +__path__ = extend_path(__path__, __name__) # type: ignore from jwutils.asyncio.Process import Process # << -------------------------- generated by python-tools.sh << diff --git a/tools/python/jwutils/auth/Auth.py b/tools/python/jwutils/auth/Auth.py index 01106aa..714fd92 100644 --- a/tools/python/jwutils/auth/Auth.py +++ b/tools/python/jwutils/auth/Auth.py @@ -74,11 +74,12 @@ class Auth(abc.ABC): # export @classmethod def load(cls, conf: Config, tp: str='') -> Self: if tp == '': - tp = conf.get('type') - if tp is None: + val = conf.get('type') + if val is None: msg = f'No type specified in auth configuration' conf.dump(ERR, msg) raise Exception(msg) + tp = val return load_object(f'jwutils.auth.{tp}.Auth', Auth, 'Auth', conf) def __init__(self, conf: Config): @@ -112,7 +113,7 @@ class Auth(abc.ABC): # export return self._user(name) @abc.abstractmethod - def _users(self) -> list[User]: + def _users(self) -> dict[str, User]: raise NotImplementedError def _user_by_email(self, email: str) -> User: @@ -128,7 +129,7 @@ class Auth(abc.ABC): # export return self._user_by_email(email) @property - def users(self) -> list[User]: + def users(self) -> dict[str, User]: return self._users() @abc.abstractmethod diff --git a/tools/python/jwutils/auth/dummy/Auth.py b/tools/python/jwutils/auth/dummy/Auth.py index eb31744..4b6b9c0 100644 --- a/tools/python/jwutils/auth/dummy/Auth.py +++ b/tools/python/jwutils/auth/dummy/Auth.py @@ -26,7 +26,7 @@ class User(UserBase): # export self.__conf = conf self.__auth = auth self.__groups: Optional[list[GroupBase]] = None - self.__email = conf.get('email') + self.__email: str = conf['email'] @property def conf(self): @@ -51,14 +51,15 @@ class Auth(AuthBase): # export def __init__(self, conf: Config): super().__init__(conf) - self.___users: Optional[dict[str, User]] = None + self.___users: Optional[dict[str, UserBase]] = None self.__groups = None - self.__current_user: User|None = None + self.__current_user: UserBase|None = None + self.__user_by_email: Optional[dict[str, UserBase]] = None @property - def __users(self) -> User: + def __users(self) -> dict[str, UserBase]: if self.___users is None: - ret: dict[str, User] = {} + ret: dict[str, UserBase] = {} for name in self.conf.entries('user'): conf = self.conf.branch('user.' + name) ret[name] = User(self, name, conf) @@ -69,24 +70,24 @@ class Auth(AuthBase): # export slog(WARNING, f'Returning False for {access_type} access to resource {what} by {who}') return False - def _user(self, name) -> User: + def _user(self, name) -> UserBase: return self.__users[name] - def _users(self) -> list[User]: + def _users(self) -> dict[str, UserBase]: return self.__users - def _current_user(self) -> User: + def _current_user(self) -> UserBase: if self.__current_user is None: self.__current_user = self._user(self.conf['current_user']) return self.__current_user - def _user_by_email(self, email: str) -> User: + def _user_by_email(self, email: str) -> UserBase: if self.__user_by_email is None: - ret: dict[str, User] = dict() + ret: dict[str, UserBase] = dict() for user in self.__users.values(): ret[user.email] = user self.__user_by_email = ret return self.__user_by_email[email] def _projects(self, name, flags: ProjectFlags) -> list[str]: - return None + return [] diff --git a/tools/python/jwutils/auth/ldap/Auth.py b/tools/python/jwutils/auth/ldap/Auth.py index a714642..29ebf83 100644 --- a/tools/python/jwutils/auth/ldap/Auth.py +++ b/tools/python/jwutils/auth/ldap/Auth.py @@ -54,7 +54,7 @@ class Auth(AuthBase): # export def __init__(self, conf: Config): super().__init__(conf) - self.___users: Optional[dict[str, User]] = None + self.___users: Optional[dict[str, UserBase]] = None self.___user_by_email: Optional[dict[str, User]] = None self.__groups = None self.__current_user: User|None = None @@ -66,9 +66,9 @@ class Auth(AuthBase): # export return bind(self.conf) @property - def __users(self) -> User: + def __users(self) -> dict[str, UserBase]: if self.___users is None: - ret: dict[str, User] = {} + ret: dict[str, UserBase] = {} ret_by_email: dict[str, User] = {} for res in self.__conn.find( self.__user_base_dn, @@ -101,40 +101,40 @@ class Auth(AuthBase): # export slog(WARNING, f'Exception {e}') raise continue - for user in self.__dummy.users.values(): - ret[user.name] = user + for dummy_user in self.__dummy.users.values(): + ret[dummy_user.name] = dummy_user self.___users = ret self.___user_by_email = ret_by_email return self.___users @property - def __user_by_email(self) -> User: + def __user_by_email(self) -> dict[str, UserBase]: if self.___user_by_email is None: self.__users - return self.___user_by_email + return self.___user_by_email # type: ignore # We are sure that ___user_by_email is not None at this point def _access(self, what: str, access_type: Optional[Access], who: User|GroupBase|None) -> bool: # type: ignore slog(WARNING, f'Returning False for {access_type} access to resource {what} by {who}') return False - def _user(self, name) -> User: + def _user(self, name) -> UserBase: try: return self.__users[name] except: slog(ERR, f'No such user: "{name}"') raise - def _user_by_email(self, email: str) -> User: + def _user_by_email(self, email: str) -> UserBase: return self.__user_by_email[email] def _current_user(self) -> User: raise NotImplementedError - def _users(self) -> list[User]: + def _users(self) -> dict[str, UserBase]: return self.__users def _projects(self, name, flags: ProjectFlags) -> list[str]: if flags & ProjectFlags.Contributing: # TODO: Ask LDAP - pass - return None + slog(WARNING, f'Querying LDAP for projects a user contributes to is not implemented, ignoring') + return [] diff --git a/tools/python/jwutils/graph/yed/MapAttr2Shape.py b/tools/python/jwutils/graph/yed/MapAttr2Shape.py index 1962322..9749bdf 100644 --- a/tools/python/jwutils/graph/yed/MapAttr2Shape.py +++ b/tools/python/jwutils/graph/yed/MapAttr2Shape.py @@ -29,7 +29,7 @@ class MapAttr2Shape: # export for name, url in self.__ns.items(): ET.register_namespace(name, url) - def __keys(self, root): + def __keys(self, root) -> dict[str, str]: ret: dict[str, str] = {} for el in root.findall('key', self.__ns): attr_name = el.get('attr.name') @@ -44,7 +44,7 @@ class MapAttr2Shape: # export return None return data.text - def __attribs(self, node, keys): + def __attribs(self, node, keys) -> dict[str, str]: ret: dict[str, str] = {} for name, key in keys.items(): val = self.__value(node, key) @@ -93,13 +93,13 @@ class MapAttr2Shape: # export values[key] = default continue try: - if isinstance(str, mapping): + if isinstance(mapping, str): values[key] = mapping continue + mapped = mapping(self.__attribs(node, keys)) + values[key] = mapped or default except: pass - mapped = mapping(self.__attribs(node, keys)) - values[key] = mapped or default color = values['color'] text = values['text'] diff --git a/tools/python/jwutils/ldap.py b/tools/python/jwutils/ldap.py index 6728644..f84ab2f 100644 --- a/tools/python/jwutils/ldap.py +++ b/tools/python/jwutils/ldap.py @@ -83,7 +83,7 @@ class Connection: # export raise Exception(f'Failed to bind to {c.ldap_uri} with dn {c.bind_dn} ({e})') self.__ldap = ret self.__backtrace = backtrace - self.__object_classes: dict[str, ObjectClass]|None = None + self.__object_classes_by_oid: dict[str, ObjectClass]|None = None self.__object_class_tree: nx.Graph|None = None self.__object_classes_by_name: dict[str, ObjectClass]|None = None @@ -93,12 +93,10 @@ class Connection: # export def add(self, attrs: dict[str, bytes], dn: str|None=None): if dn is None: - dn = attrs.get('dn') - if dn is None: + if not 'dn' in attrs: raise Exception('No DN to add an LDAP entry to') - else: - attrs = copy.deepcopy(attrs) - del attrs['dn'] + attrs = copy.deepcopy(attrs) + del attrs['dn'] try: slog(INFO, f'LDAP: Add [{dn}] -> {attrs}') self.__ldap.add_s(dn, ldap.modlist.addModlist(attrs)) @@ -175,14 +173,14 @@ class Connection: # export assert_not_empty=False, ): - def __walk_cb_find(conn: Connection, entry, context): + def __walk_cb_find(conn: Connection, entry: Any, context: Any): result.append(entry) def __search(): return f'{base} -> "{filterstr}"' try: - result = [] + result: list[Any] = [] self.walk(__walk_cb_find, base, scope=scope, filterstr=filterstr, attrlist=attrlist) except Exception as e: slog(ERR, f'Failed search {__search()} ({e})') @@ -194,9 +192,9 @@ class Connection: # export return result @property - def object_classes(self) -> list[ObjectClass]: + def object_classes(self) -> dict[str, ObjectClass]: #def object_classes(self): - if self.__object_classes is None: + if self.__object_classes_by_oid is None: res = self.find(base='', scope=ldap.SCOPE_BASE, filterstr='(objectClass=*)', attrlist=['subschemaSubentry']) dn = res[0][1]['subschemaSubentry'][0].decode('utf-8') # Usually yields cn=Subschema res = self.find(base=dn, scope=ldap.SCOPE_BASE, filterstr='(objectClass=*)', attrlist=['*', '+']) @@ -204,13 +202,13 @@ class Connection: # export subschema_subentry = ldap.cidict.cidict(subschema_entry[1]) subschema = ldap.schema.SubSchema(subschema_subentry) object_class_oids = subschema.listall(ObjectClass) - self.__object_classes = { + self.__object_classes_by_oid = { oid: subschema.get_obj(ObjectClass, oid) for oid in object_class_oids } - return self.__object_classes + return self.__object_classes_by_oid @property - def object_class_by_name(self): + def object_class_by_name(self) -> dict[str, ObjectClass]: if self.__object_classes_by_name is None: ret: dict[str, ObjectClass] = {} self.__object_classes_by_name = ret @@ -230,7 +228,7 @@ class Connection: # export def object_class_path(self, leaf: str|ObjectClass): def cb(oc, context): ret.append(oc) - ret = [] + ret: list[str] = [] self.__oc_recurse_to_top(leaf, cb, None) return reversed(ret) diff --git a/tools/python/jwutils/log.py b/tools/python/jwutils/log.py index cf7e600..30e5be2 100644 --- a/tools/python/jwutils/log.py +++ b/tools/python/jwutils/log.py @@ -98,7 +98,7 @@ class Stream: self.stream = stream self.flags = flags -_streams: dict[int, io.IOBase] = dict() +_streams: dict[int, Stream] = dict() _stream_descriptors = [reversed(range(1, 16))] def add_capture_stream(stream, flags=0x0): @@ -120,7 +120,7 @@ def log_level(s: Optional[str]=None) -> int: # export return _level return parse_log_prio_str(s) -def get_caller_pos(up: int = 1, kwargs: Optional[dict[str, Any]] = None) -> Tuple[str, int]: +def get_caller_pos(up: int = 1, kwargs: Optional[dict[str, Any]] = None) -> Tuple[str, str, int]: if kwargs and 'caller' in kwargs: r = kwargs['caller'] del kwargs['caller'] @@ -261,10 +261,10 @@ def set_level(level_: str) -> None: # export return _level = level_ -def set_flags(flags: str|None) -> None: # export +def set_flags(flags: str|None) -> str: # export global _flags ret = ','.join(_flags) - if _flags is not None: + if flags is not None: _flags = set(flags.split(',')) return ret diff --git a/tools/python/jwutils/stree/StringTree.py b/tools/python/jwutils/stree/StringTree.py index eea13ad..de986a2 100644 --- a/tools/python/jwutils/stree/StringTree.py +++ b/tools/python/jwutils/stree/StringTree.py @@ -287,7 +287,7 @@ class StringTree: # export case _: raise NotImplementedError(f'Matcher {match} is not yet implemented') - ret = [] + ret: list[StringTree] = [] if depth_first: __children()