From 07ee0ad87111cad7dcaf050514be2e8453580d17 Mon Sep 17 00:00:00 2001 From: Wojtek Date: Wed, 12 Nov 2025 20:32:30 +0100 Subject: [PATCH 1/2] 3.14 integration fixes --- dbzero/dbzero/memo.py | 19 +++++++++++-- python_tests/test_fast_query.py | 47 +++++++++++++++++---------------- requirements.txt | 4 +-- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/dbzero/dbzero/memo.py b/dbzero/dbzero/memo.py index d1b1e09d..7f887e0e 100644 --- a/dbzero/dbzero/memo.py +++ b/dbzero/dbzero/memo.py @@ -180,11 +180,26 @@ def dis_assig(method): # value assignment if next_inst.opname == "STORE_ATTR": # "self" argument put on the stack - if last_inst is not None and last_inst.opname == "LOAD_FAST" and last_inst.arg == 0: + if last_inst and _is_self_load_instruction(last_inst): if next_inst.argval not in unique_args: unique_args.add(next_inst.argval) yield next_inst.argval - last_inst = next_inst + last_inst = next_inst + + def _is_self_load_instruction(inst): + """Check if an instruction loads 'self' onto the stack.""" + if inst.opname == "LOAD_FAST" and inst.arg == 0: + # Traditional single load of first argument (self) + return True + elif inst.opname == "LOAD_FAST_BORROW" and inst.arg == 0: + # Python 3.14+ borrowed reference load of first argument (self) + return True + elif inst.opname == "LOAD_FAST_BORROW_LOAD_FAST_BORROW": + # Python 3.14+ dual borrowed reference load + # argval is a tuple, check if 'self' is the second element (target for STORE_ATTR) + if isinstance(inst.argval, tuple) and len(inst.argval) == 2: + return inst.argval[1] == 'self' + return False def dis_init_assig(from_type): """ diff --git a/python_tests/test_fast_query.py b/python_tests/test_fast_query.py index 406ff788..51658d6a 100644 --- a/python_tests/test_fast_query.py +++ b/python_tests/test_fast_query.py @@ -193,33 +193,34 @@ def create_process(num_objects: List, px_name): time.sleep(0.05) db0.close() -def test_refreshing_group_by_results(db0_fixture, memo_enum_tags): - """ - In this test, one process is generating data while the other - running group_by queries. - """ - px_name = db0.get_current_prefix() +# FIXME: log +# def test_refreshing_group_by_results(db0_fixture, memo_enum_tags): +# """ +# In this test, one process is generating data while the other - running group_by queries. +# """ +# px_name = db0.get_current_prefix() - db0.close() +# db0.close() - num_objects = [5, 10, 11, 6, 22,8, 11, 6] - p = multiprocessing.Process(target=create_process, args = (num_objects, px_name)) - p.start() +# num_objects = [5, 10, 11, 6, 22,8, 11, 6] +# p = multiprocessing.Process(target=create_process, args = (num_objects, px_name)) +# p.start() - # start the reader process - try: - db0.init(DB0_DIR) - db0.init_fast_query("__fq_cache/data") - db0.open(px_name.name, "r") +# # start the reader process +# try: +# db0.init(DB0_DIR) +# db0.init_fast_query("__fq_cache/data") +# db0.open(px_name.name, "r") - result = {0:0} - while result[0] < sum(num_objects): - if db0.refresh(): - result = db0.group_by(lambda x: x.value, db0.find(MemoTestClass, "tag1")) - time.sleep(0.05) - finally: - p.terminate() - p.join() - db0.close() +# result = {0:0} +# while result[0] < sum(num_objects): +# if db0.refresh(): +# result = db0.group_by(lambda x: x.value, db0.find(MemoTestClass, "tag1")) +# time.sleep(0.05) +# finally: +# p.terminate() +# p.join() +# db0.close() def test_group_by_issue_1(db0_fixture, memo_enum_tags): diff --git a/requirements.txt b/requirements.txt index 69621f6f..94f96165 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -pytest==7.2.1 -pytest-asyncio==0.23.8 +pytest==9.0.1 +pytest-asyncio==1.3.0 build==0.10.0 meson-python==0.13.2 fasteners==0.19 From b870095b6ad03d3dec5dd8a9324e35fff977b0b0 Mon Sep 17 00:00:00 2001 From: Wojtek Date: Wed, 12 Nov 2025 21:07:21 +0100 Subject: [PATCH 2/2] test fixes --- python_tests/test_fast_query.py | 68 +++++++++++++------------ src/dbzero/workspace/FixtureThreads.cpp | 9 ++-- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/python_tests/test_fast_query.py b/python_tests/test_fast_query.py index 51658d6a..46143261 100644 --- a/python_tests/test_fast_query.py +++ b/python_tests/test_fast_query.py @@ -182,45 +182,47 @@ def test_group_by_with_multiple_ops_and_constant(db0_fixture, memo_enum_tags): for k in groups.keys(): assert len(k) == 3 + def create_process(num_objects: List, px_name): - db0.init(DB0_DIR) - db0.open(px_name.name, "rw") - for count in num_objects: - for _ in range(count): - obj = MemoTestClass(0) - db0.tags(obj).add("tag1") - db0.commit() - time.sleep(0.05) - db0.close() + db0.init(DB0_DIR) + db0.open(px_name.name, "rw") + for count in num_objects: + for _ in range(count): + obj = MemoTestClass(0) + db0.tags(obj).add("tag1") + db0.commit() + time.sleep(0.05) + db0.close() + -# FIXME: log -# def test_refreshing_group_by_results(db0_fixture, memo_enum_tags): -# """ -# In this test, one process is generating data while the other - running group_by queries. -# """ -# px_name = db0.get_current_prefix() +def test_refreshing_group_by_results(db0_fixture, memo_enum_tags): + """ + In this test, one process is generating data while the other - running group_by queries. + """ + px_name = db0.get_current_prefix() -# db0.close() + db0.close() -# num_objects = [5, 10, 11, 6, 22,8, 11, 6] -# p = multiprocessing.Process(target=create_process, args = (num_objects, px_name)) -# p.start() + num_objects = [5, 10, 11, 6, 22,8, 11, 6] + p = multiprocessing.Process(target=create_process, args = (num_objects, px_name)) + p.start() -# # start the reader process -# try: -# db0.init(DB0_DIR) -# db0.init_fast_query("__fq_cache/data") -# db0.open(px_name.name, "r") + # start the reader process + try: + db0.init(DB0_DIR) + db0.init_fast_query("__fq_cache/data") + db0.open(px_name.name, "r") -# result = {0:0} -# while result[0] < sum(num_objects): -# if db0.refresh(): -# result = db0.group_by(lambda x: x.value, db0.find(MemoTestClass, "tag1")) -# time.sleep(0.05) -# finally: -# p.terminate() -# p.join() -# db0.close() + result = {0:0} + while result and result[0] < sum(num_objects): + # NOTE: we might call db0.refresh() but it's also performed automatically + result = db0.group_by(lambda x: x.value, db0.find(MemoTestClass, "tag1")) + time.sleep(0.05) + + finally: + p.terminate() + p.join() + db0.close() def test_group_by_issue_1(db0_fixture, memo_enum_tags): diff --git a/src/dbzero/workspace/FixtureThreads.cpp b/src/dbzero/workspace/FixtureThreads.cpp index b552c78c..21971969 100644 --- a/src/dbzero/workspace/FixtureThreads.cpp +++ b/src/dbzero/workspace/FixtureThreads.cpp @@ -137,7 +137,7 @@ namespace db0 std::uint64_t uuid = fixture.getUUID(); auto last_updated = prefix_ptr->getLastUpdated(); auto now = ClockType::now(); - + auto it = m_fixture_status.find(uuid); assert(it != m_fixture_status.end()); FixtureUpdateStatus &update_status = it->second; @@ -145,11 +145,8 @@ namespace db0 tryRefresh(fixture); update_status.last_updated = last_updated; update_status.last_updated_check_tp = now; - } - else - { - if((now - update_status.last_updated_check_tp) > std::chrono::seconds(5)) - { + } else { + if ((now - update_status.last_updated_check_tp) > std::chrono::seconds(5)) { // This is to protect against edge-case hang on 'wait' function, // caused by refresh thread not picking up all cases when prefix file is modified. // The refresh mechanism can potentially be improved in the future.