From 6f8707c35967dff12632ea88a55d4d9c40bcd8fa Mon Sep 17 00:00:00 2001 From: Thor Whalen <1906276+thorwhalen@users.noreply.github.com> Date: Tue, 23 Jun 2026 22:54:17 +0200 Subject: [PATCH] Fix filter_regex on Windows: compile as a regex, not a path template filter_regex compiled its pattern with safe_compile, which is meant for file-path templates and re.escape's its input on Windows. That turned a real regex like (\.json)$ into a literal-string matcher, so EVERY regex key-filter was broken on Windows -- most visibly filter_suffixes('.json'), which backs dol.Jsons: no *.json key matched, and any write/read raised `KeyError: 'Key not in store: .json'`. Use re.compile (filter_regex's argument is a regex, by contract). safe_compile is unchanged and still used for actual path templates (mk_pattern_from_template...), where its Windows escaping is correct. Behavior on macOS/Linux is unchanged (safe_compile's normpath was a no-op for these patterns). Adds an OS-independent regression test (simulates Linux/Darwin/Windows). Claude-Session: https://claude.ai/code/session_019bFtivmtdcXDoCQt3B9gGp --- dol/tests/test_trans.py | 34 +++++++++++++++++++++++++++++++++- dol/trans.py | 14 +++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/dol/tests/test_trans.py b/dol/tests/test_trans.py index 6248d7c0..6494f1ca 100644 --- a/dol/tests/test_trans.py +++ b/dol/tests/test_trans.py @@ -1,6 +1,38 @@ """Test trans.py functionality.""" -from dol.trans import filt_iter, redirect_getattr_to_getitem +import dol.util +from dol.trans import ( + filt_iter, + filter_prefixes, + filter_regex, + filter_suffixes, + redirect_getattr_to_getitem, +) + + +def test_filter_regex_is_os_independent(): + """Regex filters must compile as REGEXES, not as path templates. + + Regression for a Windows-only bug: ``filter_regex`` used the path-oriented + ``safe_compile``, which ``re.escape``s its input on Windows. That turned a + pattern like ``(\\.json)$`` into a literal matcher, so ``filter_suffixes('.json')`` + rejected every ``*.json`` key on Windows and ``dol.Jsons`` raised + ``KeyError: 'Key not in store: .json'`` on write. + """ + real_system = dol.util.platform.system + try: + # Simulate every platform, including Windows (the broken one). + for system in ("Linux", "Darwin", "Windows"): + dol.util.platform.system = lambda system=system: system + assert bool(filter_regex(r"(\.json)$")("doc-001.json")) is True + assert bool(filter_regex(r"(\.json)$")("doc-001.txt")) is False + assert bool(filter_suffixes(".json")("doc-001.json")) is True + assert bool(filter_suffixes([".txt", ".doc"])("report.doc")) is True + assert bool(filter_suffixes(".json")("doc-001.txt")) is False + assert bool(filter_prefixes("test")("test_image.jpg")) is True + assert bool(filter_prefixes("test")("report.doc")) is False + finally: + dol.util.platform.system = real_system def test_filt_iter(): diff --git a/dol/trans.py b/dol/trans.py index 3390d7ba..beb883f8 100644 --- a/dol/trans.py +++ b/dol/trans.py @@ -1481,9 +1481,21 @@ def filter_regex(regex, *, return_search_func=False): >>> is_txt("report.doc") False + The argument is a *regular expression*, so it is compiled with ``re.compile`` + -- NOT ``safe_compile`` (which is for file-path templates and ``re.escape``s its + input on Windows). Using ``safe_compile`` here silently broke every regex filter + on Windows: e.g. ``filter_suffixes('.json')`` (used by ``Jsons``) had its + ``(\.json)$`` pattern escaped into a literal string matcher, so no ``*.json`` key + matched and the store raised ``KeyError: 'Key not in store: .json'``. + + >>> is_json = filter_regex(r"(\.json)$") # works identically on every OS + >>> is_json("doc-001.json") + True + >>> is_json("doc-001.txt") + False """ if isinstance(regex, str): - regex = safe_compile(regex) + regex = re.compile(regex) if return_search_func: return regex.search else: