Skip to content
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

Makes classes compatible with mypy 1.2 #487

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ jobs:
- name: Run tests
run: |
poetry run flake8 .
poetry run mypy classes ./tests/**/*.py
# TODO: Remove `no-warn-unused-ignores` flag once we drop support for Python 3.7 and 3.8
poetry run mypy --no-warn-unused-ignores classes ./tests/**/*.py
poetry run codespell classes tests docs typesafety README.md CONTRIBUTING.md CHANGELOG.md
poetry run pytest classes tests docs/pages README.md
poetry run doc8 -q docs
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

We follow Semantic Versions since the `0.1.0` release.

## Version 0.5.0 WIP

### Features

- Now requires `mypy>=1.2`

## Version 0.4.1

Expand Down
2 changes: 1 addition & 1 deletion classes/_typeclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ def __call__(
],
*args,
**kwargs,
) -> _ReturnType:
) -> _ReturnType: # type: ignore[type-var]
"""
We use this method to actually call a typeclass.

Expand Down
6 changes: 3 additions & 3 deletions classes/contrib/mypy/typeops/call_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from mypy.typeops import get_type_vars, make_simplified_union
from mypy.types import CallableType, Instance, ProperType
from mypy.types import Type as MypyType
from mypy.types import TypeVarType, union_items
from mypy.types import TypeVarType
from typing_extensions import Final, final

from classes.contrib.mypy.typeops import type_loader
from classes.contrib.mypy.typeops import type_loader, union

_INCOMPATIBLE_TYPEVAR_MSG: Final = (
'Argument 1 to {0} has incompatible type "{1}"; expected "{2}"'
Expand Down Expand Up @@ -61,7 +61,7 @@ def _infer_type_var(
first_arg: TypeVarType,
passed_type: MypyType,
) -> CallableType:
instance_types = union_items(self._instance_type)
instance_types = union.union_items(self._instance_type)
if isinstance(self._associated_type, Instance):
instance_types.append(_load_supports_type(
first_arg,
Expand Down
8 changes: 4 additions & 4 deletions classes/contrib/mypy/typeops/mro.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
from mypy.subtypes import is_equivalent
from mypy.types import Instance
from mypy.types import Type as MypyType
from mypy.types import UnionType, union_items
from mypy.types import UnionType
from typing_extensions import final

from classes.contrib.mypy.typeops import type_loader
from classes.contrib.mypy.typeops import type_loader, union


@final
Expand Down Expand Up @@ -78,7 +78,7 @@ def __init__(
"""
self._associated_type = associated_type
self._ctx = ctx
self._instance_types = union_items(instance_type)
self._instance_types = union.union_items(instance_type)

