Fix errors reported by mypy

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2025-10-13 12:45:51 +02:00
commit bfd0544ff8
13 changed files with 68 additions and 71 deletions

View file

@ -8,10 +8,10 @@ from jwutils.log import *
class ArgsContainer: # export class ArgsContainer: # export
__args = OrderedDict() __args: OrderedDict[str, str] = OrderedDict()
__kwargs = OrderedDict() __kwargs: OrderedDict[str, str] = OrderedDict()
__values = {} __values: dict[str, str] = {}
__specified_args = list() __specified_args: list[str] = list()
def __getattr__(self, name): def __getattr__(self, name):
values = self.__values values = self.__values
@ -47,12 +47,10 @@ class ArgsContainer: # export
def keys(self): def keys(self):
return self.__args.keys() return self.__args.keys()
@property def args(self, name) -> str:
def args(self, name):
return self.__args[name] return self.__args[name]
@property def kwargs(self, name) -> str:
def kwargs(self, name):
return self.__kwargs[name] return self.__kwargs[name]
def dump(self, prio, *args, **kwargs): def dump(self, prio, *args, **kwargs):

View file

@ -48,7 +48,7 @@ class Cmd(abc.ABC): # export
return return
self.child_classes.append(cmd) 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 # Will be called from App base class constructor and set up the parser hierarchy
def add_arguments(self, parser: ArgumentParser) -> None: def add_arguments(self, parser: ArgumentParser) -> None:
pass pass

View file

@ -90,6 +90,10 @@ class Cmds: # export
slog(DEBUG, f'Adding top-level command {cmd} to parser') slog(DEBUG, f'Adding top-level command {cmd} to parser')
self.__add_cmd_to_parser(cmd, subparsers) 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): async def __run(self, argv=None):
argcomplete.autocomplete(self.__parser) argcomplete.autocomplete(self.__parser)
self.args = self.__parser.parse_args(args=argv) self.args = self.__parser.parse_args(args=argv)
@ -115,7 +119,7 @@ class Cmds: # export
pr.enable() pr.enable()
try: try:
ret = await self.args.func(self.args) ret = await self._run(self.args)
except Exception as e: except Exception as e:
if hasattr(e, 'message'): if hasattr(e, 'message'):
slog(ERR, e.message) slog(ERR, e.message)

View file

@ -103,7 +103,7 @@ class Config(): # export
self.__conf.dump(DEBUG, "superposed configuration") self.__conf.dump(DEBUG, "superposed configuration")
def __getitem__(self, key: str) -> Optional[str]: def __getitem__(self, key: str) -> str:
ret = self.get(key) ret = self.get(key)
if ret is None: if ret is None:
raise KeyError(key) raise KeyError(key)

View file

@ -5,12 +5,6 @@ from collections import namedtuple
from ..log import * from ..log import *
# --- python 2 / 3 compatibility stuff
try:
basestring # type: ignore
except NameError:
basestring = str
L, R = 'Left Right'.split() L, R = 'Left Right'.split()
ARG, KEYW, QUOTED, LPAREN, RPAREN = 'arg kw quoted ( )'.split() ARG, KEYW, QUOTED, LPAREN, RPAREN = 'arg kw quoted ( )'.split()
@ -252,7 +246,7 @@ class ShuntingYard(object): # export
return vals.pop() return vals.pop()
def eval(self, infix): def eval(self, infix):
if not isinstance(infix, basestring): if not isinstance(infix, str):
return infix return infix
postfix = self.infix_to_postfix(infix) postfix = self.infix_to_postfix(infix)
self.debug(f'"{infix}" --> {postfix}') self.debug(f'"{infix}" --> {postfix}')

View file

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# >> -------------------------- generated by python-tools.sh >> # >> -------------------------- 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 from jwutils.asyncio.Process import Process
# << -------------------------- generated by python-tools.sh << # << -------------------------- generated by python-tools.sh <<

View file

