Skip to content

Commit dd5772a

Browse files
committed
Rewrite configurations; add types for generics
Use classes instead of dictionaries for usage configurations; add types for generics like `dict` and `Callable`.
1 parent 264d38f commit dd5772a

30 files changed

+289
-151
lines changed

emmio/audio/config.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55
from emmio.language import LanguageConfig
66

77

8+
class AudioUsageConfig(BaseModel):
9+
"""Configuration for a collection of audio files."""
10+
11+
id: str
12+
"""Identifier of the audio files."""
13+
14+
language: LanguageConfig
15+
"""Language of the files."""
16+
17+
818
class AudioConfig(BaseModel):
919
"""Configuration for a collection of audio files."""
1020

emmio/audio/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class DirectoryAudioProvider(AudioProvider):
6969
def __post_init__(self) -> None:
7070
"""Initialize the audio provider."""
7171

72-
self.path_pattern: re.Pattern = re.compile(
72+
self.path_pattern: re.Pattern[str] = re.compile(
7373
rf"(?P<word>[^()]*)\s*(\([^()]*\))?\s*\d?\.{self.file_extension}"
7474
)
7575
self.cache: dict[str, list[Path]] = defaultdict(list)

emmio/audio/data.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
from dataclasses import dataclass
44
from pathlib import Path
5-
from typing import Self
5+
from typing import Any, Self
66

7-
from emmio.audio.config import AudioConfig
7+
from emmio.audio.config import AudioConfig, AudioUsageConfig
88
from emmio.audio.core import (
99
AudioCollection,
1010
AudioProvider,
@@ -32,7 +32,7 @@ def from_config(cls, path: Path) -> Self:
3232
:param path: path to the configuration file
3333
:return: audio data
3434
"""
35-
config: dict = ArtifactData.read_config(path)
35+
config: dict[str, Any] = ArtifactData.read_config(path)
3636

3737
audio_providers: dict[str, AudioProvider] = {}
3838
for id_, data in config.items():
@@ -41,23 +41,25 @@ def from_config(cls, path: Path) -> Self:
4141
)
4242
return cls(path, audio_providers)
4343

44-
def get_audio_provider(self, usage_config: dict) -> AudioProvider:
44+
def get_audio_provider(
45+
self, usage_config: AudioUsageConfig
46+
) -> AudioProvider:
4547
"""Get an audio provider from a usage configuration.
4648
4749
:param usage_config: usage configuration
4850
:return: audio provider
4951
"""
50-
match id_ := usage_config["id"]:
52+
match id_ := usage_config.id:
5153
case "wikimedia_commons":
5254
return WikimediaCommonsAudioProvider(
53-
Language.from_code(usage_config["language"]),
55+
Language.from_code(usage_config.language),
5456
self.path / "cache",
5557
)
5658
case _:
5759
return self.audio_providers[id_]
5860

5961
def get_audio_collection(
60-
self, usage_configs: list[dict]
62+
self, usage_configs: list[AudioUsageConfig]
6163
) -> AudioCollection:
6264
"""Get an audio collection from a list of usage configurations.
6365

emmio/core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from abc import ABC, abstractmethod
66
from datetime import datetime
77
from pathlib import Path
8-
from typing import Self
8+
from typing import Any, Self
99

1010
from pydantic import BaseModel
1111

@@ -54,7 +54,7 @@ def from_config(cls, path: Path) -> Self:
5454
raise NotImplementedError()
5555

5656
@staticmethod
57-
def read_config(path: Path) -> dict:
57+
def read_config(path: Path) -> dict[str, Any]:
5858
"""Read the configuration file.
5959
6060
:param path: path to the configuration file
@@ -69,5 +69,5 @@ def read_config(path: Path) -> dict:
6969
raise FileExistsError()
7070

7171
with (path / "config.json").open(encoding="utf-8") as config_file:
72-
result: dict = json.load(config_file)
72+
result: dict[str, Any] = json.load(config_file)
7373
return result

emmio/data.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,21 @@
1818
from typing import Self
1919

2020
from emmio import ui
21+
from emmio.audio.config import AudioUsageConfig
2122
from emmio.audio.core import AudioCollection, AudioProvider
2223
from emmio.audio.data import AudioData
24+
from emmio.dictionary.config import DictionaryUsageConfig
2325
from emmio.dictionary.core import Dictionary, DictionaryCollection
2426
from emmio.dictionary.data import DictionaryData
2527
from emmio.language import Language
2628
from emmio.learn.core import Learning
2729
from emmio.lexicon.core import Lexicon
30+
from emmio.lists.config import ListUsageConfig
2831
from emmio.lists.core import List
2932
from emmio.lists.data import ListsData
3033
from emmio.lists.frequency_list import FrequencyList
31-
from emmio.sentence.core import Sentences, SentencesCollection
34+
from emmio.sentence.config import SentencesUsageConfig
35+
from emmio.sentence.core import SentencesCollection
3236
from emmio.sentence.data import SentencesData
3337
from emmio.text.core import Texts
3438
from emmio.text.data import TextData
@@ -119,34 +123,34 @@ def get_lists_data(self) -> ListsData:
119123
)
120124
return self._lists_data
121125

122-
def get_list(self, usage_config: dict) -> List | None:
126+
def get_list(self, usage_config: ListUsageConfig) -> List | None:
123127
"""Get a list by usage configuration."""
124128
return self.get_lists_data().get_list(usage_config)
125129

126-
def get_frequency_list(self, usage_config: dict) -> FrequencyList | None:
130+
def get_frequency_list(
131+
self, usage_config: ListUsageConfig
132+
) -> FrequencyList | None:
127133
"""Get a frequency list by usage configuration."""
128134
return self.get_lists_data().get_frequency_list(usage_config)
129135

130-
def get_dictionary(self, usage_config: dict) -> Dictionary | None:
136+
def get_dictionary(
137+
self, usage_config: DictionaryUsageConfig
138+
) -> Dictionary | None:
131139
"""Get a dictionary by usage configuration."""
132140
return self.dictionaries.get_dictionary(usage_config)
133141

134142
def get_dictionaries(
135-
self, usage_configs: list[dict]
143+
self, usage_configs: list[DictionaryUsageConfig]
136144
) -> DictionaryCollection:
137145
"""Get a collection of dictionaries by usage configurations."""
138146
return self.dictionaries.get_dictionaries(usage_configs)
139147

140-
def get_sentences(self, usage_config: dict) -> Sentences:
141-
"""Get sentences by usage configuration."""
142-
return self.sentences.get_sentences(usage_config)
143-
144148
def get_text(self, text_id: str) -> Texts:
145149
"""Get a text by its identifier."""
146150
return self.texts.get_text(text_id)
147151

148152
def get_sentences_collection(
149-
self, usage_configs: list[dict]
153+
self, usage_configs: list[SentencesUsageConfig]
150154
) -> SentencesCollection:
151155
"""Get a collection of sentences by usage configurations."""
152156
return self.sentences.get_sentences_collection(usage_configs)
@@ -161,20 +165,22 @@ def get_audio_data(self) -> AudioData:
161165
)
162166
return self._audio_data
163167

164-
def get_audio_provider(self, usage_config: dict) -> AudioProvider:
168+
def get_audio_provider(
169+
self, usage_config: AudioUsageConfig
170+
) -> AudioProvider:
165171
"""Get an audio provider by usage configuration."""
166172
return self.get_audio_data().get_audio_provider(usage_config)
167173

168174
def get_audio_collection(
169-
self, usage_configs: list[dict]
175+
self, usage_configs: list[AudioUsageConfig]
170176
) -> AudioCollection:
171177
"""Get an audio collection by usage configurations."""
172178
return self.get_audio_data().get_audio_collection(usage_configs)
173179

174180
def get_words(self, id_: str) -> list[str] | None:
175181
"""Get words from a list by its identifier."""
176182

177-
if not (list_ := self.get_list({"id": id_})):
183+
if not (list_ := self.get_list(ListUsageConfig(id=id_))):
178184
return None
179185
return list_.get_words()
180186

emmio/dictionary/config.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@
55
from emmio.language import LanguageConfig
66

77

8+
class DictionaryUsageConfig(BaseModel):
9+
"""Configuration of a dictionary."""
10+
11+
id: str
12+
"""Identifier of the dictionary."""
13+
14+
from_language: LanguageConfig | None = None
15+
"""Language of words being defined."""
16+
17+
to_language: LanguageConfig | None = None
18+
"""Language of definitions and translations."""
19+
20+
name: str | None = None
21+
"""Additional name to identify the dictionary."""
22+
23+
824
class DictionaryConfig(BaseModel):
925
"""Configuration of a dictionary."""
1026

emmio/dictionary/data.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
from dataclasses import dataclass
44
from pathlib import Path
5-
from typing import Self
5+
from typing import Any, Self
66

77
from emmio.core import ArtifactData
8-
from emmio.dictionary.config import DictionaryConfig
8+
from emmio.dictionary.config import DictionaryConfig, DictionaryUsageConfig
99
from emmio.dictionary.core import (
1010
Dictionary,
1111
DictionaryCollection,
@@ -32,7 +32,7 @@ def from_config(cls, path: Path) -> Self:
3232
3333
:param path: path to the directory with dictionaries
3434
"""
35-
config: dict = ArtifactData.read_config(path)
35+
config: dict[str, Any] = ArtifactData.read_config(path)
3636

3737
dictionaries: dict[str, Dictionary] = {}
3838
for id_, data in config.items():
@@ -42,23 +42,38 @@ def from_config(cls, path: Path) -> Self:
4242
return cls(path, dictionaries)
4343

4444
def get_dictionary(
45-
self, dictionary_usage_config: dict
45+
self, dictionary_usage_config: DictionaryUsageConfig
4646
) -> Dictionary | None:
4747
"""Get dictionary by dictionary usage configuration."""
48-
match id_ := dictionary_usage_config["id"]:
48+
49+
match id_ := dictionary_usage_config.id:
4950
case "kaikki":
51+
if dictionary_usage_config.from_language is None:
52+
raise ValueError(
53+
"Language is required for Kaikki dictionary."
54+
)
55+
if dictionary_usage_config.name is None:
56+
raise ValueError("Name is required for Kaikki dictionary.")
5057
return EnglishWiktionaryKaikki(
5158
self.path,
5259
self.path / "cache",
53-
Language.from_code(dictionary_usage_config["language"]),
54-
dictionary_usage_config["name"],
60+
Language.from_code(dictionary_usage_config.from_language),
61+
dictionary_usage_config.name,
5562
)
5663
case "google_translate":
64+
if dictionary_usage_config.from_language is None:
65+
raise ValueError(
66+
"Language is required for Google Translate dictionary."
67+
)
68+
if dictionary_usage_config.to_language is None:
69+
raise ValueError(
70+
"Language is required for Google Translate dictionary."
71+
)
5772
return GoogleTranslate(
5873
self.path,
5974
self.path / "cache",
60-
Language.from_code(dictionary_usage_config["from"]),
61-
Language.from_code(dictionary_usage_config["to"]),
75+
Language.from_code(dictionary_usage_config.from_language),
76+
Language.from_code(dictionary_usage_config.to_language),
6277
)
6378
case _:
6479
if id_ in self.dictionaries:
@@ -67,7 +82,7 @@ def get_dictionary(
6782
return None
6883

6984
def get_dictionaries(
70-
self, dictionary_usage_configs: list[dict]
85+
self, dictionary_usage_configs: list[DictionaryUsageConfig]
7186
) -> DictionaryCollection:
7287
"""Get dictionaries by dictionary usage configurations.
7388

emmio/dictionary/en_wiktionary.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@
4242
}
4343

4444

45-
LINK_PATTERN: re.Pattern = re.compile(
45+
LINK_PATTERN: re.Pattern[str] = re.compile(
4646
r"^(?P<preffix>\(.*\) )?(?P<link_type>.*) of "
4747
r"(?P<link>[^:;,. ]*)[:;,.]?"
4848
r'(?P<suffix1>[:;,] .*)?(?P<suffix2> \(.*\))?(?P<suffix3> ".*")?$'
4949
)
50-
DESCRIPTOR_PATTERN: re.Pattern = re.compile(r"\((?P<descriptor>[^()]*)\) .*")
50+
DESCRIPTOR_PATTERN: re.Pattern[str] = re.compile(
51+
r"\((?P<descriptor>[^()]*)\) .*"
52+
)
5153

5254

5355
def get_file_name(word: str) -> str:

emmio/graph.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def cumulative_actions(
5959
self,
6060
records: list[tuple[LearningRecord, Learning]],
6161
lexicons: list[Lexicon],
62-
point: Callable,
62+
point: Callable[[datetime], datetime],
6363
width: float,
6464
by_language: bool = False,
6565
) -> None:

emmio/language.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def __init__(
4040
symbols: str,
4141
self_name: str | None = None,
4242
parent: Language | None = None,
43-
checking: Callable | None = None,
43+
checking: Callable[[str], bool] | None = None,
4444
sentence_end: str | None = None,
4545
) -> None:
4646
self.code: str = code
@@ -51,7 +51,7 @@ def __init__(
5151
self.sentence_end: str | None = sentence_end
5252
self.iso639_language = ISO639Language(code)
5353

54-
self.has_symbol: Callable
54+
self.has_symbol: Callable[[str], bool]
5555
if checking:
5656
self.has_symbol = checking
5757
else:

0 commit comments

Comments
 (0)