diff --git a/server/src/uds/REST/dispatcher.py b/server/src/uds/REST/dispatcher.py index 1f95025f0..fd9cf64e8 100644 --- a/server/src/uds/REST/dispatcher.py +++ b/server/src/uds/REST/dispatcher.py @@ -167,12 +167,9 @@ class Dispatcher(View): # type: ignore content_type="text/plain", ) except AttributeError: - allowedMethods = [] - for n in ['get', 'post', 'put', 'delete']: - if hasattr(handler, n): - allowedMethods.append(n) + allowed_methods: list[str] = [n for n in ['get', 'post', 'put', 'delete'] if hasattr(handler, n)] log.log_operation(handler, 405, log.LogLevel.ERROR) - return http.HttpResponseNotAllowed(allowedMethods, content_type="text/plain") + return http.HttpResponseNotAllowed(allowed_methods, content_type="text/plain") except exceptions.rest.AccessDenied: log.log_operation(handler, 403, log.LogLevel.ERROR) return http.HttpResponseForbidden('access denied', content_type="text/plain") diff --git a/server/src/uds/REST/methods/servers_management.py b/server/src/uds/REST/methods/servers_management.py index 34cce30ad..d8b8e7026 100644 --- a/server/src/uds/REST/methods/servers_management.py +++ b/server/src/uds/REST/methods/servers_management.py @@ -62,7 +62,7 @@ class ServersTokens(ModelHandler): path = 'servers' name = 'tokens' - table_title = typing.cast('str', _('Registered Servers')) + table_title = _('Registered Servers') table_fields = [ {'hostname': {'title': _('Hostname')}}, {'ip': {'title': _('IP')}}, @@ -72,8 +72,8 @@ class ServersTokens(ModelHandler): {'stamp': {'title': _('Date'), 'type': 'datetime'}}, ] - def item_as_dict(self, item_: 'Model') -> dict[str, typing.Any]: - item = typing.cast('models.Server', item_) # We will receive for sure + def item_as_dict(self, item: 'Model') -> dict[str, typing.Any]: + item = typing.cast('models.Server', item) # We will receive for sure return { 'id': item.uuid, 'name': str(_('Token isued by {} from {}')).format(item.username, item.ip), @@ -111,8 +111,8 @@ class ServersTokens(ModelHandler): class ServersServers(DetailHandler): custom_methods = ['maintenance'] - def get_items(self, parent_: 'Model', item: typing.Optional[str]) -> types.rest.ManyItemsDictType: - parent = typing.cast('models.ServerGroup', parent_) # We will receive for sure + def get_items(self, parent: 'Model', item: typing.Optional[str]) -> types.rest.ManyItemsDictType: + parent = typing.cast('models.ServerGroup', parent) # We will receive for sure try: multi = False if item is None: @@ -120,7 +120,7 @@ class ServersServers(DetailHandler): q = parent.servers.all() else: q = parent.servers.filter(uuid=process_uuid(item)) - res = [] + res: types.rest.ManyItemsDictType = [] i = None for i in q: val = { @@ -144,7 +144,7 @@ class ServersServers(DetailHandler): def get_title(self, parent: 'Model') -> str: parent = ensure.is_instance(parent, models.ServerGroup) try: - return _('Servers of {0}').format(parent.name) + return (_('Servers of {0}')).format(parent.name) except Exception: return str(_('Servers')) @@ -316,7 +316,7 @@ class ServersGroups(ModelHandler): name = 'groups' save_fields = ['name', 'comments', 'type', 'tags'] # Subtype is appended on pre_save - table_title = typing.cast(str, _('Servers Groups')) + table_title = _('Servers Groups') table_fields = [ {'name': {'title': _('Name')}}, {'comments': {'title': _('Comments')}}, @@ -338,9 +338,9 @@ class ServersGroups(ModelHandler): type_ += '@default' kind, subkind = type_.split('@')[:2] if kind == types.servers.ServerType.SERVER.name: - kind = typing.cast(str, _('Standard')) + kind = _('Standard') elif kind == types.servers.ServerType.UNMANAGED.name: - kind = typing.cast(str, _('Unmanaged')) + kind = _('Unmanaged') title = _('of type') + f' {subkind.upper()} {kind}' return self.add_field( self.add_default_fields( diff --git a/server/src/uds/REST/methods/services.py b/server/src/uds/REST/methods/services.py index 8eb78c6ca..4b1f05754 100644 --- a/server/src/uds/REST/methods/services.py +++ b/server/src/uds/REST/methods/services.py @@ -88,14 +88,14 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods } @staticmethod - def service_to_dict(item: models.Service, perm: int, full: bool = False) -> dict[str, typing.Any]: + def service_to_dict(item: models.Service, perm: int, full: bool = False) -> types.rest.ItemDictType: """ Convert a service db item to a dict for a rest response :param item: Service item (db) :param full: If full is requested, add "extra" fields to complete information """ itemType = item.get_type() - ret_value = { + ret_value: dict[str, typing.Any] = { 'id': item.uuid, 'name': item.name, 'tags': [tag.tag for tag in item.tags.all()], @@ -166,7 +166,7 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods service = parent.services.get(uuid=process_uuid(item)) service.__dict__.update(fields) - if service is None: + if not service: raise Exception('Cannot create service!') service.tags.set([models.Tag.objects.get_or_create(tag=val)[0] for val in tags]) @@ -322,11 +322,11 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods except Exception: raise self.invalid_item_response() from None - def servicepools(self, parent: 'Model', item: str) -> typing.Any: + def servicepools(self, parent: 'Model', item: str) -> types.rest.ManyItemsDictType: parent = ensure.is_instance(parent, models.Provider) service = parent.services.get(uuid=process_uuid(item)) logger.debug('Got parameters for servicepools: %s, %s', parent, item) - res = [] + res: types.rest.ManyItemsDictType = [] for i in service.deployedServices.all(): try: self.ensure_has_access( diff --git a/server/src/uds/REST/methods/users_groups.py b/server/src/uds/REST/methods/users_groups.py index 63827de60..aba786788 100644 --- a/server/src/uds/REST/methods/users_groups.py +++ b/server/src/uds/REST/methods/users_groups.py @@ -396,7 +396,7 @@ class Groups(DetailHandler): def get_types(self, parent: 'Model', for_type: typing.Optional[str]) -> collections.abc.Iterable[types.rest.TypeInfoDict]: parent = ensure.is_instance(parent, Authenticator) - tDct = { + types_dict: dict[str, dict[str, str]] = { 'group': {'name': _('Group'), 'description': _('UDS Group')}, 'meta': {'name': _('Meta group'), 'description': _('UDS Meta Group')}, } @@ -407,7 +407,7 @@ class Groups(DetailHandler): 'description': v['description'], 'icon': '', } - for k, v in tDct.items() + for k, v in types_dict.items() ] if for_type is None: diff --git a/server/src/uds/REST/model.py b/server/src/uds/REST/model.py index 53aad1539..5697871c0 100644 --- a/server/src/uds/REST/model.py +++ b/server/src/uds/REST/model.py @@ -139,7 +139,7 @@ class BaseModelHandler(Handler): guiDesc['order'] = field.get('order', 0) guiDesc['label'] = field.get('label', field['name']) - v = { + v: dict[str, typing.Any] = { 'name': field.get('name', ''), 'value': field.get('value', ''), 'gui': guiDesc, @@ -289,7 +289,7 @@ class BaseModelHandler(Handler): icon=type_.icon64().replace('\n', ''), ).as_dict(**self.type_info(type_)) if hasattr(type_, 'group'): - res['group'] = _(type_.group) # Add group info is it is contained + res['group'] = getattr(type_, 'group') # Add group info is it is contained return res def process_table_fields( @@ -830,10 +830,10 @@ class ModelHandler(BaseModelHandler): return data # Filtering a non iterable (list or tuple) - if not isinstance(data, (list, tuple, GeneratorType)): + if not isinstance(data, collections.abc.Iterable): return data - logger.debug('data: %s, fltr: %s', data, self.fltr) + logger.debug('data: %s, fltr: %s', typing.cast(typing.Any, data), self.fltr) try: fld, pattern = self.fltr.split('=') s, e = '', '' @@ -846,15 +846,19 @@ class ModelHandler(BaseModelHandler): r = re.compile(s + fnmatch.translate(pattern) + e, re.RegexFlag.IGNORECASE) - def fltr_function(item: collections.abc.MutableMapping[str, typing.Any]) -> bool: + def fltr_function(item: typing.Any) -> bool: + if not isinstance(item, dict): + return False try: - if fld not in item or r.match(item[fld]) is None: + if fld not in item or r.match(typing.cast(dict[str, typing.Any], item)[fld]) is None: return False except Exception: return False return True - res = list(filter(fltr_function, data)) + res: list[dict[str, typing.Any]] = list( + filter(fltr_function, typing.cast(collections.abc.Iterable[dict[str, typing.Any]], data)) + ) logger.debug('After filtering: %s', res) return res @@ -1048,9 +1052,7 @@ class ModelHandler(BaseModelHandler): raise self.invalid_request_response() try: # DB maybe case sensitive??, anyway, uuids are stored in lowercase - item = self.model.objects.get( - uuid=self._args[0].lower() - ) + item = self.model.objects.get(uuid=self._args[0].lower()) return self.get_logs(item) except Exception as e: raise self.invalid_item_response() from e diff --git a/server/src/uds/core/types/rest.py b/server/src/uds/core/types/rest.py index 7bd0d7ed2..80f208112 100644 --- a/server/src/uds/core/types/rest.py +++ b/server/src/uds/core/types/rest.py @@ -33,16 +33,8 @@ import typing import dataclasses import collections.abc -from click import group - -class TypeInfoDict(typing.TypedDict): - name: str - type: str - description: str - icon: str - - group: typing.NotRequired[str] +TypeInfoDict = dict[str, typing.Any] # Alias for type info dict @dataclasses.dataclass class TypeInfo: @@ -51,25 +43,27 @@ class TypeInfo: description: str icon: str - def as_dict(self, group: typing.Optional[str] = None) -> TypeInfoDict: - res: TypeInfoDict = { + def as_dict(self, **kwargs: typing.Any) -> TypeInfoDict: + res: dict[str, typing.Any] = { 'name': self.name, 'type': self.type, 'description': self.description, 'icon': self.icon, } - if group is not None: - res['group'] = group + res.update(kwargs) + return res - + + # This is a named tuple for convenience, and must be # compatible with tuple[str, bool] (name, needs_parent) class ModelCustomMethod(typing.NamedTuple): name: str needs_parent: bool = True + # Alias for item type ItemDictType = dict[str, typing.Any] # Alias for get_items return type -ManyItemsDictType = typing.Union[list[ItemDictType], ItemDictType] \ No newline at end of file +ManyItemsDictType = typing.Union[list[ItemDictType], ItemDictType] diff --git a/server/src/uds/models/tag.py b/server/src/uds/models/tag.py index d61d7ac9b..9049b7050 100644 --- a/server/src/uds/models/tag.py +++ b/server/src/uds/models/tag.py @@ -99,7 +99,7 @@ class Tag(UUIDModel): class TaggingMixin(models.Model): - tags: 'models.ManyToManyField[models.Model, TaggingMixin]' = models.ManyToManyField(Tag) + tags: 'models.ManyToManyField[Tag, TaggingMixin]' = models.ManyToManyField(Tag) class Meta: # pylint: disable=too-few-public-methods abstract = True