Skip to content

Commit 8fd434e

Browse files
committed
Fixes mypy crash, closes #232
1 parent 9ce717a commit 8fd434e

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

classes/contrib/mypy/features/typeclass.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from classes.contrib.mypy.typeops import (
1818
call_signatures,
19+
fallback,
1920
instance_args,
2021
mro,
2122
type_loader,
@@ -154,6 +155,10 @@ class InstanceDefReturnType(object):
154155
155156
"""
156157

158+
@fallback.error_to_any({
159+
# TODO: later we can use a custom exception type for this:
160+
KeyError: 'Typeclass cannot be loaded, it must be a global declaration',
161+
})
157162
def __call__(self, ctx: MethodContext) -> MypyType:
158163
"""Main entry point."""
159164
assert isinstance(ctx.type, Instance)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from typing import Any, Callable, Mapping, Type
2+
3+
from mypy.plugin import MethodContext
4+
from mypy.types import AnyType
5+
from mypy.types import Type as MypyType
6+
from mypy.types import TypeOfAny
7+
8+
_MethodCallback = Callable[[Any, MethodContext], MypyType] # type: ignore
9+
10+
11+
def error_to_any(
12+
error_map: Mapping[Type[Exception], str],
13+
) -> Callable[[_MethodCallback], _MethodCallback]:
14+
"""
15+
Decorator for ``mypy`` callbacks to catch given errors.
16+
17+
We use to show custom messages for given exceptions.
18+
If other exceptions are present, then we show just an error message.
19+
"""
20+
def decorator(func: _MethodCallback) -> _MethodCallback:
21+
def factory(self, ctx: MethodContext) -> MypyType:
22+
try:
23+
return func(self, ctx)
24+
except Exception as ex:
25+
ctx.api.fail(
26+
error_map.get(type(ex), str(ex)),
27+
ctx.context,
28+
)
29+
return AnyType(TypeOfAny.from_error)
30+
return factory
31+
return decorator

typesafety/test_typeclass/test_typeclass.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,23 @@
6666
main:3: note: def [_AssociatedType] typeclass(definition: Type[_AssociatedType]) -> _TypeClassDef[_AssociatedType]
6767
main:3: note: def [_SignatureType, _InstanceType, _AssociatedType, _Fullname <: str] typeclass(signature: _SignatureType) -> _TypeClass[_InstanceType, _SignatureType, _AssociatedType, _Fullname]
6868
main:3: note: Possible overload variants:
69+
70+
71+
- case: typeclass_non_global_declaration
72+
disable_cache: false
73+
main: |
74+
from classes import typeclass
75+
76+
def some():
77+
@typeclass
78+
def a(instance) -> str:
79+
...
80+
81+
@a.instance(int)
82+
def _a_int(instance: int) -> str:
83+
...
84+
85+
reveal_type(_a_int)
86+
out: |
87+
main:8: error: Typeclass cannot be loaded, it must be a global declaration
88+
main:12: note: Revealed type is "Any"

0 commit comments

Comments
 (0)