# Why do we store added types in a mutable global state?
# Because, these types are hard to replicate without the proper context.
Expand Down Expand Up @@ -181,7 +181,7 @@ def _remove_unified_type(
base = instance_type.type.bases[index]
union_types = [
type_arg
for type_arg in union_items(base.args[0])
for type_arg in union.union_items(base.args[0])
if type_arg not in supports_type.args
]
instance_type.type.bases[index] = supports_type.copy_modified(
Expand Down
2 changes: 1 addition & 1 deletion classes/contrib/mypy/typeops/type_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def load_supports_type(
[arg_type],
)
assert supports_spec
supports_spec.type._promote = None # noqa: WPS437
supports_spec.type._promote = [] # noqa: WPS437
return supports_spec


Expand Down
13 changes: 13 additions & 0 deletions classes/contrib/mypy/typeops/union.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import List

from mypy.types import ProperType
from mypy.types import Type as MypyType
from mypy.types import flatten_nested_unions, get_proper_type


def union_items(typ: MypyType) -> List[ProperType]:
"""Get and flat all union types."""
return [
get_proper_type(union_member)
for union_member in flatten_nested_unions([typ])
]
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

from mypy.erasetype import erase_type
from mypy.plugin import MethodContext
from mypy.sametypes import is_same_type
from mypy.subtypes import is_subtype
from mypy.subtypes import is_same_type, is_subtype
from mypy.types import Instance
from mypy.types import Type as MypyType
from mypy.types import TypedDictType
Expand Down
2,066 changes: 1,113 additions & 953 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ python = "^3.7"
typing_extensions = ">=3.10,<5.0"

[tool.poetry.dev-dependencies]
mypy = "^0.942"
mypy = "^1.2.0"

wemake-python-styleguide = "^0.17"
flake8-pytest-style = "^1.6"
nitpick = "^0.32"
nitpick = "^0.33.1"

safety = "^2.3"

pytest = "^7.2"
pytest-cov = "^4.0"
pytest-randomly = "^3.12"
pytest-mypy-plugins = "^1.9"
pytest-mypy-plugins = "^1.10.1"

sphinx = "^5.2"
sphinx-autodoc-typehints = "^1.20"
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ exclude_lines =
plugins =
classes.contrib.mypy.classes_plugin

disable_error_code = empty-body

allow_redefinition = false
check_untyped_defs = true
disallow_any_explicit = true
Expand Down
6 changes: 3 additions & 3 deletions tests/test_associated_type/test_variadic_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ def test_subtype_is_variadic():
class Example(AssociatedType[_FirstType]):
"""Correct type."""

assert Example[int]
assert Example[int, int] # type: ignore
assert Example[int, int, str] # type: ignore
assert Example[int] # type: ignore[truthy-function]
assert Example[int, int] # type: ignore[misc]
assert Example[int, int, str] # type: ignore[misc]
2 changes: 1 addition & 1 deletion tests/test_supports.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __instancecheck__(cls, other) -> bool:
)


class _ListOfStr(List[str], metaclass=_ListOfStrMeta):
class _ListOfStr(List[str], metaclass=_ListOfStrMeta): # type: ignore[misc]
"""We use this for testing concrete type calls."""


Expand Down
2 changes: 1 addition & 1 deletion tests/test_typeclass/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __instancecheck__(cls, other) -> bool:
)


class _ListOfStr(List[str], metaclass=_ListOfStrMeta):
class _ListOfStr(List[str], metaclass=_ListOfStrMeta): # type: ignore[misc]
"""We use this for testing concrete type calls."""


Expand Down
2 changes: 1 addition & 1 deletion tests/test_typeclass/test_typed_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def __instancecheck__(cls, arg: object) -> bool:

_Meta = type('_Meta', (_UserDictMeta, type(TypedDict)), {})

class UserDict(_User, metaclass=_Meta):
class UserDict(_User, metaclass=_Meta): # type: ignore[misc]
"""We use this class to represent a typed dict with instance check."""

@typeclass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
def to_json(instance, verbose: bool = False) -> str:
...
out: |
main:6: error: Single direct subclass of "classes._typeclass.AssociatedType" required; got "main.ToJson"
main:6: error: Single direct subclass of "classes._typeclass.AssociatedType" required; got "main.ToJson" [misc]


- case: typeclass_definied_by_multiple_parents
Expand All @@ -28,4 +28,4 @@
def to_json(instance, verbose: bool = False) -> str:
...
out: |
main:9: error: Single direct subclass of "classes._typeclass.AssociatedType" required; got "main.ToJson"
main:9: error: Single direct subclass of "classes._typeclass.AssociatedType" required; got "main.ToJson" [misc]
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
def compare(instance) -> int:
...
out: |
main:7: error: Associated types must not have bodies
main:7: error: Associated types must not have bodies [misc]


- case: associated_type_with_attr
Expand All @@ -26,7 +26,7 @@
def compare(instance) -> int:
...
out: |
main:6: error: Associated types must not have bodies
main:6: error: Associated types must not have bodies [misc]


- case: associated_type_with_pass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
def compare(instance: List[X]) -> X:
...
out: |
main:10: error: Generic type "main.Compare" with "0" type arguments does not match generic instance declaration "builtins.list[X`-1]" with "1" type arguments
main:10: error: Generic type "main.Compare" with "0" type arguments does not match generic instance declaration "builtins.list[X`-1]" with "1" type arguments [misc]
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
def from_json(instance) -> str:
...
out: |
main:10: error: AssociatedType "main.ToJson" must not be reused, originally associated with "main.from_json"
main:10: error: AssociatedType "main.ToJson" must not be reused, originally associated with "main.from_json" [misc]
4 changes: 2 additions & 2 deletions typesafety/test_associated_type/test_variadic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
One[int, str]
Two[int]
out: |
main:18: error: Type application has too many types (1 expected)
main:19: error: Type application has too few types (2 expected)
main:18: error: Type application has too many types (1 expected) [misc]
main:19: error: Type application has too few types (2 expected) [misc]
26 changes: 13 additions & 13 deletions typesafety/test_supports_type/test_generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

