diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst index 85ab76da5cee..f160515f0a9e 100644 --- a/docs/source/error_code_list2.rst +++ b/docs/source/error_code_list2.rst @@ -85,8 +85,11 @@ Example: Check that methods do not have redundant Self annotations [redundant-self] -------------------------------------------------------------------------- -Such annotations are allowed by :pep:`673` but are redundant, so if you want -warnings about them, enable this error code. +If a method uses the ``Self`` type in the return type or the type of a +non-self argument, there is no need to annotate the ``self`` argument +explicitly. Such annotations are allowed by :pep:`673` but are +redundant. If you enable this error code, mypy will generate an error if +there is a redundant ``Self`` type. Example: @@ -97,7 +100,7 @@ Example: from typing import Self class C: - # Error: Redundant Self annotation on method first argument + # Error: Redundant "Self" annotation for the first method argument def copy(self: Self) -> Self: return type(self)() @@ -236,29 +239,34 @@ mypy generates an error if it thinks that an expression is redundant. Check that expression is not implicitly true in boolean context [truthy-bool] ----------------------------------------------------------------------------- -Warn when an expression whose type does not implement ``__bool__`` or ``__len__`` is used in boolean context, -since unless implemented by a sub-type, the expression will always evaluate to true. +Warn when the type of an expression in a boolean context does not +implement ``__bool__`` or ``__len__``. Unless one of these is +implemented by a subtype, the expression will always be considered +true, and there may be a bug in the condition. + +As an exception, the ``object`` type is allowed in a boolean context. +Using an iterable value in a boolean context has a separate error code +(see below). .. code-block:: python # Use "mypy --enable-error-code truthy-bool ..." class Foo: - pass + pass foo = Foo() # Error: "foo" has type "Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context if foo: - ... - -The check is similar in concept to ensuring that an expression's type implements an expected interface (e.g. ``Sized``), -except that attempting to invoke an undefined method (e.g. ``__len__``) results in an error, -while attempting to evaluate an object in boolean context without a concrete implementation results in a truthy value. + ... Check that iterable is not implicitly true in boolean context [truthy-iterable] ------------------------------------------------------------------------------- -``Iterable`` does not implement ``__len__`` and so this code will be flagged: +Generate an error if a value of type ``Iterable`` is used as a boolean +condition, since ``Iterable`` does not implement ``__len__`` or ``__bool__``. + +Example: .. code-block:: python @@ -270,9 +278,13 @@ Check that iterable is not implicitly true in boolean context [truthy-iterable] return [42] return [x + 1 for x in items] -If called with a ``Generator`` like ``int(x) for x in []``, this function would not return ``[42]`` unlike -what the author might have intended. Of course it's possible that ``transform`` is only passed ``list`` objects, -and so there is no error in practice. In such case, it is recommended to annotate ``items: Collection[int]``. +If ``transform`` is called with a ``Generator`` argument, such as +``int(x) for x in []``, this function would not return ``[42]`` unlike +what might be intended. Of course, it's possible that ``transform`` is +only called with ``list`` or other container objects, and the ``if not +items`` check is actually valid. If that is the case, it is +recommended to annotate ``items`` as ``Collection[int]`` instead of +``Iterable[int]``. .. _ignore-without-code: diff --git a/docs/source/generics.rst b/docs/source/generics.rst index a867bc863c83..b8fefd27870f 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -262,10 +262,11 @@ Generic methods and generic self ******************************** You can also define generic methods — just use a type variable in the -method signature that is different from class type variables. In particular, -``self`` may also be generic, allowing a method to return the most precise -type known at the point of access. In this way, for example, you can typecheck -chaining of setter methods: +method signature that is different from class type variables. In +particular, the ``self`` argument may also be generic, allowing a +method to return the most precise type known at the point of access. +In this way, for example, you can type check a chain of setter +methods: .. code-block:: python @@ -291,7 +292,9 @@ chaining of setter methods: circle: Circle = Circle().set_scale(0.5).set_radius(2.7) square: Square = Square().set_scale(0.5).set_width(3.2) -Without using generic ``self``, the last two lines could not be type-checked properly. +Without using generic ``self``, the last two lines could not be type +checked properly, since the return type of ``set_scale`` would be +``Shape``, which doesn't define ``set_radius`` or ``set_width``. Other uses are factory methods, such as copy and deserialization. For class methods, you can also define generic ``cls``, using :py:class:`Type[T] `: @@ -324,16 +327,18 @@ In the latter case, you must implement this method in all future subclasses. Note also that mypy cannot always verify that the implementation of a copy or a deserialization method returns the actual type of self. Therefore you may need to silence mypy inside these methods (but not at the call site), -possibly by making use of the ``Any`` type. +possibly by making use of the ``Any`` type or a ``# type: ignore`` comment. -Note that this feature may accept some unsafe code for the purpose of -*practicality*. For example: +Note that mypy lets you use generic self types in certain unsafe ways +in order to support common idioms. For example, using a generic +self type in an argument type is accepted even though it's unsafe: .. code-block:: python from typing import TypeVar T = TypeVar("T") + class Base: def compare(self: T, other: T) -> bool: return False @@ -342,25 +347,27 @@ Note that this feature may accept some unsafe code for the purpose of def __init__(self, x: int) -> None: self.x = x - # This is unsafe (see below), but allowed because it is - # a common pattern, and rarely causes issues in practice. + # This is unsafe (see below) but allowed because it's + # a common pattern and rarely causes issues in practice. def compare(self, other: Sub) -> bool: return self.x > other.x b: Base = Sub(42) b.compare(Base()) # Runtime error here: 'Base' object has no attribute 'x' -For some advanced uses of self-types see :ref:`additional examples `. +For some advanced uses of self types, see :ref:`additional examples `. Automatic self types using typing.Self ************************************** -The patterns described above are quite common, so there is a syntactic sugar -for them introduced in :pep:`673`. Instead of defining a type variable and -using an explicit ``self`` annotation, you can import a magic type ``typing.Self`` -that is automatically transformed into a type variable with an upper bound of -current class, and you don't need an annotation for ``self`` (or ``cls`` for -class methods). The above example can thus be rewritten as: +Since the patterns described above are quite common, mypy supports a +simpler syntax, introduced in :pep:`673`, to make them easier to use. +Instead of defining a type variable and using an explicit annotation +for ``self``, you can import the special type ``typing.Self`` that is +automatically transformed into a type variable with the current class +as the upper bound, and you don't need an annotation for ``self`` (or +``cls`` in class methods). The example from the previous section can +be made simpler by using ``Self``: .. code-block:: python @@ -381,13 +388,13 @@ class methods). The above example can thus be rewritten as: a, b = SuperFriend.make_pair() -This is more compact than using explicit type variables, plus additionally -you can use ``Self`` in attribute annotations, not just in methods. +This is more compact than using explicit type variables. Also, you can +use ``Self`` in attribute annotations in addition to methods. .. note:: - To use this feature on versions of Python before 3.11, you will need to - import ``Self`` from ``typing_extensions`` version 4.0 or newer. + To use this feature on Python versions earlier than 3.11, you will need to + import ``Self`` from ``typing_extensions`` (version 4.0 or newer). .. _variance-of-generics: @@ -916,5 +923,5 @@ defeating the purpose of using aliases. Example: OIntVec = Optional[Vec[int]] -Using type variable bounds or values in generic aliases, has the same effect +Using type variable bounds or values in generic aliases has the same effect as in generic classes/functions. diff --git a/docs/source/index.rst b/docs/source/index.rst index 27b3a078af6c..ffbd6080cd6f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -39,7 +39,7 @@ understand, debug, and maintain. .. note:: - Although mypy is production ready, there will be occasional changes + Although mypy is production ready, there may be occasional changes that break backward compatibility. The mypy development team tries to minimize the impact of changes to user code. In case of a major breaking change, mypy's major version will be bumped. diff --git a/mypy/semanal.py b/mypy/semanal.py index cd5d5a0d808d..9836ecf38e10 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -986,7 +986,7 @@ def prepare_method_signature(self, func: FuncDef, info: TypeInfo, has_self_type: # This error is off by default, since it is explicitly allowed # by the PEP 673. self.fail( - "Redundant Self annotation on method first argument", + 'Redundant "Self" annotation for the first method argument', func, code=codes.REDUNDANT_SELF_TYPE, ) diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 2d45d28764a0..555cef3641f8 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -1627,13 +1627,13 @@ class C: from typing import Self, Type class C: - def copy(self: Self) -> Self: # E: Redundant Self annotation on method first argument + def copy(self: Self) -> Self: # E: Redundant "Self" annotation for the first method argument d: Defer class Defer: ... return self @classmethod - def g(cls: Type[Self]) -> Self: # E: Redundant Self annotation on method first argument + def g(cls: Type[Self]) -> Self: # E: Redundant "Self" annotation for the first method argument d: DeferAgain class DeferAgain: ... return cls()