Skip to content

Commit 9fd55aa

Browse files
authored
[mypyc] Add note about using non-native class to subclass built-in types (#19236)
Without the note, it's not clear what's the easiest way forward. Also add a doc link. Test that subclassing a built-in exception type actually works as suggested by the note.
1 parent 5610a23 commit 9fd55aa

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

mypyc/irbuild/prepare.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,16 @@ def prepare_class_def(
298298
errors.error(
299299
"Inheriting from most builtin types is unimplemented", path, cdef.line
300300
)
301+
errors.note(
302+
"Potential workaround: @mypy_extensions.mypyc_attr(native_class=False)",
303+
path,
304+
cdef.line,
305+
)
306+
errors.note(
307+
"https://mypyc.readthedocs.io/en/stable/native_classes.html#defining-non-native-classes",
308+
path,
309+
cdef.line,
310+
)
301311

302312
# Set up the parent class
303313
bases = [mapper.type_to_ir[base.type] for base in info.bases if base.type in mapper.type_to_ir]

mypyc/test-data/commandline.test

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ Foo.lol = 50 # E: Only class variables defined as ClassVar can be assigned to
138138
def decorator(x: Any) -> Any:
139139
return x
140140

141-
class NeverMetaclass(type): # E: Inheriting from most builtin types is unimplemented
141+
class NeverMetaclass(type): # E: Inheriting from most builtin types is unimplemented \
142+
# N: Potential workaround: @mypy_extensions.mypyc_attr(native_class=False) \
143+
# N: https://mypyc.readthedocs.io/en/stable/native_classes.html#defining-non-native-classes
142144
pass
143145

144146
class Concrete1:

mypyc/test-data/irbuild-classes.test

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1375,7 +1375,9 @@ class BadUse(): # E: native_class must be used with True or False only
13751375
from mypy_extensions import mypyc_attr
13761376

13771377
@mypyc_attr(native_class=True)
1378-
class M(type): # E: Inheriting from most builtin types is unimplemented
1378+
class M(type): # E: Inheriting from most builtin types is unimplemented \
1379+
# N: Potential workaround: @mypy_extensions.mypyc_attr(native_class=False) \
1380+
# N: https://mypyc.readthedocs.io/en/stable/native_classes.html#defining-non-native-classes
13791381
pass
13801382

13811383
@mypyc_attr(native_class=True)

mypyc/test-data/run-classes.test

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,53 @@ def welp() -> int:
934934
from native import welp
935935
assert welp() == 35
936936

937+
[case testSubclassUnsupportedException]
938+
from mypy_extensions import mypyc_attr
939+
940+
@mypyc_attr(native_class=False)
941+
class MyError(ZeroDivisionError):
942+
pass
943+
944+
@mypyc_attr(native_class=False)
945+
class MyError2(ZeroDivisionError):
946+
def __init__(self, s: str) -> None:
947+
super().__init__(s + "!")
948+
self.x = s.upper()
949+
950+
def f() -> None:
951+
raise MyError("foobar")
952+
953+
def test_non_native_exception_subclass_basics() -> None:
954+
e = MyError()
955+
assert isinstance(e, MyError)
956+
assert isinstance(e, ZeroDivisionError)
957+
assert isinstance(e, Exception)
958+
959+
e = MyError("x")
960+
assert repr(e) == "MyError('x')"
961+
962+
e2 = MyError2("ab")
963+
assert repr(e2) == "MyError2('ab!')", repr(e2)
964+
assert e2.x == "AB"
965+
966+
def test_raise_non_native_exception_subclass_1() -> None:
967+
try:
968+
f()
969+
except MyError:
970+
x = True
971+
else:
972+
assert False
973+
assert x
974+
975+
def test_raise_non_native_exception_subclass_2() -> None:
976+
try:
977+
f()
978+
except ZeroDivisionError:
979+
x = True
980+
else:
981+
assert False
982+
assert x
983+
937984
[case testSubclassPy]
938985
from b import B, V
939986
class A(B):

0 commit comments

Comments
 (0)