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..46143261 100644 --- a/python_tests/test_fast_query.py +++ b/python_tests/test_fast_query.py @@ -182,16 +182,18 @@ 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() + def test_refreshing_group_by_results(db0_fixture, memo_enum_tags): """ @@ -212,10 +214,11 @@ def test_refreshing_group_by_results(db0_fixture, memo_enum_tags): 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")) + 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() 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 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.