8000 Add support for Self type by ilevkivskyi · Pull Request #14041 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Add support for Self type #14041

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b205241
Start working on Self type
ilevkivskyi Nov 7, 2022
5e5bd6f
Add support for special forms; some fixes
ilevkivskyi Nov 7, 2022
7f91f3f
More fixes; more tests
ilevkivskyi Nov 7, 2022
80a11f6
Improve a test
ilevkivskyi Nov 8, 2022
2eb0db1
More tests few more fixes
ilevkivskyi Nov 8, 2022
535d936
Add incremental tests
ilevkivskyi Nov 8, 2022
ca7c7e8
Add docs
ilevkivskyi Nov 8, 2022
2ee66ec
Minor cleanup
ilevkivskyi Nov 8, 2022
ccb74a7
Fix self-compilation
ilevkivskyi Nov 8, 2022
504fe2c
Best effort support for unusual locations for self
ilevkivskyi Nov 8, 2022
1a99961
Some cleanups
ilevkivskyi Nov 9, 2022
ce8d345
Enable ClassVar (to some safe extent)
ilevkivskyi Nov 9, 2022
324eff2
Allow redundant Self by default; add error code
ilevkivskyi Nov 9, 2022
d96cfdc
Prohibit Self with arguments
ilevkivskyi Nov 9, 2022
0b953cf
Address CR; minor cleanups
ilevkivskyi Nov 10, 2022
5829804
Prohibit unclear cases; some more tests
ilevkivskyi Nov 10, 2022
3ec47b9
Make ClassVar in generics better
ilevkivskyi Nov 10, 2022
24dd649
More cleanup
ilevkivskyi Nov 10, 2022
ac6234d
Fix TypeVar id clash
ilevkivskyi Nov 11, 2022
61c0589
Final tweaks + couple tests
ilevkivskyi Nov 12, 2022
cbd97b1
Fix another bug from mypy_primer
ilevkivskyi Nov 12, 2022
362d84a
Fix upper bound for Self
ilevkivskyi Nov 12, 2022
a5740eb
More CR (docstring)
ilevkivskyi Nov 12, 2022
6694f3b
Fix Self import; fix method bodies; simplify id handling
ilevkivskyi Nov 12, 2022
3f86bf2
Allow using plain class in final classes
ilevkivskyi Nov 12, 2022
16e017d
Merge branch 'master' into self-type
ilevkivskyi Nov 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Allow redundant Self by default; add error code
  • Loading branch information
ilevkivskyi committed Nov 9, 2022
commit 324eff2bef6b076340f67add43f77dee49cea5a4
19 changes: 19 additions & 0 deletions docs/source/error_code_list2.rst
8000
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,25 @@ Example:
# Error: Redundant cast to "int" [redundant-cast]
return cast(int, x)

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.

Example:

.. code-block:: python

# mypy: enable-error-code="redundant-self"

from typing import Self

class C:
# Error: Redundant Self annotation on method first argument
def copy(self: Self) -> Self:
return type(self)()

Check that comparisons are overlapping [comparison-overlap]
-----------------------------------------------------------

Expand Down
6 changes: 6 additions & 0 deletions mypy/errorcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ def __str__(self) -> str:
"General",
default_enabled=False,
)
REDUNDANT_SELF_TYPE = ErrorCode(
"redundant-self",
"Warn about redundant Self type annotations on method first argument",
"General",
default_enabled=False,
)


# Syntax errors are often blocking.
Expand Down
37 changes: 34 additions & 3 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@
from mypy.semanal_typeddict import TypedDictAnalyzer
from mypy.tvar_scope import TypeVarLikeScope
from mypy.typeanal import (
SELF_TYPE_NAMES,
TypeAnalyser,
TypeVarLikeList,
TypeVarLikeQuery,
Expand Down Expand Up @@ -948,12 +949,42 @@ def prepare_method_signature(self, func: FuncDef, info: TypeInfo, has_self_type:
func.type = replace_implicit_first_type(functype, leading_type)
elif has_self_type and isinstance(func.unanalyzed_type, CallableType):
if not isinstance(get_proper_type(func.unanalyzed_type.arg_types[0]), AnyType):
self.fail(
"Method cannot have explicit self annotation and Self type", func
)
if self.is_expected_self_type(
self_type, func.is_class or func.name == "__new__"
):
# This error is off by default, since it is explicitly allowed
# by the PEP 673.
self.fail(
"Redundant Self annotation on method first argument",
func,
code=codes.REDUNDANT_SELF_TYPE,
)
else:
self.fail(
"Method cannot have explicit self annotation and Self type", func
)
elif has_self_type:
self.fail("Static methods cannot use Self type", func)

def is_expected_self_type(self, typ: Type, is_classmethod: bool) -> bool:
"""Does this (analyzed or not) type represent the expected Self type for a method?"""
assert self.type is not None
typ = get_proper_type(typ)
if is_classmethod:
if isinstance(typ, TypeType):
return self.is_expected_self_type(typ.item, is_classmethod=False)
if isinstance(typ, UnboundType):
sym = self.lookup_qualified(typ.name, typ, suppress_errors=True)
if sym is not None and sym.fullname == "typing.Type" and typ.args:
return self.is_expected_self_type(typ.args[0], is_classmethod=False)
return False
if isinstance(typ, TypeVarType):
return typ == self.type.self_type
if isinstance(typ, UnboundType):
sym = self.lookup_qualified(typ.name, typ, suppress_errors=True)
return sym is not None and sym.fullname in SELF_TYPE_NAMES
return False

def set_original_def(self, previous: Node | None, new: FuncDef | Decorator) -> bool:
"""If 'new' conditionally redefine 'previous', set 'previous' as original

Expand Down
44 changes: 44 additions & 0 deletions test-data/unit/check-selftype.test
Original file line number Diff line number Diff line change
Expand Up @@ -1470,3 +1470,47 @@ class C:
x: Self
def __init__(self, x: C) -> None:
self.x = x # E: Incompatible types in assignment (expression has type "C", variable has type "Self")

[case testTypingSelfRedundantAllowed]
from typing import Self, Type

class C:
def f(self: Self) -> Self:
d: Defer
class Defer: ...
return self

@classmethod
def g(cls: Type[Self]) -> Self:
d: DeferAgain
class DeferAgain: ...
return cls()
[builtins fixtures/classmethod.pyi]

[case testTypingSelfRedundantWarning]
# mypy: enable-error-code="redundant-self"

from typing import Self, Type

class C:
def copy(self: Self) -> Self: # E: Redundant Self annotation on method first argument
d: Defer
class Defer: ...
return self

@classmethod
def g(cls: Type[Self]) -> Self: # E: Redundant Self annotation on method first argument
d: DeferAgain
class DeferAgain: ...
return cls()
[builtins fixtures/classmethod.pyi]

-- Handle unusual locations consistently using a flag

-- Self in cast and type assert should be a Self (and probably actually everywhere)

-- Always prohibit in type aliases

-- Protocol test with ClassVar default

-- NamedTuple with Self (class)method
0