@ -74,11 +74,12 @@ class Auth(abc.ABC): # export
@classmethod @classmethod
def load(cls, conf: Config, tp: str='') -> Self: def load(cls, conf: Config, tp: str='') -> Self:
if tp == '': if tp == '':
tp = conf.get('type') val = conf.get('type')
if tp is None: if val is None:
msg = f'No type specified in auth configuration' msg = f'No type specified in auth configuration'
conf.dump(ERR, msg) conf.dump(ERR, msg)
raise Exception(msg) raise Exception(msg)
tp = val
return load_object(f'jwutils.auth.{tp}.Auth', Auth, 'Auth', conf) return load_object(f'jwutils.auth.{tp}.Auth', Auth, 'Auth', conf)
def __init__(self, conf: Config): def __init__(self, conf: Config):
@ -112,7 +113,7 @@ class Auth(abc.ABC): # export
return self._user(name) return self._user(name)
@abc.abstractmethod @abc.abstractmethod
def _users(self) -> list[User]: def _users(self) -> dict[str, User]:
raise NotImplementedError raise NotImplementedError
def _user_by_email(self, email: str) -> User: def _user_by_email(self, email: str) -> User:
@ -128,7 +129,7 @@ class Auth(abc.ABC): # export
return self._user_by_email(email) return self._user_by_email(email)
@property @property
def users(self) -> list[User]: def users(self) -> dict[str, User]:
return self._users() return self._users()
@abc.abstractmethod @abc.abstractmethod

View file

@ -26,7 +26,7 @@ class User(UserBase): # export
self.__conf = conf self.__conf = conf
self.__auth = auth self.__auth = auth
self.__groups: Optional[list[GroupBase]] = None self.__groups: Optional[list[GroupBase]] = None
self.__email = conf.get('email') self.__email: str = conf['email']
@property @property
def conf(self): def conf(self):
@ -51,14 +51,15 @@ class Auth(AuthBase): # export
def __init__(self, conf: Config): def __init__(self, conf: Config):
super().__init__(conf) super().__init__(conf)
self.___users: Optional[dict[str, User]] = None self.___users: Optional[dict[str, UserBase]] = None
self.__groups = 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 @property
def __users(self) -> User: def __users(self) -> dict[str, UserBase]:
if self.___users is None: if self.___users is None:
ret: dict[str, User] = {} ret: dict[str, UserBase] = {}
for name in self.conf.entries('user'): for name in self.conf.entries('user'):
conf = self.conf.branch('user.' + name) conf = self.conf.branch('user.' + name)
ret[name] = User(self, name, conf) 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}') slog(WARNING, f'Returning False for {access_type} access to resource {what} by {who}')
return False return False
def _user(self, name) -> User: def _user(self, name) -> UserBase:
return self.__users[name] return self.__users[name]
def _users(self) -> list[User]: def _users(self) -> dict[str, UserBase]:
return self.__users return self.__users
def _current_user(self) -> User: def _current_user(self) -> UserBase:
if self.__current_user is None: if self.__current_user is None:
self.__current_user = self._user(self.conf['current_user']) self.__current_user = self._user(self.conf['current_user'])
return self.__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: if self.__user_by_email is None:
ret: dict[str, User] = dict() ret: dict[str, UserBase] = dict()
for user in self.__users.values(): for user in self.__users.values():
ret[user.email] = user ret[user.email] = user
self.__user_by_email = ret self.__user_by_email = ret
return self.__user_by_email[email] return self.__user_by_email[email]
def _projects(self, name, flags: ProjectFlags) -> list[str]: def _projects(self, name, flags: ProjectFlags) -> list[str]:
return None return []

View file