x: Supports[Some[int]] = [1, 2, 3]
y = {1, 2, 3}
reveal_type(some(x)) # N: Revealed type is "builtins.int*"
reveal_type(some(y)) # N: Revealed type is "builtins.int*"
reveal_type(some(x)) # N: Revealed type is "builtins.int"
reveal_type(some(y)) # N: Revealed type is "builtins.int"


- case: supports_generic_correct2
Expand All @@ -47,8 +47,8 @@

x: Supports[Some[int, str]] = {1: 'a'}

reveal_type(some(x, 1, 'a')) # N: Revealed type is "builtins.str*"
reveal_type(some({'a': 1}, 'a', 1)) # N: Revealed type is "builtins.int*"
reveal_type(some(x, 1, 'a')) # N: Revealed type is "builtins.str"
reveal_type(some({'a': 1}, 'a', 1)) # N: Revealed type is "builtins.int"


- case: supports_generic_wrong1
Expand All @@ -73,8 +73,8 @@
x: Supports[Some[int]] = {1, 2, 3}
some({1, 2, 3})
out: |
main:17: error: Incompatible types in assignment (expression has type "Set[int]", variable has type "Supports[Some[int]]")
main:18: error: Argument 1 to "some" has incompatible type "Set[int]"; expected "Supports[Some[<nothing>]]"
main:17: error: Incompatible types in assignment (expression has type "Set[int]", variable has type "Supports[Some[int]]") [assignment]
main:18: error: Argument 1 to "some" has incompatible type "Set[int]"; expected "Supports[Some[<nothing>]]" [arg-type]


- case: supports_generic_wrong2
Expand Down Expand Up @@ -105,11 +105,11 @@
y: Supports[Some[int]] = {1, 2, 3}
z: Supports[Some[int]] = 1
out: |
main:17: error: Found different typeclass ".instance" calls, use only "main.some"
main:17: error: Instance "Union[builtins.list[X`-1], builtins.set[X`-1]]" does not match inferred type "builtins.set[_T`1]"
main:22: error: Incompatible types in assignment (expression has type "List[int]", variable has type "Supports[Some[int]]")
main:23: error: Incompatible types in assignment (expression has type "Set[int]", variable has type "Supports[Some[int]]")
main:24: error: Incompatible types in assignment (expression has type "int", variable has type "Supports[Some[int]]")
main:17: error: Found different typeclass ".instance" calls, use only "main.some" [misc]
main:17: error: Instance "Union[builtins.list[X`-1], builtins.set[X`-1]]" does not match inferred type "builtins.set[_T`1]" [misc]
main:22: error: Incompatible types in assignment (expression has type "List[int]", variable has type "Supports[Some[int]]") [assignment]
main:23: error: Incompatible types in assignment (expression has type "Set[int]", variable has type "Supports[Some[int]]") [assignment]
main:24: error: Incompatible types in assignment (expression has type "int", variable has type "Supports[Some[int]]") [assignment]


- case: supports_multiple_one_generic_one_regular
Expand Down Expand Up @@ -177,5 +177,5 @@
...

a: Supports[Some[str], Other[int]]
reveal_type(some(a)) # N: Revealed type is "builtins.str*"
reveal_type(other(a)) # N: Revealed type is "builtins.int*"
reveal_type(some(a)) # N: Revealed type is "builtins.str"
reveal_type(other(a)) # N: Revealed type is "builtins.int"
18 changes: 9 additions & 9 deletions typesafety/test_supports_type/test_regular.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

convert_to_json(1)
convert_to_json('a')
convert_to_json(None) # E: Argument 1 to "convert_to_json" has incompatible type "None"; expected "Supports[ToJson]"
convert_to_json(None) # E: Argument 1 to "convert_to_json" has incompatible type "None"; expected "Supports[ToJson]" [arg-type]


- case: typeclass_supports_type_restriction
Expand Down Expand Up @@ -74,7 +74,7 @@

