fix: correct base filter syntax to Obsidian standard (== and double quotes)

This commit is contained in:
Research Assistant 2026-06-01 11:16:53 +08:00
parent d10c29bd96
commit e269c0b8d8
2 changed files with 50 additions and 12 deletions

View file

@ -74,7 +74,7 @@ def build_base_views(domain: str) -> list[dict]:
{
"name": "待 OCR",
"order": ["year", "first_author", "title", "has_pdf", "do_ocr", "ocr_status", "pdf_path"],
"filter": "do_ocr = true AND ocr_status = 'pending'",
"filter": 'do_ocr == true && ocr_status == "pending"',
},
{
"name": "待深度阅读",
@ -89,12 +89,12 @@ def build_base_views(domain: str) -> list[dict]:
"deep_reading_status",
"pdf_path",
],
"filter": "analyze = true AND ocr_status = 'done' AND deep_reading_status = 'pending'",
"filter": 'analyze == true && ocr_status == "done" && deep_reading_status == "pending"',
},
{
"name": "重做OCR",
"order": ["year", "first_author", "title", "ocr_redo", "ocr_status"],
"filter": "ocr_status = 'done'",
"filter": 'ocr_status == "done"',
},
]
@ -137,7 +137,7 @@ def _render_views_section(views: list[dict]) -> str:
for col in v["order"]:
lines.append(f" - {col}")
if v["filter"]:
lines.append(f' filter: "{v["filter"]}"')
lines.append(f" filter: '{v['filter']}'")
if v.get("sort"):
lines.append(" sort:")
for sort_item in v["sort"]:
@ -285,7 +285,7 @@ views:
for col in v["order"]:
rendered += f" - {col}\n"
if v["filter"]:
rendered += f' filter: "{v["filter"]}"\n'
rendered += f" filter: '{v['filter']}'\n"
else:
rendered += "\n"
if v.get("sort"):
@ -377,7 +377,7 @@ def _build_base_yaml(folder_filter: str, views: list[dict]) -> str:
for col in v["order"]:
views_yaml += f" - {col}\n"
if v["filter"]:
views_yaml += f' filter: "{v["filter"]}"\n'
views_yaml += f" filter: '{v['filter']}'\n"
else:
views_yaml += "\n"
if v.get("sort"):

View file

@ -18,7 +18,7 @@ class TestBuildBaseViews:
redo = next(v for v in views if v["name"] == "重做OCR")
assert redo["order"] == ["year", "first_author", "title", "ocr_redo", "ocr_status"]
assert redo["filter"] == "ocr_status = 'done'"
assert redo["filter"] == 'ocr_status == "done"'
def test_returns_exactly_4_views(self):
views = build_base_views("骨科")
@ -41,15 +41,15 @@ class TestBuildBaseViews:
def test_pending_ocr_filter(self):
views = build_base_views("骨科")
pending = next(v for v in views if v["name"] == "待 OCR")
assert "do_ocr = true" in pending["filter"]
assert "ocr_status = 'pending'" in pending["filter"]
assert "do_ocr == true" in pending["filter"]
assert 'ocr_status == "pending"' in pending["filter"]
def test_deep_reading_pending_filter(self):
views = build_base_views("骨科")
pending = next(v for v in views if v["name"] == "待深度阅读")
assert "analyze = true" in pending["filter"]
assert "ocr_status = 'done'" in pending["filter"]
assert "deep_reading_status = 'pending'" in pending["filter"]
assert "analyze == true" in pending["filter"]
assert 'ocr_status == "done"' in pending["filter"]
assert 'deep_reading_status == "pending"' in pending["filter"]
def test_removed_views_not_present(self):
removed = {"推荐分析", "OCR 完成", "深度阅读完成", "正式卡片", "全记录"}
@ -111,3 +111,41 @@ class TestSubstituteConfigPlaceholders:
lit.mkdir()
result = substitute_config_placeholders(content, {"literature": lit, "vault": vault})
assert "\\" not in result # Should use forward slash
class TestBaseFilterYAMLSyntax:
"""Verify generated Base YAML uses correct Obsidian Base filter syntax."""
def test_all_filters_use_double_equals_and_double_quotes(self):
"""Filter values must use == and " for strings, per Obsidian Base docs."""
views = build_base_views("test")
for v in views:
if not v["filter"]:
continue
f = v["filter"]
assert "=" not in f.replace("==", ""), f"single = in filter: {f}"
assert "'" not in f, f"single quote in filter: {f}"
def test_rendered_yaml_wraps_filter_in_single_quotes(self):
"""YAML output must wrap filter strings in single quotes to protect double quotes inside."""
from paperforge.worker.base_views import _render_views_section
views = build_base_views("test")
yaml_output = _render_views_section(views)
for v in views:
if not v["filter"]:
continue
expected_line = f" filter: '{v['filter']}'"
assert expected_line in yaml_output, (
f"Expected YAML line not found: {expected_line}\nGot:\n{yaml_output}"
)
def test_no_single_quote_in_rendered_filter_value(self):
"""No single quote inside the filter value (would break YAML single-quote wrapping)."""
views = build_base_views("test")
for v in views:
if not v["filter"]:
continue
inner = v["filter"]
assert "'" not in inner, f"single quote inside filter value: {inner}"