@ -54,7 +54,7 @@ class Auth(AuthBase): # export
def __init__(self, conf: Config): def __init__(self, conf: Config):
super().__init__(conf) 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.___user_by_email: Optional[dict[str, User]] = None
self.__groups = None self.__groups = None
self.__current_user: User|None = None self.__current_user: User|None = None
@ -66,9 +66,9 @@ class Auth(AuthBase): # export
return bind(self.conf) return bind(self.conf)
@property @property
def __users(self) -> User: def __users(self) -> dict[str, UserBase]:
if self.___users is None: if self.___users is None:
ret: dict[str, User] = {} ret: dict[str, UserBase] = {}
ret_by_email: dict[str, User] = {} ret_by_email: dict[str, User] = {}
for res in self.__conn.find( for res in self.__conn.find(
self.__user_base_dn, self.__user_base_dn,
@ -101,40 +101,40 @@ class Auth(AuthBase): # export
slog(WARNING, f'Exception {e}') slog(WARNING, f'Exception {e}')
raise raise
continue continue
for user in self.__dummy.users.values(): for dummy_user in self.__dummy.users.values():
ret[user.name] = user ret[dummy_user.name] = dummy_user
self.___users = ret self.___users = ret
self.___user_by_email = ret_by_email self.___user_by_email = ret_by_email
return self.___users return self.___users
@property @property
def __user_by_email(self) -> User: def __user_by_email(self) -> dict[str, UserBase]:
if self.___user_by_email is None: if self.___user_by_email is None:
self.__users 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 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}') slog(WARNING, f'Returning False for {access_type} access to resource {what} by {who}')
return False return False
def _user(self, name) -> User: def _user(self, name) -> UserBase:
try: try:
return self.__users[name] return self.__users[name]
except: except:
slog(ERR, f'No such user: "{name}"') slog(ERR, f'No such user: "{name}"')
raise raise
def _user_by_email(self, email: str) -> User: def _user_by_email(self, email: str) -> UserBase:
return self.__user_by_email[email] return self.__user_by_email[email]
def _current_user(self) -> User: def _current_user(self) -> User:
raise NotImplementedError raise NotImplementedError
def _users(self) -> list[User]: def _users(self) -> dict[str, UserBase]:
return self.__users return self.__users
def _projects(self, name, flags: ProjectFlags) -> list[str]: def _projects(self, name, flags: ProjectFlags) -> list[str]:
if flags & ProjectFlags.Contributing: if flags & ProjectFlags.Contributing:
# TODO: Ask LDAP # TODO: Ask LDAP
pass slog(WARNING, f'Querying LDAP for projects a user contributes to is not implemented, ignoring')
return None return []

View file

@ -29,7 +29,7 @@ class MapAttr2Shape: # export
for name, url in self.__ns.items(): for name, url in self.__ns.items():
ET.register_namespace(name, url) ET.register_namespace(name, url)
def __keys(self, root): def __keys(self, root) -> dict[str, str]:
ret: dict[str, str] = {} ret: dict[str, str] = {}
for el in root.findall('key', self.__ns): for el in root.findall('key', self.__ns):
attr_name = el.get('attr.name') attr_name = el.get('attr.name')
@ -44,7 +44,7 @@ class MapAttr2Shape: # export
return None return None
return data.text return data.text
def __attribs(self, node, keys): def __attribs(self, node, keys) -> dict[str, str]:
ret: dict[str, str] = {} ret: dict[str, str] = {}
for name, key in keys.items(): for name, key in keys.items():
val = self.__value(node, key) val = self.__value(node, key)
@ -93,13 +93,13 @@ class MapAttr2Shape: # export
values[key] = default values[key] = default
continue continue
try: try:
if isinstance(str, mapping): if isinstance(mapping, str):
values[key] = mapping values[key] = mapping
continue continue
mapped = mapping(self.__attribs(node, keys))
values[key] = mapped or default
except: except:
pass pass
mapped = mapping(self.__attribs(node, keys))
values[key] = mapped or default
color = values['color'] color = values['color']
text = values['text'] text = values['text']

View file

@ -83,7 +83,7 @@ class Connection: # export
raise Exception(f'Failed to bind to {c.ldap_uri} with dn {c.bind_dn} ({e})') raise Exception(f'Failed to bind to {c.ldap_uri} with dn {c.bind_dn} ({e})')
self.__ldap = ret self.__ldap = ret
self.__backtrace = backtrace 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_class_tree: nx.Graph|None = None
self.__object_classes_by_name: dict[str, ObjectClass]|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): def add(self, attrs: dict[str, bytes], dn: str|None=None):
if dn is None: if dn is None:
dn = attrs.get('dn') if not 'dn' in attrs:
if dn is None:
raise Exception('No DN to add an LDAP entry to') raise Exception('No DN to add an LDAP entry to')
else: attrs = copy.deepcopy(attrs)
attrs = copy.deepcopy(attrs) del attrs['dn']
del attrs['dn']
try: try:
slog(INFO, f'LDAP: Add [{dn}] -> {attrs}') slog(INFO, f'LDAP: Add [{dn}] -> {attrs}')
self.__ldap.add_s(dn, ldap.modlist.addModlist(attrs)) self.__ldap.add_s(dn, ldap.modlist.addModlist(attrs))
@ -175,14 +173,14 @@ class Connection: # export
assert_not_empty=False, 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) result.append(entry)
def __search(): def __search():
return f'{base} -> "{filterstr}"' return f'{base} -> "{filterstr}"'
try: try:
result = [] result: list[Any] = []
self.walk(__walk_cb_find, base, scope=scope, filterstr=filterstr, attrlist=attrlist) self.walk(__walk_cb_find, base, scope=scope, filterstr=filterstr, attrlist=attrlist)
except Exception as e: except Exception as e:
slog(ERR, f'Failed search {__search()} ({e})') slog(ERR, f'Failed search {__search()} ({e})')
@ -194,9 +192,9 @@ class Connection: # export
return result return result
@property @property
def object_classes(self) -> list[ObjectClass]: def object_classes(self) -> dict[str, ObjectClass]:
#def object_classes(self): #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']) 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 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=['*', '+']) 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_subentry = ldap.cidict.cidict(subschema_entry[1])
subschema = ldap.schema.SubSchema(subschema_subentry) subschema = ldap.schema.SubSchema(subschema_subentry)
object_class_oids = subschema.listall(ObjectClass) 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 oid: subschema.get_obj(ObjectClass, oid) for oid in object_class_oids
} }
return self.__object_classes return self.__object_classes_by_oid
@property @property
def object_class_by_name(self): def object_class_by_name(self) -> dict[str, ObjectClass]:
if self.__object_classes_by_name is None: if self.__object_classes_by_name is None:
ret: dict[str, ObjectClass] = {} ret: dict[str, ObjectClass] = {}
self.__object_classes_by_name = ret self.__object_classes_by_name = ret
@ -230,7 +228,7 @@ class Connection: # export
def object_class_path(self, leaf: str|ObjectClass): def object_class_path(self, leaf: str|ObjectClass):
def cb(oc, context): def cb(oc, context):
ret.append(oc) ret.append(oc)
ret = [] ret: list[str] = []
self.__oc_recurse_to_top(leaf, cb, None) self.__oc_recurse_to_top(leaf, cb, None)
return reversed(ret) return reversed(ret)

