From 1da085eb1950db046132ea5e730dac193b1fb16f Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 4 Jun 2025 16:56:34 +0100 Subject: [PATCH 1/5] [mypyc] Add note about using non-native class to subclass built-in types --- mypyc/irbuild/prepare.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 98ff348d8c30..efebfe37089f 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -298,6 +298,9 @@ def prepare_class_def( errors.error( "Inheriting from most builtin types is unimplemented", path, cdef.line ) + errors.note( + "Potential workaround: @mypy_extensions.mypyc_attr(native_class=False)", path, cdef.line + ) # Set up the parent class bases = [mapper.type_to_ir[base.type] for base in info.bases if base.type in mapper.type_to_ir] From 8379e1b573040e1d5847aa4c1b208d959248d9b8 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 4 Jun 2025 16:58:07 +0100 Subject: [PATCH 2/5] Update test case --- mypyc/test-data/irbuild-classes.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index 9d564a552a05..1f99091c85e2 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -1375,7 +1375,8 @@ class BadUse(): # E: native_class must be used with True or False only from mypy_extensions import mypyc_attr @mypyc_attr(native_class=True) -class M(type): # E: Inheriting from most builtin types is unimplemented +class M(type): # E: Inheriting from most builtin types is unimplemented \ + # N: Potential workaround: @mypy_extensions.mypyc_attr(native_class=False) pass @mypyc_attr(native_class=True) From 36df24f518c39e8663e695a65a5a15a9427453e3 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 4 Jun 2025 17:00:55 +0100 Subject: [PATCH 3/5] Add documentation link --- mypyc/irbuild/prepare.py | 9 ++++++++- mypyc/test-data/irbuild-classes.test | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index efebfe37089f..65951999dcf9 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -299,7 +299,14 @@ def prepare_class_def( "Inheriting from most builtin types is unimplemented", path, cdef.line ) errors.note( - "Potential workaround: @mypy_extensions.mypyc_attr(native_class=False)", path, cdef.line + "Potential workaround: @mypy_extensions.mypyc_attr(native_class=False)", + path, + cdef.line, + ) + errors.note( + "https://mypyc.readthedocs.io/en/stable/native_classes.html#defining-non-native-classes", + path, + cdef.line, ) # Set up the parent class diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index 1f99091c85e2..fa4708f02e0b 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -1376,7 +1376,8 @@ from mypy_extensions import mypyc_attr @mypyc_attr(native_class=True) class M(type): # E: Inheriting from most builtin types is unimplemented \ - # N: Potential workaround: @mypy_extensions.mypyc_attr(native_class=False) + # N: Potential workaround: @mypy_extensions.mypyc_attr(native_class=False) \ + # N: https://mypyc.readthedocs.io/en/stable/native_classes.html#defining-non-native-classes pass @mypyc_attr(native_class=True) From a18ee3a33096d5e7ef7273483128fd165f73d64d Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 4 Jun 2025 17:08:29 +0100 Subject: [PATCH 4/5] Add run tests --- mypyc/test-data/run-classes.test | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index b98f1989da51..fd486980ef16 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -934,6 +934,53 @@ def welp() -> int: from native import welp assert welp() == 35 +[case testSubclassUnsupportedException] +from mypy_extensions import mypyc_attr + +@mypyc_attr(native_class=False) +class MyError(ZeroDivisionError): + pass + +@mypyc_attr(native_class=False) +class MyError2(ZeroDivisionError): + def __init__(self, s: str) -> None: + super().__init__(s + "!") + self.x = s.upper() + +def f() -> None: + raise MyError("foobar") + +def test_non_native_exception_subclass_basics() -> None: + e = MyError() + assert isinstance(e, MyError) + assert isinstance(e, ZeroDivisionError) + assert isinstance(e, Exception) + + e = MyError("x") + assert repr(e) == "MyError('x')" + + e2 = MyError2("ab") + assert repr(e2) == "MyError2('ab!')", repr(e2) + assert e2.x == "AB" + +def test_raise_non_native_exception_subclass_1() -> None: + try: + f() + except MyError: + x = True + else: + assert False + assert x + +def test_raise_non_native_exception_subclass_2() -> None: + try: + f() + except ZeroDivisionError: + x = True + else: + assert False + assert x + [case testSubclassPy] from b import B, V class A(B): From 9efa0478557ae17b6536611acb5977a0e1609039 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 4 Jun 2025 17:27:49 +0100 Subject: [PATCH 5/5] Update test --- mypyc/test-data/commandline.test | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypyc/test-data/commandline.test b/mypyc/test-data/commandline.test index ae0be03eb66b..77c2e08bcf34 100644 --- a/mypyc/test-data/commandline.test +++ b/mypyc/test-data/commandline.test @@ -138,7 +138,9 @@ Foo.lol = 50 # E: Only class variables defined as ClassVar can be assigned to def decorator(x: Any) -> Any: return x -class NeverMetaclass(type): # E: Inheriting from most builtin types is unimplemented +class NeverMetaclass(type): # E: Inheriting from most builtin types is unimplemented \ + # N: Potential workaround: @mypy_extensions.mypyc_attr(native_class=False) \ + # N: https://mypyc.readthedocs.io/en/stable/native_classes.html#defining-non-native-classes pass class Concrete1: