Skip to content

feat: new mypyc primitives for weakref.proxy #19217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions mypyc/primitives/weakref_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,21 @@
c_function_name="PyWeakref_NewRef",
error_kind=ERR_MAGIC,
)

new_proxy_op = function_op(
name="_weakref.proxy",
arg_types=[object_rprimitive],
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,
)
52 changes: 52 additions & 0 deletions mypyc/test-data/irbuild-weakref.test
Original file line number Diff line number Diff line change
Expand Up @@ -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
70 changes: 67 additions & 3 deletions mypyc/test-data/run-weakref.test
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
Expand All @@ -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()
11 changes: 11 additions & 0 deletions test-data/unit/lib-stub/_weakref.pyi
Original file line number Diff line number Diff line change
@@ -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: ...
13 changes: 12 additions & 1 deletion test-data/unit/lib-stub/weakref.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
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"
__callback__: Callable[[Self], Any]
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"]
Loading