import io
import sys
import threading
import time
import pytest
from mrrc import MARCReader
@pytest.fixture
def suppress_auto_switching():
original = sys.getswitchinterval()
sys.setswitchinterval(100.0)
yield
sys.setswitchinterval(original)
@pytest.fixture
def mrc_file(fixture_1k, tmp_path):
path = tmp_path / "gil_test.mrc"
path.write_bytes(fixture_1k)
return path
def _run_with_counter_thread(iterate_fn):
counter = [0]
stop = threading.Event()
def count_loop():
while not stop.is_set():
counter[0] += 1
time.sleep(0)
t = threading.Thread(target=count_loop, daemon=True)
t.start()
record_count = iterate_fn()
stop.set()
t.join(timeout=2.0)
return counter[0], record_count
class TestGILReleaseVerification:
def test_rustfile_releases_gil(self, suppress_auto_switching, mrc_file):
reader = MARCReader(str(mrc_file))
assert reader.backend_type == "rust_file"
def iterate():
count = 0
for _ in reader:
count += 1
return count
counter, record_count = _run_with_counter_thread(iterate)
assert record_count == 1000
assert counter > 0, "Counter thread never ran — GIL was not released"
def test_cursor_releases_gil(self, suppress_auto_switching, fixture_1k):
reader = MARCReader(fixture_1k)
assert reader.backend_type == "cursor"
def iterate():
count = 0
for _ in reader:
count += 1
return count
counter, record_count = _run_with_counter_thread(iterate)
assert record_count == 1000
assert counter > 0, "Counter thread never ran — GIL was not released"
def test_python_file_releases_gil(self, suppress_auto_switching, fixture_1k):
reader = MARCReader(io.BytesIO(fixture_1k))
assert reader.backend_type == "python_file"
def iterate():
count = 0
for _ in reader:
count += 1
return count
counter, record_count = _run_with_counter_thread(iterate)
assert record_count == 1000
assert counter > 0, "Counter thread never ran — GIL was not released"