From d29eab8717564ae51969f3b7760f8bf5c16919d4 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 01/10] add tests --- mypyc/test-data/run-weakref.test | 70 ++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test index 902c9e407ff4..892c29c50521 100644 --- a/mypyc/test-data/run-weakref.test +++ b/mypyc/test-data/run-weakref.test @@ -7,7 +7,6 @@ from mypy_extensions import mypyc_attr @mypyc_attr(native_class=False) class Object: """some random weakreffable object""" - pass def test_weakref_ref(): obj = Object() @@ -16,6 +15,20 @@ def test_weakref_ref(): obj = None assert r() is None, r() +[file driver.py] +from native import test_weakref_ref + +test_weakref_ref() + + +[case testWeakrefRefWithCallback] +from weakref import ref +from mypy_extensions import mypyc_attr + +@mypyc_attr(native_class=False) +class Object: + """some random weakreffable object""" + def test_weakref_ref_with_callback(): obj = Object() r = ref(obj, lambda x: x) @@ -24,7 +37,58 @@ def test_weakref_ref_with_callback(): assert r() is None, r() [file driver.py] -from native import test_weakref_ref, test_weakref_ref_with_callback +from native import test_weakref_ref_with_callback -test_weakref_ref() test_weakref_ref_with_callback() + + +[case testWeakrefProxy] +import pytest # type: ignore [import-not-found] +from weakref import proxy +from mypy_extensions import mypyc_attr + +@mypyc_attr(native_class=False) +class Object: + """some random weakreffable object""" + def some_meth(self) -> int: + return 1 + +def test_weakref_proxy(): + obj = Object() + p = proxy(obj) + assert obj.some_meth() == 1 + assert p.some_meth() == 1 + obj = None + with pytest.raises(ReferenceError): + p.some_meth() + +[file driver.py] +from native import test_weakref_proxy + +test_weakref_proxy() + + +[case testWeakrefProxyWithCallback] +import pytest # type: ignore [import-not-found] +from weakref import proxy +from mypy_extensions import mypyc_attr + +@mypyc_attr(native_class=False) +class Object: + """some random weakreffable object""" + def some_meth(self) -> int: + return 1 + +def test_weakref_proxy_with_callback(): + obj = Object() + p = proxy(obj, lambda x: x) + assert obj.some_meth() == 1 + assert p.some_meth() == 1 + obj = None + with pytest.raises(ReferenceError): + p.some_meth() + +[file driver.py] +from native import test_weakref_proxy_with_callback + +test_weakref_proxy_with_callback() From d043cda4bb5777cfa68ab5f2f566736268d0b73b Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 02/10] _weakref stubs --- test-data/unit/lib-stub/_weakref.pyi | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 test-data/unit/lib-stub/_weakref.pyi diff --git a/test-data/unit/lib-stub/_weakref.pyi b/test-data/unit/lib-stub/_weakref.pyi new file mode 100644 index 000000000000..70012375e645 --- /dev/null +++ b/test-data/unit/lib-stub/_weakref.pyi @@ -0,0 +1,11 @@ +from typing import Any, Callable, TypeVar, overload +from weakref import CallableProxyType + +_C = TypeVar("_C", bound=Callable[..., Any]) +_T = TypeVar("_T") + +# Return CallableProxyType if object is callable, ProxyType otherwise +@overload +def proxy(object: _C, callback: Callable[[_C], Any] | None = None, /) -> CallableProxyType[_C]: ... +@overload +def proxy(object: _T, callback: Callable[[_T], Any] | None = None, /) -> Any: ... From 81760b2eaa3e1783cb6025cc54df4e1405d79089 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 03/10] weakref stubs --- test-data/unit/lib-stub/weakref.pyi | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test-data/unit/lib-stub/weakref.pyi b/test-data/unit/lib-stub/weakref.pyi index 34e01f4d48f1..f26a52f351a3 100644 --- a/test-data/unit/lib-stub/weakref.pyi +++ b/test-data/unit/lib-stub/weakref.pyi @@ -1,7 +1,9 @@ +from _weakref import proxy from collections.abc import Callable -from typing import Any, Generic, TypeVar +from typing import Any, ClassVar, Generic, TypeVar, final from typing_extensions import Self +_C = TypeVar("_C", bound=Callable[..., Any]) _T = TypeVar("_T") class ReferenceType(Generic[_T]): # "weakref" @@ -9,3 +11,12 @@ class ReferenceType(Generic[_T]): # "weakref" def __new__(cls, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> Self: ... ref = ReferenceType + +@final +class CallableProxyType(Generic[_C]): # "weakcallableproxy" + def __eq__(self, value: object, /) -> bool: ... + def __getattr__(self, attr: str) -> Any: ... + __call__: _C + __hash__: ClassVar[None] # type: ignore[assignment] + +__all__ = ["proxy"] From e7906258287b1cdddcb0e626b54cd82bbdbc8dcf Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 04/10] feat: new primitive for weakref.ref --- mypyc/test-data/run-weakref.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test index 892c29c50521..1a95d6fbe4ff 100644 --- a/mypyc/test-data/run-weakref.test +++ b/mypyc/test-data/run-weakref.test @@ -1,6 +1,7 @@ # Test cases for weakrefs (compile and run) [case testWeakrefRef] +import pytest # type: ignore [import-not-found] from weakref import ref from mypy_extensions import mypyc_attr From 1bcc358f31a51412dc5474024f94307f741b210f Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 05/10] feat(test): test ir --- mypyc/test-data/irbuild-weakref.test | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/mypyc/test-data/irbuild-weakref.test b/mypyc/test-data/irbuild-weakref.test index 58ac6417d297..2180b1e747aa 100644 --- a/mypyc/test-data/irbuild-weakref.test +++ b/mypyc/test-data/irbuild-weakref.test @@ -49,3 +49,55 @@ def f(x, cb): L0: r0 = PyWeakref_NewRef(x, cb) return r0 + +[case testWeakrefProxy] +import weakref +from typing import Any, Callable +def f(x: object) -> object: + return weakref.proxy(x) + +[out] +def f(x): + x, r0 :: object +L0: + r0 = PyWeakref_NewProxy(x, 0) + return r0 + +[case testWeakrefProxyCallback] +import weakref +from typing import Any, Callable +def f(x: object, cb: Callable[[object], Any]) -> object: + return weakref.proxy(x, cb) + +[out] +def f(x, cb): + x, cb, r0 :: object +L0: + r0 = PyWeakref_NewProxy(x, cb) + return r0 + +[case testFromWeakrefProxy] +from typing import Any, Callable +from weakref import proxy +def f(x: object) -> object: + return proxy(x) + +[out] +def f(x): + x, r0 :: object +L0: + r0 = PyWeakref_NewProxy(x, 0) + return r0 + +[case testFromWeakrefProxyCallback] +from typing import Any, Callable +from weakref import proxy +def f(x: object, cb: Callable[[object], Any]) -> object: + return proxy(x, cb) + +[out] +def f(x, cb): + x, cb, r0 :: object +L0: + r0 = PyWeakref_NewProxy(x, cb) + return r0 From 996987c81bac8b4a3bc230986174b94c069fb1df Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 06/10] fix: steal maybe --- mypyc/primitives/weakref_ops.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mypyc/primitives/weakref_ops.py b/mypyc/primitives/weakref_ops.py index a7ac035b22a4..48bcdb829cee 100644 --- a/mypyc/primitives/weakref_ops.py +++ b/mypyc/primitives/weakref_ops.py @@ -20,3 +20,22 @@ c_function_name="PyWeakref_NewRef", error_kind=ERR_MAGIC, ) + +new_proxy_op = function_op( + name="_weakref.proxy", + arg_types=[object_rprimitive], + steals=[True], + return_type=object_rprimitive, + c_function_name="PyWeakref_NewProxy", + extra_int_constants=[(0, pointer_rprimitive)], + error_kind=ERR_MAGIC, +) + +new_proxy_with_callback_op = function_op( + name="_weakref.proxy", + arg_types=[object_rprimitive, object_rprimitive], + steals=[True, False], + return_type=object_rprimitive, + c_function_name="PyWeakref_NewProxy", + error_kind=ERR_MAGIC, +) From 3bcada69bbbb951d2b298d39e33cdab97cac3798 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 07/10] feat(test): split up run tests --- mypyc/test-data/run-weakref.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test index 1a95d6fbe4ff..892c29c50521 100644 --- a/mypyc/test-data/run-weakref.test +++ b/mypyc/test-data/run-weakref.test @@ -1,7 +1,6 @@ # Test cases for weakrefs (compile and run) [case testWeakrefRef] -import pytest # type: ignore [import-not-found] from weakref import ref from mypy_extensions import mypyc_attr From 9d6c52ccae94eba732d8eb063be351f5a98502de Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 08/10] Update weakref_ops.py --- mypyc/primitives/weakref_ops.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypyc/primitives/weakref_ops.py b/mypyc/primitives/weakref_ops.py index 48bcdb829cee..85e07cdb85b7 100644 --- a/mypyc/primitives/weakref_ops.py +++ b/mypyc/primitives/weakref_ops.py @@ -24,7 +24,6 @@ new_proxy_op = function_op( name="_weakref.proxy", arg_types=[object_rprimitive], - steals=[True], return_type=object_rprimitive, c_function_name="PyWeakref_NewProxy", extra_int_constants=[(0, pointer_rprimitive)], From 1c96658793574f49d2e33a954f1790d0200d2b84 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 09/10] finalize PR --- mypyc/primitives/weakref_ops.py | 2 +- mypyc/test-data/fixtures/test-weakref.pyi | 10 ++++++++++ mypyc/test-data/run-weakref.test | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 mypyc/test-data/fixtures/test-weakref.pyi diff --git a/mypyc/primitives/weakref_ops.py b/mypyc/primitives/weakref_ops.py index 85e07cdb85b7..f7a7406db8f9 100644 --- a/mypyc/primitives/weakref_ops.py +++ b/mypyc/primitives/weakref_ops.py @@ -33,7 +33,7 @@ new_proxy_with_callback_op = function_op( name="_weakref.proxy", arg_types=[object_rprimitive, object_rprimitive], - steals=[True, False], + #steals=[True, False], return_type=object_rprimitive, c_function_name="PyWeakref_NewProxy", error_kind=ERR_MAGIC, diff --git a/mypyc/test-data/fixtures/test-weakref.pyi b/mypyc/test-data/fixtures/test-weakref.pyi new file mode 100644 index 000000000000..80525fe07d6a --- /dev/null +++ b/mypyc/test-data/fixtures/test-weakref.pyi @@ -0,0 +1,10 @@ +class dict: ... +class ellipsis: ... +class int: ... +class str: ... +class tuple: ... +class type: ... +class list: ... +class BaseException: ... +class Exception(BaseException): ... +class ReferenceError(Exception): ... \ No newline at end of file diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test index 892c29c50521..0b070b1567fb 100644 --- a/mypyc/test-data/run-weakref.test +++ b/mypyc/test-data/run-weakref.test @@ -58,10 +58,12 @@ def test_weakref_proxy(): p = proxy(obj) assert obj.some_meth() == 1 assert p.some_meth() == 1 + obj.some_meth() obj = None with pytest.raises(ReferenceError): p.some_meth() +[builtins fixtures/test-weakref.pyi] [file driver.py] from native import test_weakref_proxy @@ -84,10 +86,12 @@ def test_weakref_proxy_with_callback(): p = proxy(obj, lambda x: x) assert obj.some_meth() == 1 assert p.some_meth() == 1 + obj.some_meth() obj = None with pytest.raises(ReferenceError): p.some_meth() +[builtins fixtures/test-weakref.pyi] [file driver.py] from native import test_weakref_proxy_with_callback From 652de32a9f2d68cf2fb974c787ea46f5e9af072d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 01:59:22 +0000 Subject: [PATCH 10/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/primitives/weakref_ops.py | 2 +- mypyc/test-data/fixtures/test-weakref.pyi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mypyc/primitives/weakref_ops.py b/mypyc/primitives/weakref_ops.py index f7a7406db8f9..21379d3b2c82 100644 --- a/mypyc/primitives/weakref_ops.py +++ b/mypyc/primitives/weakref_ops.py @@ -33,7 +33,7 @@ new_proxy_with_callback_op = function_op( name="_weakref.proxy", arg_types=[object_rprimitive, object_rprimitive], - #steals=[True, False], + # steals=[True, False], return_type=object_rprimitive, c_function_name="PyWeakref_NewProxy", error_kind=ERR_MAGIC, diff --git a/mypyc/test-data/fixtures/test-weakref.pyi b/mypyc/test-data/fixtures/test-weakref.pyi index 80525fe07d6a..73896835114b 100644 --- a/mypyc/test-data/fixtures/test-weakref.pyi +++ b/mypyc/test-data/fixtures/test-weakref.pyi @@ -7,4 +7,4 @@ class type: ... class list: ... class BaseException: ... class Exception(BaseException): ... -class ReferenceError(Exception): ... \ No newline at end of file +class ReferenceError(Exception): ...