Skip to content

Commit c179f0c

Browse files
committed
fix(ru-exporter): restore missing sc_pli2ru_dpd_json path in paths_ru.py and update sutta central ru exporter
1 parent 50c362a commit c179f0c

3 files changed

Lines changed: 62 additions & 18 deletions

File tree

exporter/sutta_central/sutta_central_exporter_ru.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from tools.pali_sort_key import pali_sort_key
3737
from tools.pali_text_files import sc_texts
3838
from tools.paths import ProjectPaths
39+
from tools.paths_ru import RuPaths
3940
from tools.printer import printer as pr
4041
from tools.tools_for_ru_exporter import ru_replace_abbreviations
4142

@@ -44,6 +45,7 @@
4445

4546
class SuttaCentralExporterRu:
4647
pth: ProjectPaths = ProjectPaths()
48+
ru_pth: RuPaths = RuPaths()
4749
db_session: Session = get_db_session(pth.dpd_db_path)
4850

4951
sc_books_list = [
@@ -255,8 +257,8 @@ def save_sc_dict(self):
255257
"""Save to JSON."""
256258

257259
pr.green_tmr("saving sc dict")
258-
self.pth.sc_pli2ru_dpd_json.parent.mkdir(parents=True, exist_ok=True)
259-
with open(self.pth.sc_pli2ru_dpd_json, "w") as f:
260+
self.ru_pth.sc_pli2ru_dpd_json.parent.mkdir(parents=True, exist_ok=True)
261+
with open(self.ru_pth.sc_pli2ru_dpd_json, "w", encoding="utf-8") as f:
260262
dump(self.sc_dict_compiled, f, ensure_ascii=False, indent=2)
261263
pr.yes("OK")
262264

tests/test_sutta_central_exporter_ru.py

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
import json
1010
from io import StringIO
11-
from pathlib import Path
12-
from unittest.mock import MagicMock, call, patch
11+
from typing import Any
12+
from unittest.mock import MagicMock, patch
1313

1414
import pytest
1515

@@ -21,12 +21,14 @@
2121
# Helpers
2222
# ---------------------------------------------------------------------------
2323

24-
def _bare(with_ai: bool = False, with_eng_fallback: bool = False) -> SuttaCentralExporterRu:
24+
25+
def _bare(with_ai: bool = False, with_eng_fallback: bool = False) -> Any:
2526
"""Return a SuttaCentralExporterRu instance without running __init__."""
2627
inst = object.__new__(SuttaCentralExporterRu)
2728
inst.with_ai = with_ai
2829
inst.with_eng_fallback = with_eng_fallback
2930
inst.pth = MagicMock()
31+
inst.ru_pth = MagicMock()
3032
inst.db_session = MagicMock()
3133
inst.sc_word_set = set()
3234
inst.lookup_dict = {}
@@ -70,6 +72,7 @@ def _lookup(headword_ids=None, deconstructions=None):
7072
# flip()
7173
# ---------------------------------------------------------------------------
7274

75+
7376
class TestFlip:
7477
def setup_method(self):
7578
self.inst = _bare()
@@ -146,28 +149,39 @@ def test_ru_meaning_with_literal_and_construction(self, _abbr):
146149
def test_empty_ru_meaning_lit_excluded(self, _abbr):
147150
"""Empty ru_meaning_lit (falsy) must not add '; досл.' clause."""
148151
inst = _bare()
149-
result = inst.make_sc_headword_entry(_hw(ru=_ru(ru_meaning="учение", ru_meaning_lit="")))
152+
result = inst.make_sc_headword_entry(
153+
_hw(ru=_ru(ru_meaning="учение", ru_meaning_lit=""))
154+
)
150155
assert "досл." not in result
151156
assert result == "сущ. <b>учение</b>"
152157

153158
@patch(f"{MODULE}.ru_replace_abbreviations", return_value="гл")
154159
def test_ai_entry_when_ai_enabled(self, _abbr):
155160
inst = _bare(with_ai=True)
156-
result = inst.make_sc_headword_entry(_hw(pos="verb", ru=_ru(ru_meaning_raw="понимать")))
161+
result = inst.make_sc_headword_entry(
162+
_hw(pos="verb", ru=_ru(ru_meaning_raw="понимать"))
163+
)
157164
assert result == "гл. <i>[пер. ИИ]</i> понимать"
158165

159166
@patch(f"{MODULE}.ru_replace_abbreviations", return_value="гл")
160167
def test_ai_entry_returns_none_when_ai_disabled(self, _abbr):
161168
inst = _bare(with_ai=False)
162-
result = inst.make_sc_headword_entry(_hw(pos="verb", ru=_ru(ru_meaning_raw="понимать")))
169+
result = inst.make_sc_headword_entry(
170+
_hw(pos="verb", ru=_ru(ru_meaning_raw="понимать"))
171+
)
163172
assert result is None
164173

165174
@patch(f"{MODULE}.ru_replace_abbreviations", return_value="гл")
166175
def test_ai_entry_includes_construction(self, _abbr):
167176
inst = _bare(with_ai=True)
168177
result = inst.make_sc_headword_entry(
169-
_hw(pos="verb", ru=_ru(ru_meaning_raw="понимать"), construction_summary="pa + jānā")
178+
_hw(
179+
pos="verb",
180+
ru=_ru(ru_meaning_raw="понимать"),
181+
construction_summary="pa + jānā",
182+
)
170183
)
184+
assert result is not None
171185
assert "[pa + jānā]" in result
172186

173187
@patch(f"{MODULE}.make_meaning_combo", return_value="teaching; law")
@@ -189,14 +203,19 @@ def test_eng_fallback_returns_none_when_disabled(self, _abbr):
189203
@patch(f"{MODULE}.ru_replace_abbreviations", return_value="сущ")
190204
def test_eng_fallback_includes_construction(self, _abbr, _combo):
191205
inst = _bare(with_eng_fallback=True)
192-
result = inst.make_sc_headword_entry(_hw(ru=None, construction_summary="dhā + ma"))
206+
result = inst.make_sc_headword_entry(
207+
_hw(ru=None, construction_summary="dhā + ma")
208+
)
209+
assert result is not None
193210
assert "[dhā + ma]" in result
194211

195212
@patch(f"{MODULE}.ru_replace_abbreviations", return_value="сущ")
196213
def test_all_empty_ru_fields_returns_none(self, _abbr):
197214
"""ru object with all empty meaning fields → None."""
198215
inst = _bare()
199-
result = inst.make_sc_headword_entry(_hw(ru=_ru(ru_meaning="", ru_meaning_raw="")))
216+
result = inst.make_sc_headword_entry(
217+
_hw(ru=_ru(ru_meaning="", ru_meaning_raw=""))
218+
)
200219
assert result is None
201220

202221
@patch(f"{MODULE}.ru_replace_abbreviations", return_value="сущ")
@@ -206,6 +225,7 @@ def test_ru_meaning_preferred_over_raw(self, _abbr):
206225
result = inst.make_sc_headword_entry(
207226
_hw(ru=_ru(ru_meaning="учение", ru_meaning_raw="ИИ перевод"))
208227
)
228+
assert result is not None
209229
assert "<b>учение</b>" in result
210230
assert "[пер. ИИ]" not in result
211231

@@ -222,6 +242,7 @@ def test_pos_abbreviation_always_called(self, mock_abbr):
222242
# make_sc_dict()
223243
# ---------------------------------------------------------------------------
224244

245+
225246
class TestMakeScDict:
226247
def test_word_not_in_lookup_dict_skipped(self):
227248
inst = _bare()
@@ -290,7 +311,9 @@ def test_headwords_and_deconstructor_both_added(self, _abbr):
290311
hw = _hw(lemma_1="dhamma", pos="masc", ru=_ru(ru_meaning="учение"))
291312
inst = _bare()
292313
inst.sc_word_set = {"dhamma"}
293-
inst.lookup_dict = {"dhamma": _lookup(headword_ids=[1], deconstructions=["x + y"])}
314+
inst.lookup_dict = {
315+
"dhamma": _lookup(headword_ids=[1], deconstructions=["x + y"])
316+
}
294317
inst.headword_dict = {1: hw}
295318
inst.make_sc_dict()
296319
assert len(inst.sc_dict["dhamma"]) == 2
@@ -322,6 +345,7 @@ def test_multiple_words_each_processed_independently(self):
322345
# compile_sc_dict()
323346
# ---------------------------------------------------------------------------
324347

348+
325349
class TestCompileScDict:
326350
def test_empty_word_set(self):
327351
inst = _bare()
@@ -426,6 +450,7 @@ def test_compiled_entry_has_definition_key(self):
426450
# make_lookup_dict()
427451
# ---------------------------------------------------------------------------
428452

453+
429454
class TestMakeLookupDict:
430455
def test_populates_lookup_dict_from_db(self):
431456
inst = _bare()
@@ -465,6 +490,7 @@ def test_duplicate_keys_last_one_wins(self):
465490
# make_headwords_dict()
466491
# ---------------------------------------------------------------------------
467492

493+
468494
class TestMakeHeadwordsDict:
469495
def test_populates_headword_dict_by_id(self):
470496
inst = _bare()
@@ -512,6 +538,7 @@ def test_queries_dpdheadword_model(self):
512538
# save_sc_dict()
513539
# ---------------------------------------------------------------------------
514540

541+
515542
class TestSaveScDict:
516543
def _run_save(self, inst):
517544
"""Run save_sc_dict, capture written bytes, return parsed JSON."""
@@ -532,9 +559,14 @@ def __exit__(self_, *a):
532559
def test_creates_parent_directory(self):
533560
inst = _bare()
534561
inst.sc_dict_compiled = []
535-
with patch("builtins.open", return_value=MagicMock(__enter__=lambda s: StringIO(), __exit__=lambda s, *a: None)):
562+
with patch(
563+
"builtins.open",
564+
return_value=MagicMock(
565+
__enter__=lambda s: StringIO(), __exit__=lambda s, *a: None
566+
),
567+
):
536568
inst.save_sc_dict()
537-
inst.pth.sc_pli2ru_dpd_json.parent.mkdir.assert_called_once_with(
569+
inst.ru_pth.sc_pli2ru_dpd_json.parent.mkdir.assert_called_once_with(
538570
parents=True, exist_ok=True
539571
)
540572

@@ -575,12 +607,17 @@ def test_opens_file_at_correct_path(self):
575607
inst = _bare()
576608
inst.sc_dict_compiled = []
577609
mock_path = MagicMock()
578-
inst.pth.sc_pli2ru_dpd_json = mock_path
579-
580-
with patch("builtins.open", return_value=MagicMock(__enter__=lambda s: StringIO(), __exit__=lambda s, *a: None)) as m_open:
610+
inst.ru_pth.sc_pli2ru_dpd_json = mock_path
611+
612+
with patch(
613+
"builtins.open",
614+
return_value=MagicMock(
615+
__enter__=lambda s: StringIO(), __exit__=lambda s, *a: None
616+
),
617+
) as m_open:
581618
inst.save_sc_dict()
582619

583-
m_open.assert_called_once_with(mock_path, "w")
620+
m_open.assert_called_once_with(mock_path, "w", encoding="utf-8")
584621

585622

586623
# ---------------------------------------------------------------------------

tools/paths_ru.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,11 @@ def __init__(self, base_dir: Optional[Path] = None, create_dirs=True):
327327
base_dir / "resources/tpr_downloads/release_zips/dpd_with_rus.zip"
328328
)
329329

330+
# resources/sc-data/dictionaries/simple/ru
331+
self.sc_pli2ru_dpd_json = (
332+
base_dir / "resources/sc-data/dictionaries/simple/ru/pli2ru_dpd.json"
333+
)
334+
330335
# identity/
331336
self.dpd_css_path = base_dir / "identity/css/dpd.css"
332337
self.dpd_variables_css_path = base_dir / "identity/css/dpd-variables.css"

0 commit comments

Comments
 (0)