convert_to_json(to_json, 1)
convert_to_json(to_json, 'a')
convert_to_json(to_json, None) # E: Argument 2 to "convert_to_json" has incompatible type "None"; expected "Supports[ToJson]"
convert_to_json(to_json, None) # E: Argument 2 to "convert_to_json" has incompatible type "None"; expected "Supports[ToJson]" [arg-type]


- case: typeclass_supports_with_function
Expand All @@ -97,7 +97,7 @@
def convert_to_json(instance: Supports[to_json]) -> str:
...
out: |
main:15: error: Function "main.to_json" is not valid as a type
main:15: error: Function "main.to_json" is not valid as a type [valid-type]
main:15: note: Perhaps you need "Callable[...]" or a callback protocol?


Expand All @@ -119,7 +119,7 @@
def convert_to_json(instance: Supports[Other]) -> str:
return to_json(instance)
out: |
main:14: error: Argument 1 to "to_json" has incompatible type "Supports[Other]"; expected "Supports[ToJson]"
main:14: error: Argument 1 to "to_json" has incompatible type "Supports[Other]"; expected "Supports[ToJson]" [arg-type]


- case: supports_annotation
Expand All @@ -139,20 +139,20 @@
return str(instance)

a: Supports[ToJson] = 1
b: Supports[ToJson] = 'a' # E: Incompatible types in assignment (expression has type "str", variable has type "Supports[ToJson]")
b: Supports[ToJson] = 'a' # E: Incompatible types in assignment (expression has type "str", variable has type "Supports[ToJson]") [assignment]


- case: supports_type_bound
disable_cache: false
main: |
from classes import Supports, AssociatedType

a: Supports[int] # E: Type argument "builtins.int" of "Supports" must be a subtype of "classes._typeclass.AssociatedType"
a: Supports[int] # E: Type argument "builtins.int" of "Supports" must be a subtype of "classes._typeclass.AssociatedType" [misc]

class A(AssociatedType):
...

b: Supports[A, int] # E: Type argument "builtins.int" of "Supports" must be a subtype of "classes._typeclass.AssociatedType"
b: Supports[A, int] # E: Type argument "builtins.int" of "Supports" must be a subtype of "classes._typeclass.AssociatedType" [misc]


- case: supports_multiple_types
Expand Down Expand Up @@ -261,5 +261,5 @@
a: Supports[ToJson] = 'a'
b: Supports[FromJson] = 'a' # error
out: |
main:21: error: Instance callback is incompatible "def (instance: builtins.str, other: Any) -> builtins.str"; expected "def (instance: builtins.str) -> builtins.str"
main:26: error: Incompatible types in assignment (expression has type "str", variable has type "Supports[FromJson]")
main:21: error: Instance callback is incompatible "def (instance: builtins.str, other: Any) -> builtins.str"; expected "def (instance: builtins.str) -> builtins.str" [misc]
main:26: error: Incompatible types in assignment (expression has type "str", variable has type "Supports[FromJson]") [assignment]
8 changes: 4 additions & 4 deletions typesafety/test_typeclass/test__call__.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
some(B()) # ok
some(C()) # ok
out: |
main:20: error: Argument 1 to "some" has incompatible type "A"; expected "B"
main:20: error: Argument 1 to "some" has incompatible type "A"; expected "B" [arg-type]


- case: typeclass_call_generic_instance_variance
Expand Down Expand Up @@ -98,7 +98,7 @@
some(b) # ok
some(c) # ok
out: |
main:26: error: Argument 1 to "some" has incompatible type "A[int]"; expected "B[<nothing>]"
main:26: error: Argument 1 to "some" has incompatible type "A[int]"; expected "B[<nothing>]" [arg-type]


- case: typeclass_call_variance_union1
Expand Down Expand Up @@ -129,7 +129,7 @@
some(B()) # ok
some(C()) # ok
out: |
main:22: error: Argument 1 to "some" has incompatible type "A"; expected "B"
main:22: error: Argument 1 to "some" has incompatible type "A"; expected "B" [arg-type]


- case: typeclass_call_variance_union2
Expand Down Expand Up @@ -238,4 +238,4 @@
def some(instance) -> int:
...

some() # E: Missing positional argument "instance" in call to "__call__" of "_TypeClass"
some() # E: Missing positional argument "instance" in call to "__call__" of "_TypeClass" [call-arg]
Loading