11from dataclasses import dataclass , field
22from pathlib import Path
3- from subprocess import check_call
3+ from subprocess import run
44from tempfile import TemporaryDirectory
55from typing import List , Optional
6+ from unicodedata import normalize
67
78from . import PYCONLANG_PATH
89from .data import LEXURGY_VERSION
1213LEXURGY_PATH = PYCONLANG_PATH / f"lexurgy-{ LEXURGY_VERSION } " / "bin" / "lexurgy"
1314
1415
16+ @dataclass (eq = True , frozen = True )
17+ class Evolved :
18+ proto : str
19+ modern : str
20+ phonetic : str
21+
22+
1523@dataclass
1624class LexurgySession :
1725 args : List [str ] = field (default_factory = list )
@@ -23,35 +31,45 @@ def clear(self) -> None:
2331 def add_word (self , word : str ) -> None :
2432 self .words .append (word )
2533
26- def evolve (self ) -> List [str ]:
34+ def evolve (self ) -> List [Evolved ]:
2735 return self .evolve_words (self .words )
2836
29- def evolve_word (self , word : str ) -> str :
37+ def evolve_word (self , word : str ) -> Evolved :
3038 return self .evolve_words ([word ])[0 ]
3139
32- def evolve_words (self , words : List [str ]) -> List [str ]:
40+ def evolve_words (self , words : List [str ]) -> List [Evolved ]:
3341 with TemporaryDirectory () as tmpdir :
3442 dir_path = Path (tmpdir )
3543 input_words = dir_path / "words.wli"
3644 input_words .write_text ("\n " .join (words ))
37- check_call (
38- [
39- "sh" ,
40- str (LEXURGY_PATH ),
41- "sc" ,
42- "changes.lsc" ,
43- str (input_words ),
44- ]
45- + self .args
45+ run (
46+ ["sh" , str (LEXURGY_PATH ), "sc" , "changes.lsc" , str (input_words ), "-m" ]
47+ + self .args ,
48+ check = True ,
49+ capture_output = True ,
4650 )
4751
4852 output_words = dir_path / "words_ev.wli"
49- return output_words .read_text ().strip ().split ("\n " )
53+ phonetic_words = dir_path / "words_phonetic.wli"
54+
55+ moderns = normalize ("NFD" , output_words .read_text ().strip ()).split ("\n " )
56+
57+ if phonetic_words .exists ():
58+ phonetics = (
59+ normalize ("NFD" , phonetic_words .read_text ()).strip ().split ("\n " )
60+ )
61+ else :
62+ phonetics = moderns
63+
64+ return [
65+ Evolved (proto , modern , phonetic )
66+ for proto , modern , phonetic in zip (words , moderns , phonetics )
67+ ]
5068
5169
5270def evolve_word (
5371 word : str , * , start : Optional [Rule ] = None , end : Optional [Rule ] = None
54- ) -> str :
72+ ) -> Evolved :
5573 args = []
5674 if start is not None :
5775 args .extend (["-a" , start .name ])
@@ -60,16 +78,16 @@ def evolve_word(
6078 return LexurgySession (args ).evolve_word (word )
6179
6280
63- def evolve_proto (proto : Proto , end : Optional [Rule ] = None ) -> str :
81+ def evolve_proto (proto : Proto , end : Optional [Rule ] = None ) -> Evolved :
6482 return evolve_word (proto .form , start = proto .era , end = end )
6583
6684
67- def evolve (fusion : ResolvedForm ) -> str :
85+ def evolve (fusion : ResolvedForm ) -> Evolved :
6886 form = fusion .stem
6987 for affix in fusion .affixes :
7088 if affix .era is not None and form .era != affix .era :
71- evolved = evolve_proto (form , affix .era )
72- evolved_affix = evolve (affix .form )
89+ evolved = evolve_proto (form , affix .era ). phonetic
90+ evolved_affix = evolve (affix .form ). phonetic
7391
7492 form = Proto (fuse (evolved , evolved_affix , affix .affix .type ), affix .era )
7593 else :
@@ -87,9 +105,11 @@ def fuse(stem: str, affix: str, affix_type: AffixType) -> str:
87105 return stem + affix
88106
89107
90- def glom_at (prefix : str , suffix : str , rule : Rule , stressed_suffix : bool = False ) -> str :
91- evolved_prefix = evolve_word (prefix , end = rule )
92- evolved_suffix = evolve_word (suffix , end = rule )
108+ def glom_at (
109+ prefix : str , suffix : str , rule : Rule , stressed_suffix : bool = False
110+ ) -> Evolved :
111+ evolved_prefix = evolve_word (prefix , end = rule ).phonetic
112+ evolved_suffix = evolve_word (suffix , end = rule ).phonetic
93113
94114 if stressed_suffix :
95115 evolved_prefix = remove_primary_stress (evolved_prefix )
0 commit comments