Skip to content

Commit a6b55f0

Browse files
BobTheBuidlerKevin Kannammalil
authored andcommitted
feat: new mypyc primitives for weakref.proxy (#19217)
This PR adds 2 new weakref primitives for weakref.proxy (1 and 2 arg) (cherry picked from commit 8f2371a)
1 parent 5a323dd commit a6b55f0

File tree

6 files changed

+128
-12
lines changed

6 files changed

+128
-12
lines changed

mypyc/primitives/weakref_ops.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,21 @@
2020
c_function_name="PyWeakref_NewRef",
2121
error_kind=ERR_MAGIC,
2222
)
23+
24+
new_proxy_op = function_op(
25+
name="_weakref.proxy",
26+
arg_types=[object_rprimitive],
27+
return_type=object_rprimitive,
28+
c_function_name="PyWeakref_NewProxy",
29+
extra_int_constants=[(0, pointer_rprimitive)],
30+
error_kind=ERR_MAGIC,
31+
)
32+
33+
new_proxy_with_callback_op = function_op(
34+
name="_weakref.proxy",
35+
arg_types=[object_rprimitive, object_rprimitive],
36+
# steals=[True, False],
37+
return_type=object_rprimitive,
38+
c_function_name="PyWeakref_NewProxy",
39+
error_kind=ERR_MAGIC,
40+
)

mypyc/test-data/fixtures/ir.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ class RuntimeError(Exception): pass
343343
class UnicodeEncodeError(RuntimeError): pass
344344
class UnicodeDecodeError(RuntimeError): pass
345345
class NotImplementedError(RuntimeError): pass
346+
class ReferenceError(Exception): pass
346347

347348
class StopIteration(Exception):
348349
value: Any

mypyc/test-data/irbuild-weakref.test

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,55 @@ def f(x, cb):
4949
L0:
5050
r0 = PyWeakref_NewRef(x, cb)
5151
return r0
52+
53+
[case testWeakrefProxy]
54+
import weakref
55+
from typing import Any, Callable
56+
def f(x: object) -> object:
57+
return weakref.proxy(x)
58+
59+
[out]
60+
def f(x):
61+
x, r0 :: object
62+
L0:
63+
r0 = PyWeakref_NewProxy(x, 0)
64+
return r0
65+
66+
[case testWeakrefProxyCallback]
67+
import weakref
68+
from typing import Any, Callable
69+
def f(x: object, cb: Callable[[object], Any]) -> object:
70+
return weakref.proxy(x, cb)
71+
72+
[out]
73+
def f(x, cb):
74+
x, cb, r0 :: object
75+
L0:
76+
r0 = PyWeakref_NewProxy(x, cb)
77+
return r0
78+
79+
[case testFromWeakrefProxy]
80+
from typing import Any, Callable
81+
from weakref import proxy
82+
def f(x: object) -> object:
83+
return proxy(x)
84+
85+
[out]
86+
def f(x):
87+
x, r0 :: object
88+
L0:
89+
r0 = PyWeakref_NewProxy(x, 0)
90+
return r0
91+
92+
[case testFromWeakrefProxyCallback]
93+
from typing import Any, Callable
94+
from weakref import proxy
95+
def f(x: object, cb: Callable[[object], Any]) -> object:
96+
return proxy(x, cb)
97+
98+
[out]
99+
def f(x, cb):
100+
x, cb, r0 :: object
101+
L0:
102+
r0 = PyWeakref_NewProxy(x, cb)
103+
return r0

mypyc/test-data/run-weakref.test

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,52 @@
11
# Test cases for weakrefs (compile and run)
22

33
[case testWeakrefRef]
4-
from weakref import ref
4+
# mypy: disable-error-code="union-attr"
5+
from weakref import proxy, ref
56
from mypy_extensions import mypyc_attr
7+
from testutil import assertRaises
8+
from typing import Optional
69

710
@mypyc_attr(native_class=False)
811
class Object:
912
"""some random weakreffable object"""
10-
pass
13+
def some_meth(self) -> int:
14+
return 1
1115

12-
def test_weakref_ref():
13-
obj = Object()
16+
_callback_called_cache = {"ref": False, "proxy": False}
17+
18+
def test_weakref_ref() -> None:
19+
obj: Optional[Object] = Object()
1420
r = ref(obj)
1521
assert r() is obj
1622
obj = None
1723
assert r() is None, r()
1824

19-
def test_weakref_ref_with_callback():
20-
obj = Object()
21-
r = ref(obj, lambda x: x)
25+
def test_weakref_ref_with_callback() -> None:
26+
obj: Optional[Object] = Object()
27+
r = ref(obj, lambda x: _callback_called_cache.__setitem__("ref", True))
2228
assert r() is obj
2329
obj = None
2430
assert r() is None, r()
31+
assert _callback_called_cache["ref"] is True
2532

26-
[file driver.py]
27-
from native import test_weakref_ref, test_weakref_ref_with_callback
33+
def test_weakref_proxy() -> None:
34+
obj: Optional[Object] = Object()
35+
p = proxy(obj)
36+
assert obj.some_meth() == 1
37+
assert p.some_meth() == 1
38+
obj.some_meth()
39+
obj = None
40+
with assertRaises(ReferenceError):
41+
p.some_meth()
2842

29-
test_weakref_ref()
30-
test_weakref_ref_with_callback()
43+
def test_weakref_proxy_with_callback() -> None:
44+
obj: Optional[Object] = Object()
45+
p = proxy(obj, lambda x: _callback_called_cache.__setitem__("proxy", True))
46+
assert obj.some_meth() == 1
47+
assert p.some_meth() == 1
48+
obj.some_meth()
49+
obj = None
50+
with assertRaises(ReferenceError):
51+
p.some_meth()
52+
assert _callback_called_cache["proxy"] is True
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from typing import Any, Callable, TypeVar, overload
2+
from weakref import CallableProxyType, ProxyType
3+
4+
_C = TypeVar("_C", bound=Callable[..., Any])
5+
_T = TypeVar("_T")
6+
7+
# Return CallableProxyType if object is callable, ProxyType otherwise
8+
@overload
9+
def proxy(object: _C, callback: Callable[[CallableProxyType[_C]], Any] | None = None, /) -> CallableProxyType[_C]: ...
10+
@overload
11+
def proxy(object: _T, callback: Callable[[ProxyType[_T]], Any] | None = None, /) -> ProxyType[_T]: ...
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1+
from _weakref import proxy
12
from collections.abc import Callable
2-
from typing import Any, Generic, TypeVar
3+
from typing import Any, ClassVar, Generic, TypeVar, final
34
from typing_extensions import Self
45

6+
_C = TypeVar("_C", bound=Callable[..., Any])
57
_T = TypeVar("_T")
68

79
class ReferenceType(Generic[_T]): # "weakref"
810
__callback__: Callable[[Self], Any]
911
def __new__(cls, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> Self: ...
12+
def __call__(self) -> _T | None: ...
1013

1114
ref = ReferenceType
15+
16+
@final
17+
class CallableProxyType(Generic[_C]): # "weakcallableproxy"
18+
def __eq__(self, value: object, /) -> bool: ...
19+
def __getattr__(self, attr: str) -> Any: ...
20+
__call__: _C
21+
__hash__: ClassVar[None] # type: ignore[assignment]
22+
23+
__all__ = ["proxy"]

0 commit comments

Comments
 (0)