View file

@ -98,7 +98,7 @@ class Stream:
self.stream = stream self.stream = stream
self.flags = flags self.flags = flags
_streams: dict[int, io.IOBase] = dict() _streams: dict[int, Stream] = dict()
_stream_descriptors = [reversed(range(1, 16))] _stream_descriptors = [reversed(range(1, 16))]
def add_capture_stream(stream, flags=0x0): def add_capture_stream(stream, flags=0x0):
@ -120,7 +120,7 @@ def log_level(s: Optional[str]=None) -> int: # export
return _level return _level
return parse_log_prio_str(s) 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: if kwargs and 'caller' in kwargs:
r = kwargs['caller'] r = kwargs['caller']
del kwargs['caller'] del kwargs['caller']
@ -261,10 +261,10 @@ def set_level(level_: str) -> None: # export
return return
_level = level_ _level = level_
def set_flags(flags: str|None) -> None: # export def set_flags(flags: str|None) -> str: # export
global _flags global _flags
ret = ','.join(_flags) ret = ','.join(_flags)
if _flags is not None: if flags is not None:
_flags = set(flags.split(',')) _flags = set(flags.split(','))
return ret return ret

View file

@ -287,7 +287,7 @@ class StringTree: # export
case _: case _:
raise NotImplementedError(f'Matcher {match} is not yet implemented') raise NotImplementedError(f'Matcher {match} is not yet implemented')
ret = [] ret: list[StringTree] = []
if depth_first: if depth_first:
__children() __children()