Skip to content
Merged
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions pyre/cpython_tests/baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
"reason": "implementation detail"
},
"test.test_code_module": {
"dynasm": "IMPORTERROR"
"dynasm": "PASS"
},
"test.test_codeccallbacks": {
"dynasm": "IMPORTERROR"
Expand Down Expand Up @@ -596,10 +596,10 @@
"dynasm": "IMPORTERROR"
},
"test.test_import": {
"dynasm": "IMPORTERROR"
"dynasm": "PASS"
},
"test.test_importlib": {
"dynasm": "IMPORTERROR"
"dynasm": "PASS"
},
"test.test_index": {
"cranelift": "PASS",
Expand Down Expand Up @@ -727,7 +727,7 @@
"dynasm": "IMPORTERROR"
},
"test.test_modulefinder": {
"dynasm": "IMPORTERROR"
"dynasm": "PASS"
},
"test.test_monitoring": {
"dynasm": "IMPORTERROR"
Expand Down Expand Up @@ -958,7 +958,7 @@
"dynasm": "IMPORTERROR"
},
"test.test_runpy": {
"dynasm": "IMPORTERROR"
"dynasm": "PASS"
},
"test.test_sax": {
"dynasm": "IMPORTERROR"
Expand Down
12 changes: 8 additions & 4 deletions pyre/cpython_tests/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,14 @@ def is_package(module: str) -> bool:
" runpy.run_path({path!r}, run_name='__main__')\n"
)

# These modules assert fully qualified class/enum names. Running their files
# as __main__ changes those names even on CPython, so preserve the dotted
# identity that libregrtest gives them.
DOTTED_IDENTITY_MODULES = {"test.test_descr", "test.test_enum"}
# test_descr and test_enum assert fully qualified class/enum names. Running
# their files as __main__ changes those names even on CPython, so preserve the
# dotted identity that libregrtest gives them.
#
# test_runpy's file as __main__ does not run test_runpy at all — it starts
# libregrtest over the whole suite (measured: 491 modules on CPython 3.14,
# 492 here), so script mode can only ever time out on it.
DOTTED_IDENTITY_MODULES = {"test.test_descr", "test.test_enum", "test.test_runpy"}

# test_datetime's load_tests appends an exhaustive test class for every
# installed system timezone when test.support.use_resources is left as None.
Expand Down
33 changes: 33 additions & 0 deletions pyre/extra_tests/parity_tests/builtin_module_loader_spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import _imp
import sys
from test.support import import_helper


name = "errno"
sys.modules.pop(name, None)

spec = type("Spec", (), {"name": name})()
module = _imp.create_builtin(spec)
assert module.__loader__ is None
assert module.__spec__ is None

sys.modules.pop(name, None)
bootstrap = import_helper.import_fresh_module(
"importlib._bootstrap",
fresh=("importlib",),
blocked=("_frozen_importlib", "_frozen_importlib_external"),
)
loader = bootstrap.BuiltinImporter
module = loader.load_module(name)
assert module.__loader__ is loader
assert module.__spec__.loader is loader

import errno

assert errno.__loader__ is errno.__spec__.loader
assert errno.__loader__ is loader
assert errno.__name__ == name
assert errno.__package__ == ""
assert sys.modules[name] is errno

print("OK")
97 changes: 97 additions & 0 deletions pyre/extra_tests/parity_tests/dict_popitem_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import types


def assert_empty_popitem(d):
try:
d.popitem()
except KeyError as exc:
assert exc.args == ("popitem(): dictionary is empty",)
else:
raise AssertionError("popitem on empty dict did not raise")


def assert_lifo(label, d, expected):
out = []
while d:
out.append(d.popitem())
assert out == expected, (label, out, expected)
assert_empty_popitem(d)


def make_kwargs(**kwargs):
return kwargs


class DictSubclass(dict):
pass


class Carrier:
pass


assert_empty_popitem({})

single = {"only": 1}
assert single.popitem() == ("only", 1)
assert single == {}

reused = {1: "a", 2: "b"}
assert reused.popitem() == (2, "b")
reused[3] = "c"
assert reused.popitem() == (3, "c")
assert reused.popitem() == (1, "a")
assert_empty_popitem(reused)

assert_lifo("int", {1: "a", 2: "b", 3: "c"}, [(3, "c"), (2, "b"), (1, "a")])
assert_lifo("str", {"a": 1, "b": 2, "c": 3}, [("c", 3), ("b", 2), ("a", 1)])
# A bytes-only dict reaches its own strategy arm, which rebuilds the key from
# the stored bytes rather than handing back a stored object.
assert_lifo("bytes", {b"a": 1, b"b": 2, b"c": 3}, [(b"c", 3), (b"b", 2), (b"a", 1)])
assert_lifo("object", {1: "a", "b": 2, (3,): "c"}, [((3,), "c"), ("b", 2), (1, "a")])
Comment thread
coderabbitai[bot] marked this conversation as resolved.

