Repository navigation
Some mixins are not properly type-hinted #2228
Description
Activity
Yes, that is a current limitation of our type-hints. For the
getmethods we have forced each manager to define agetmethod which has the correct type-hint. But we would like to have a better way to handle it for all methods without needing to define each one in every manager.Reacted by Mykola SolodukhaIs this a duplicate of #2062?
Yes, that is a current limitation of our type-hints. For the
getmethods we have forced each manager to define agetmethod which has the correct type-hint. But we would like to have a better way to handle it for all methods without needing to define each one in every manager.Wouldn't a generic protocol work for this, like mypy documentation recommends?
I made a small script to test if type checker will properly resolve the type:
import typing T = typing.TypeVar('T') class ObjClsProtocol(typing.Protocol[T]): _obj_cls: type[T] class CreateMixin: def create(self: ObjClsProtocol[T]) -> T: return self._obj_cls() class Bar: def test(self) -> int: return 1 class Foo(CreateMixin): _obj_cls = Bar typing.reveal_type(Foo().create()) typing.reveal_type(Foo().create().test())
When I ran mypy 1.14.0 it seemed to properly resolve the types:
typing_protocol.py:24: note: Revealed type is "typing_protocol.Bar" typing_protocol.py:25: note: Revealed type is "builtins.int"I made a table of the Mixins to the attributes used. This is useful for defining the protocols.
Mixin Attrs used HeadMixin self.path,self.gitlabGetMixin self._obj_cls,self.path,self.gitlabGetWithoutIdMixin self._obj_cls,self.path,self.gitlabRefreshMixin self.manager,self.encoded_id,self._update_attrs()ListMixin self._obj_cls,self.path,self.gitlabCreateMixin self._obj_cls,self.path,self.gitlab,self._typesUpdateMixin self._obj_cls,self.path,self.gitlabSetMixin self._obj_cls,self.path,self.gitlabDeleteMixin self.path,self.gitlabSaveMixin self.manager,self.encoded_idObjectDeleteMixin self.manager,self.encoded_idUserAgentDetailMixin self.manager,self.encoded_id,self._update_attrsAccessRequestMixin self.manager,self.encoded_id,self._update_attrsDownloadMixin self.managerRotateMixin self.path,self.gitlabObjectRotateMixin self.manager,self.encoded_id,self._update_attrsSubscribableMixin self.manager,self.encoded_id,self._update_attrsTodoMixin self.manager,self.encoded_id,TimeTrackingMixin self.manager,self.encoded_id,self.attributesParticipantsMixin self.manager,self.encoded_idPromoteMixin self.manager,self.encoded_idUploadMixin self.manager,self.attributes,self._upload_pathAs you can see generally there are 2 groups of attributes used:
self._obj_cls,self.path,self.gitlabandself.manager,self.encoded_idI prototyped using a Protocol for the
RESTManager. Apparently there is a commentDerived class must define ``_path`` and ``_obj_cls``.so having separate class for the manager without _obj_cls is not needed according to this comment. Not sure why the_pathis marked as Optional though.I also used the
@abstractmethodin the protocol to ensure that subclasses define the_pathand_obj_clsand it seems to be type checked but only when the class is initialised but not then defined.from typing import Protocol, TypeVar, reveal_type from abc import abstractmethod class Gitlab: ... class RESTObject: ... T = TypeVar("T", bound=RESTObject, covariant=True) class RESTManagerProtocol(Protocol[T]): _gl: Gitlab def __init__(self, gitlab: Gitlab): self._gl = gitlab @property @abstractmethod def path(self) -> str: ... @property @abstractmethod def _obj_cls(self) -> type[T]: ... class ListMixin: def list(self: RESTManagerProtocol[T]) -> list[T]: return [self._obj_cls()] class Bar(RESTObject): ... class Foo(ListMixin, RESTManagerProtocol[Bar]): path = "test/" _obj_cls = Bar class Bad(RESTManagerProtocol[Bar]): ... def test(gl: Gitlab) -> None: foo = Foo(gl) reveal_type(foo.list()) Bad(gl) if __name__ == "__main__": test(Gitlab())
The Bad class that does not define the
_pathor_obj_clsso it type errors on instantiating:typing_mixin_base.py:55: error: Cannot instantiate abstract class "Bad" with abstract attributes "_obj_cls" and "path" [abstract]- locked as resolved and limited conversation to collaborators
on Feb 9, 2026
E.g. for the
CreateMixinthe.create(...)method returns things likeProjectMergeRequestbut not thebase.RESTObjectas specified here.python-gitlabversion: 3.5.0