Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d29eab8
add tests
BobTheBuidler Aug 4, 2025
d043cda
_weakref stubs
BobTheBuidler Aug 4, 2025
81760b2
weakref stubs
BobTheBuidler Aug 4, 2025
e790625
feat: new primitive for weakref.ref
BobTheBuidler Aug 4, 2025
1bcc358
feat(test): test ir
BobTheBuidler Aug 4, 2025
996987c
fix: steal maybe
BobTheBuidler Aug 4, 2025
3bcada6
feat(test): split up run tests
BobTheBuidler Aug 4, 2025
9d6c52c
Update weakref_ops.py
BobTheBuidler Aug 4, 2025
1c96658
finalize PR
BobTheBuidler Aug 4, 2025
652de32
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 4, 2025
28129f3
Merge branch 'master' into weak-proxy
BobTheBuidler Aug 6, 2025
c58f827
Merge branch 'master' into weak-proxy
BobTheBuidler Aug 10, 2025
5f13dbf
Merge branch 'master' into weak-proxy
BobTheBuidler Aug 13, 2025
d6b8d6b
Merge branch 'master' into weak-proxy
BobTheBuidler Aug 14, 2025
23d89a2
rip out pytest.raises
BobTheBuidler Aug 17, 2025
c4f596e
rip out driver.py
BobTheBuidler Aug 17, 2025
fe03dd6
combine run tests
BobTheBuidler Aug 17, 2025
2667ae8
test callback is called
BobTheBuidler Aug 17, 2025
4d39829
Update run-weakref.test
BobTheBuidler Aug 17, 2025
54cbf90
Merge branch 'master' into weak-proxy
BobTheBuidler Aug 18, 2025
78694f3
Update run-weakref.test
BobTheBuidler Aug 18, 2025
5c9cab5
Update run-weakref.test
BobTheBuidler Aug 18, 2025
92a1f8a
Merge branch 'master' into weak-proxy
BobTheBuidler Aug 27, 2025
da8e23a
remove test-weakref.pyi
BobTheBuidler Aug 29, 2025
9fa4a16
Merge branch 'weak-proxy' of https://github.com/BobTheBuidler/mypy in…
BobTheBuidler Aug 29, 2025
05513a8
add type annotations
BobTheBuidler Sep 2, 2025
fd7632c
add `ReferenceType.__call__` to stubs
BobTheBuidler Sep 4, 2025
5eaaefe
Merge branch 'master' into weak-proxy
BobTheBuidler Sep 4, 2025
fb9e02d
fix mypy errs
BobTheBuidler Sep 4, 2025
8f5bf72
disable error code union-attr
BobTheBuidler Sep 4, 2025
5563d05
fix: use Optional instead of |
BobTheBuidler Sep 4, 2025
796d5ce
fix stubs
BobTheBuidler Sep 5, 2025
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,
)
10 changes: 10 additions & 0 deletions mypyc/test-data/fixtures/test-weakref.pyi
Original file line number Diff line number Diff line change
@@ -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): ...
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixture is probably causing the problems -- some of these definitions are too simplified (or missing). If ReferenceError is the only new thing you need here, what about adding it to the generic ir.py?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I saw a comment somewhere indicating not to add things to that file as it would slow down the whole suite.

No worries, I've updated the PR accordingly and the tests pass now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we prefer not to add too many things to the file, but sometimes it's just too much effort to avoid doing this.

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
74 changes: 71 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,62 @@ 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.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

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.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

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