kw = make_kwargs(a=1, b=2, c=3)
assert_lifo("kwargs", kw, [("c", 3), ("b", 2), ("a", 1)])

module_ns = globals()
module_ns["popitem_strategy_mod_a"] = 1
module_ns["popitem_strategy_mod_b"] = 2
assert module_ns.popitem() == ("popitem_strategy_mod_b", 2)
assert module_ns.popitem() == ("popitem_strategy_mod_a", 1)

obj = Carrier()
obj.first = 1
obj.second = 2
surrogate = "\ud800"
setattr(obj, surrogate, 3)
assert obj.__dict__.popitem() == (surrogate, 3)
assert obj.__dict__.popitem() == ("second", 2)
assert obj.__dict__.popitem() == ("first", 1)
assert_empty_popitem(obj.__dict__)

sub = DictSubclass()
sub["x"] = 1
sub["y"] = 2
assert_lifo("subclass", sub, [("y", 2), ("x", 1)])

# A non-str key moves a module dict off cell storage; popitem has a separate
# arm for that storage half, and a reader of a popped global must stop seeing it.
switched = types.ModuleType("popitem_strategy_switched")
exec("def read_g():\n return g\n", switched.__dict__)
read_g = switched.read_g
switched.__dict__[42] = "not a str key"
switched.__dict__["g"] = "before"
assert read_g() == "before"
assert switched.__dict__.popitem() == ("g", "before")
try:
read_g()
except NameError:
pass
else:
raise AssertionError("read_g must not see the popped global")
switched.__dict__["g"] = "after"
assert read_g() == "after"
assert switched.__dict__.popitem() == ("g", "after")
assert switched.__dict__.popitem() == (42, "not a str key")

print("OK")
130 changes: 130 additions & 0 deletions pyre/extra_tests/parity_tests/exception_getattribute_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
SENTINEL = object()


class E(Exception):
calls = 0
getattr_calls = 0

def __getattribute__(self, name):
type(self).calls += 1
if name == "marker":
return SENTINEL
if name == "args":
return ("overridden-args",)
if name == "__traceback__":
return "overridden-traceback"
return super().__getattribute__(name)

def __getattr__(self, name):
type(self).getattr_calls += 1
if name == "fallback":
return "fallback-value"
raise AttributeError(name)


e = E("real-args")
start = E.calls
assert e.marker is SENTINEL
assert E.calls == start + 1

start = E.calls
for _ in range(4000):
assert e.marker is SENTINEL
assert E.calls == start + 4000

assert e.args == ("overridden-args",)
assert e.__traceback__ == "overridden-traceback"
assert e.fallback == "fallback-value"
assert E.getattr_calls == 1
before = E.getattr_calls
assert e.marker is SENTINEL
assert E.getattr_calls == before


class L(list):
calls = 0

def __getattribute__(self, name):
type(self).calls += 1
if name == "marker":
return SENTINEL
return super().__getattribute__(name)


list_subclass = L([1, 2, 3])
assert list_subclass.marker is SENTINEL
assert L.calls == 1

try:
raise E("raised")
except E as raised:
assert raised.marker is SENTINEL
assert raised.args == ("overridden-args",)
assert raised.__traceback__ == "overridden-traceback"


# `__exit__` is handed the traceback the interpreter stored, not whatever the
# override answers for `__traceback__` — the unwinder reads the slot directly.
class Recorder:
seen = None

def __enter__(self):
return self

def __exit__(self, exc_type, exc, tb):
type(self).seen = (exc_type, exc, tb)
return True


with Recorder() as recorder:
raise E("in-with")
seen_type, seen_exc, seen_tb = Recorder.seen
assert seen_type is E
assert isinstance(seen_exc, E)
assert seen_tb is not None
assert seen_tb != "overridden-traceback"
assert type(seen_tb).__name__ == "traceback"
# The override is still what attribute access answers on the same object.
assert seen_exc.__traceback__ == "overridden-traceback"


# Receivers whose builtin type carries a `__getattribute__` of its own read
# their attributes unchanged: super proxies, bound methods, unions, generic
# aliases, weak proxies and struct objects.
class Q:
attr = "q-attr"

def f(self):
return "q-f"


q = Q()
bound = q.f
assert bound.__func__ is Q.f
assert bound.__self__ is q
assert bound() == "q-f"

assert (int | str).__args__ == (int, str)
assert list[int].__origin__ is list

import struct
import weakref

assert struct.Struct("i").size == struct.calcsize("i")
proxy = weakref.proxy(q)
assert proxy.attr == "q-attr"


class Base:
def who(self):
return "base"


class Derived(Base):
def who(self):
return "derived:" + super().who()


assert Derived().who() == "derived:base"

print("OK")
Loading
Loading