feat(backend): drop dictionary dialect columns, add allowed_languages
- Removes source_dialect and target_dialect from TerminologyDictionary model, schemas, routes, helper serialization, and all tests - Adds allowed_languages config field (BCP-47 language codes) to GlobalSettings with validation, consolidated settings response, and API endpoint - Adds alembic migration f1a2b3c4d5e6 to drop the two columns
This commit is contained in:
@@ -128,6 +128,22 @@ async def get_features(
|
||||
# #endregion get_features
|
||||
|
||||
|
||||
# #region get_allowed_languages [C:1] [TYPE Function]
|
||||
# @BRIEF Public endpoint returning allowed translation languages for language dropdowns.
|
||||
# @RATIONALE No auth required — needed by dictionary page, job config, etc. everywhere
|
||||
# language selects appear. Non-admin users still need the list.
|
||||
# @PRE Config manager is available.
|
||||
# @POST Returns list of BCP-47 language codes.
|
||||
@router.get("/allowed-languages")
|
||||
async def get_allowed_languages(
|
||||
config_manager: ConfigManager = Depends(get_config_manager),
|
||||
):
|
||||
return config_manager.get_config().settings.allowed_languages
|
||||
|
||||
|
||||
# #endregion get_allowed_languages
|
||||
|
||||
|
||||
# #region update_global_settings [C:2] [TYPE Function]
|
||||
# @BRIEF Updates global application settings.
|
||||
# @PRE New settings are provided.
|
||||
@@ -394,6 +410,7 @@ class ConsolidatedSettingsResponse(BaseModel):
|
||||
notifications: dict = {}
|
||||
features: dict = {}
|
||||
app_timezone: str = "Europe/Moscow"
|
||||
allowed_languages: list[str] = []
|
||||
|
||||
|
||||
# #endregion ConsolidatedSettingsResponse
|
||||
@@ -465,6 +482,7 @@ async def get_consolidated_settings(
|
||||
notifications=notifications_payload,
|
||||
features=config.settings.features.model_dump(),
|
||||
app_timezone=config.settings.app_timezone,
|
||||
allowed_languages=config.settings.allowed_languages,
|
||||
)
|
||||
logger.reflect(
|
||||
"Consolidated settings payload assembled",
|
||||
@@ -537,6 +555,10 @@ async def update_consolidated_settings(
|
||||
current_settings.app_timezone = new_tz
|
||||
invalidate_timezone_cache()
|
||||
|
||||
# Update allowed_languages if provided
|
||||
if "allowed_languages" in settings_patch:
|
||||
current_settings.allowed_languages = settings_patch["allowed_languages"]
|
||||
|
||||
config_manager.update_global_settings(current_settings)
|
||||
return {"status": "success", "message": "Settings updated"}
|
||||
|
||||
|
||||
@@ -88,8 +88,6 @@ async def create_dictionary(
|
||||
d = DictionaryManager.create_dictionary(
|
||||
db,
|
||||
name=payload.name,
|
||||
source_dialect=payload.source_dialect,
|
||||
target_dialect=payload.target_dialect,
|
||||
created_by=current_user.username,
|
||||
description=payload.description,
|
||||
is_active=payload.is_active,
|
||||
@@ -120,8 +118,6 @@ async def update_dictionary(
|
||||
dict_id=dictionary_id,
|
||||
name=payload.name,
|
||||
description=payload.description,
|
||||
source_dialect=payload.source_dialect,
|
||||
target_dialect=payload.target_dialect,
|
||||
is_active=payload.is_active,
|
||||
)
|
||||
from ....models.translate import DictionaryEntry
|
||||
|
||||
@@ -43,8 +43,6 @@ def _dict_to_response(d: Any, entry_count: int = 0) -> dict:
|
||||
"id": d.id,
|
||||
"name": d.name,
|
||||
"description": d.description,
|
||||
"source_dialect": d.source_dialect,
|
||||
"target_dialect": d.target_dialect,
|
||||
"is_active": d.is_active,
|
||||
"created_by": d.created_by,
|
||||
"created_at": d.created_at,
|
||||
|
||||
@@ -141,6 +141,26 @@ class GlobalSettings(BaseModel):
|
||||
# Global worker limit for concurrent validation runs
|
||||
GLOBAL_VALIDATION_WORKER_LIMIT: int = 3
|
||||
|
||||
# Allowed languages for translation (BCP-47 codes)
|
||||
allowed_languages: list[str] = Field(
|
||||
default_factory=lambda: [
|
||||
"ru", "en", "de", "fr", "es", "it", "pt", "zh", "ja", "ko",
|
||||
"ar", "tr", "nl", "pl", "sv", "da", "fi", "cs", "hu", "ro",
|
||||
"vi", "th", "he", "id", "ms",
|
||||
]
|
||||
)
|
||||
|
||||
@field_validator("allowed_languages")
|
||||
@classmethod
|
||||
def validate_allowed_languages(cls, v: list[str]) -> list[str]:
|
||||
import re
|
||||
for tag in v:
|
||||
if not tag or not tag.strip():
|
||||
raise ValueError("Empty language code is not allowed")
|
||||
if not re.match(r'^[a-zA-Z]{2,8}(-[a-zA-Z0-9]{1,8})*$', tag.strip()):
|
||||
raise ValueError(f"Invalid BCP-47 language code: {tag}")
|
||||
return v
|
||||
|
||||
|
||||
# #endregion GlobalSettings
|
||||
|
||||
|
||||
@@ -205,8 +205,6 @@ class TerminologyDictionary(Base):
|
||||
id = Column(String, primary_key=True, default=generate_uuid)
|
||||
name = Column(String, nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
source_dialect = Column(String, nullable=False)
|
||||
target_dialect = Column(String, nullable=False)
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_by = Column(String, nullable=True)
|
||||
created_at = Column(DateTime, default=lambda: datetime.now(UTC))
|
||||
|
||||
@@ -63,8 +63,6 @@ def _create_dict(db_session, name="Test Dict") -> TerminologyDictionary:
|
||||
d = TerminologyDictionary(
|
||||
id=str(uuid.uuid4()),
|
||||
name=name,
|
||||
source_dialect="ru",
|
||||
target_dialect="en",
|
||||
)
|
||||
db_session.add(d)
|
||||
db_session.flush()
|
||||
|
||||
@@ -44,7 +44,7 @@ class TestContextCapture:
|
||||
|
||||
# region test_context_capture_in_correction [C:2] [TYPE Function]
|
||||
def test_context_capture_in_correction(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict")
|
||||
job = TranslationJob(name="Ctx Job", source_dialect="a", target_dialect="b", status="DRAFT")
|
||||
db_session.add(job)
|
||||
db_session.flush()
|
||||
|
||||
@@ -46,13 +46,10 @@ class TestDictionaryCRUD:
|
||||
def test_create_dictionary(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(
|
||||
db_session, name="Finance Terms",
|
||||
source_dialect="postgresql", target_dialect="clickhouse",
|
||||
created_by="test_user", description="Finance-related term mappings",
|
||||
)
|
||||
assert d.id is not None
|
||||
assert d.name == "Finance Terms"
|
||||
assert d.source_dialect == "postgresql"
|
||||
assert d.target_dialect == "clickhouse"
|
||||
assert d.created_by == "test_user"
|
||||
assert d.is_active is True
|
||||
|
||||
@@ -64,7 +61,7 @@ class TestDictionaryCRUD:
|
||||
# region test_update_dictionary [C:2] [TYPE Function]
|
||||
# @BRIEF Verify dictionary metadata update.
|
||||
def test_update_dictionary(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Old Name", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Old Name")
|
||||
updated = DictionaryManager.update_dictionary(
|
||||
db_session, d.id, name="New Name", description="Updated desc", is_active=False,
|
||||
)
|
||||
@@ -76,7 +73,7 @@ class TestDictionaryCRUD:
|
||||
# region test_delete_dictionary [C:2] [TYPE Function]
|
||||
# @BRIEF Verify dictionary deletion also removes entries.
|
||||
def test_delete_dictionary(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="To Delete", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="To Delete")
|
||||
entry = DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
assert entry.id is not None
|
||||
DictionaryManager.delete_dictionary(db_session, d.id)
|
||||
@@ -88,7 +85,7 @@ class TestDictionaryCRUD:
|
||||
# @BRIEF Verify paginated dictionary listing.
|
||||
def test_list_dictionaries(self, db_session: Session):
|
||||
for i in range(5):
|
||||
DictionaryManager.create_dictionary(db_session, name=f"Dict {i}", source_dialect="a", target_dialect="b")
|
||||
DictionaryManager.create_dictionary(db_session, name=f"Dict {i}")
|
||||
dicts, total = DictionaryManager.list_dictionaries(db_session, page=1, page_size=2)
|
||||
assert total == 5
|
||||
assert len(dicts) == 2
|
||||
@@ -97,7 +94,7 @@ class TestDictionaryCRUD:
|
||||
# region test_delete_dictionary_blocked_by_active_job [C:2] [TYPE Function]
|
||||
# @BRIEF Verify deletion is blocked when attached to active/scheduled jobs.
|
||||
def test_delete_dictionary_blocked_by_active_job(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
job = TranslationJob(name="Active Job", source_dialect="a", target_dialect="b", status="ACTIVE", created_by="test_user")
|
||||
db_session.add(job)
|
||||
db_session.flush()
|
||||
@@ -111,7 +108,7 @@ class TestDictionaryCRUD:
|
||||
# region test_delete_dictionary_allowed_with_completed_job [C:2] [TYPE Function]
|
||||
# @BRIEF Verify deletion is allowed when only completed/failed jobs reference the dictionary.
|
||||
def test_delete_dictionary_allowed_with_completed_job(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
job = TranslationJob(name="Completed Job", source_dialect="a", target_dialect="b", status="COMPLETED", created_by="test_user")
|
||||
db_session.add(job)
|
||||
db_session.flush()
|
||||
@@ -130,7 +127,7 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_add_entry_duplicate [C:2] [TYPE Function]
|
||||
# @BRIEF Verify duplicate entry raises ValueError.
|
||||
def test_add_entry_duplicate(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "Hello", "Hola", source_language="en", target_language="es")
|
||||
with pytest.raises(ValueError, match="already exists"):
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "Bonjour", source_language="en", target_language="es")
|
||||
@@ -141,8 +138,8 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_add_entry_duplicate_per_dictionary [C:2] [TYPE Function]
|
||||
# @BRIEF Verify duplicate is per-dictionary (same term in different dicts is OK).
|
||||
def test_add_entry_duplicate_per_dictionary(self, db_session: Session):
|
||||
d1 = DictionaryManager.create_dictionary(db_session, name="Dict1", source_dialect="a", target_dialect="b")
|
||||
d2 = DictionaryManager.create_dictionary(db_session, name="Dict2", source_dialect="a", target_dialect="b")
|
||||
d1 = DictionaryManager.create_dictionary(db_session, name="Dict1")
|
||||
d2 = DictionaryManager.create_dictionary(db_session, name="Dict2")
|
||||
DictionaryManager.add_entry(db_session, d1.id, "hello", "hola", source_language="en", target_language="es")
|
||||
entry = DictionaryManager.add_entry(db_session, d2.id, "hello", "bonjour", source_language="en", target_language="es")
|
||||
assert entry.id is not None
|
||||
@@ -151,7 +148,7 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_edit_entry [C:2] [TYPE Function]
|
||||
# @BRIEF Verify entry edit updates fields and enforces uniqueness.
|
||||
def test_edit_entry(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
entry = DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
updated = DictionaryManager.edit_entry(db_session, entry.id, target_term="HOLA!")
|
||||
assert updated.target_term == "HOLA!"
|
||||
@@ -163,7 +160,7 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_delete_entry [C:2] [TYPE Function]
|
||||
# @BRIEF Verify entry deletion.
|
||||
def test_delete_entry(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
entry = DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
DictionaryManager.delete_entry(db_session, entry.id)
|
||||
entries, total = DictionaryManager.list_entries(db_session, d.id)
|
||||
@@ -173,7 +170,7 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_clear_entries [C:2] [TYPE Function]
|
||||
# @BRIEF Verify clearing all entries for a dictionary.
|
||||
def test_clear_entries(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
DictionaryManager.add_entry(db_session, d.id, "world", "mundo", source_language="en", target_language="es")
|
||||
deleted = DictionaryManager.clear_entries(db_session, d.id)
|
||||
@@ -185,7 +182,7 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_add_entry_with_language_pair [C:2] [TYPE Function]
|
||||
# @BRIEF Verify creating entry with language pair stores correctly.
|
||||
def test_add_entry_with_language_pair(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Lang Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Lang Test")
|
||||
entry = DictionaryManager.add_entry(db_session, d.id, "hello", "привет", source_language="en", target_language="ru")
|
||||
assert entry.source_language == "en"
|
||||
assert entry.target_language == "ru"
|
||||
@@ -198,7 +195,7 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_duplicate_same_language_pair [C:2] [TYPE Function]
|
||||
# @BRIEF Verify duplicate with same language pair raises conflict.
|
||||
def test_duplicate_same_language_pair(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Dup Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Dup Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "привет", source_language="en", target_language="ru")
|
||||
with pytest.raises(ValueError, match="already exists"):
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hallo", source_language="en", target_language="ru")
|
||||
@@ -207,7 +204,7 @@ class TestDictionaryEntryCRUD:
|
||||
# region test_same_term_different_language_pair [C:2] [TYPE Function]
|
||||
# @BRIEF Verify same term with different language pair is allowed.
|
||||
def test_same_term_different_language_pair(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Multi Lang", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Multi Lang")
|
||||
entry1 = DictionaryManager.add_entry(db_session, d.id, "hello", "привет", source_language="en", target_language="ru")
|
||||
entry2 = DictionaryManager.add_entry(db_session, d.id, "hello", "hallo", source_language="en", target_language="de")
|
||||
assert entry1.id != entry2.id
|
||||
|
||||
@@ -50,7 +50,7 @@ class TestFilterBasic:
|
||||
|
||||
# region test_filter_for_batch_matches [C:2] [TYPE Function]
|
||||
def test_filter_for_batch_matches(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
DictionaryManager.add_entry(db_session, d.id, "world", "mundo", source_language="en", target_language="es")
|
||||
DictionaryManager.add_entry(db_session, d.id, "foo", "bar", source_language="en", target_language="es")
|
||||
@@ -76,7 +76,7 @@ class TestFilterBasic:
|
||||
|
||||
# region test_filter_for_batch_case_insensitive [C:2] [TYPE Function]
|
||||
def test_filter_for_batch_case_insensitive(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict")
|
||||
DictionaryManager.add_entry(db_session, d.id, "Hello World", "Hola Mundo", source_language="en", target_language="es")
|
||||
|
||||
job = TranslationJob(name="Test Job", source_dialect="a", target_dialect="b", status="DRAFT")
|
||||
@@ -94,7 +94,7 @@ class TestFilterBasic:
|
||||
|
||||
# region test_filter_for_batch_word_boundary [C:2] [TYPE Function]
|
||||
def test_filter_for_batch_word_boundary(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test Dict")
|
||||
DictionaryManager.add_entry(db_session, d.id, "cat", "gato", source_language="en", target_language="es")
|
||||
|
||||
job = TranslationJob(name="Test Job", source_dialect="a", target_dialect="b", status="DRAFT")
|
||||
@@ -117,8 +117,8 @@ class TestFilterPriority:
|
||||
|
||||
# region test_filter_for_batch_multi_dictionary_priority [C:2] [TYPE Function]
|
||||
def test_filter_for_batch_multi_dictionary_priority(self, db_session: Session):
|
||||
d1 = DictionaryManager.create_dictionary(db_session, name="Priority1", source_dialect="a", target_dialect="b")
|
||||
d2 = DictionaryManager.create_dictionary(db_session, name="Priority2", source_dialect="a", target_dialect="b")
|
||||
d1 = DictionaryManager.create_dictionary(db_session, name="Priority1")
|
||||
d2 = DictionaryManager.create_dictionary(db_session, name="Priority2")
|
||||
DictionaryManager.add_entry(db_session, d1.id, "hello", "hola", source_language="en", target_language="es")
|
||||
DictionaryManager.add_entry(db_session, d2.id, "hello", "bonjour", source_language="en", target_language="es")
|
||||
|
||||
@@ -145,7 +145,7 @@ class TestFilterLanguagePair:
|
||||
|
||||
# region test_filter_for_batch_with_language_pair [C:2] [TYPE Function]
|
||||
def test_filter_for_batch_with_language_pair(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Lang Filter", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Lang Filter")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "привет", source_language="en", target_language="ru")
|
||||
DictionaryManager.add_entry(db_session, d.id, "world", "мир", source_language="en", target_language="ru")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hallo", source_language="en", target_language="de")
|
||||
@@ -169,7 +169,7 @@ class TestFilterLanguagePair:
|
||||
|
||||
# region test_filter_for_batch_target_language_only [C:2] [TYPE Function]
|
||||
def test_filter_for_batch_target_language_only(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Target Only", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Target Only")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "привет", source_language="en", target_language="ru")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hallo", source_language="en", target_language="de")
|
||||
DictionaryManager.add_entry(db_session, d.id, "bonjour", "hallo", source_language="fr", target_language="de")
|
||||
@@ -196,7 +196,7 @@ class TestMigration:
|
||||
|
||||
# region test_migrate_old_entries [C:2] [TYPE Function]
|
||||
def test_migrate_old_entries(self, db_session: Session):
|
||||
d = TerminologyDictionary(name="Old Dict", source_dialect="a", target_dialect="b")
|
||||
d = TerminologyDictionary(name="Old Dict")
|
||||
db_session.add(d)
|
||||
db_session.flush()
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class TestImportOverwrite:
|
||||
|
||||
# region test_import_csv_overwrite [C:2] [TYPE Function]
|
||||
def test_import_csv_overwrite(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
|
||||
csv_content = "source_term,target_term,context_notes,source_language,target_language\nhello,HELLO,,en,es\nworld,mundo,,en,es"
|
||||
@@ -59,7 +59,7 @@ class TestImportKeepExisting:
|
||||
|
||||
# region test_import_csv_keep_existing [C:2] [TYPE Function]
|
||||
def test_import_csv_keep_existing(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
|
||||
csv_content = "source_term,target_term,source_language,target_language\nhello,HELLO,en,es\nworld,mundo,en,es"
|
||||
@@ -79,7 +79,7 @@ class TestImportCancel:
|
||||
|
||||
# region test_import_csv_cancel_on_conflict [C:2] [TYPE Function]
|
||||
def test_import_csv_cancel_on_conflict(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
|
||||
csv_content = "source_term,target_term,source_language,target_language\nhello,HELLO,en,es\nworld,mundo,en,es"
|
||||
@@ -97,7 +97,7 @@ class TestImportFormat:
|
||||
|
||||
# region test_import_tsv [C:2] [TYPE Function]
|
||||
def test_import_tsv(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
tsv_content = "source_term\ttarget_term\tsource_language\ttarget_language\nhello\thola\ten\tes\nworld\tmundo\ten\tes"
|
||||
result = DictionaryManager.import_entries(db_session, d.id, tsv_content, delimiter="\t", on_conflict="overwrite")
|
||||
assert result["created"] == 2
|
||||
@@ -106,14 +106,14 @@ class TestImportFormat:
|
||||
|
||||
# region test_import_invalid_format [C:2] [TYPE Function]
|
||||
def test_import_invalid_format(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
with pytest.raises(ValueError, match="source_term"):
|
||||
DictionaryManager.import_entries(db_session, d.id, "name,value\nhello,hola", delimiter=",", on_conflict="overwrite")
|
||||
# endregion test_import_invalid_format
|
||||
|
||||
# region test_import_empty_rows [C:2] [TYPE Function]
|
||||
def test_import_empty_rows(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
csv_content = "source_term,target_term\nhello,hola\n,world\nfoo,"
|
||||
result = DictionaryManager.import_entries(db_session, d.id, csv_content, delimiter=",", on_conflict="overwrite")
|
||||
assert result["created"] == 1
|
||||
@@ -122,7 +122,7 @@ class TestImportFormat:
|
||||
|
||||
# region test_import_preview [C:2] [TYPE Function]
|
||||
def test_import_preview(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "hola", source_language="en", target_language="es")
|
||||
|
||||
csv_content = "source_term,target_term,source_language,target_language\nhello,HELLO,en,es\nworld,mundo,en,es"
|
||||
@@ -142,7 +142,7 @@ class TestExportEntries:
|
||||
|
||||
# region test_export_entries [C:2] [TYPE Function]
|
||||
def test_export_entries(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Export Test", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Export Test")
|
||||
DictionaryManager.add_entry(db_session, d.id, "hello", "привет", source_language="en", target_language="ru")
|
||||
DictionaryManager.add_entry(db_session, d.id, "world", "мир", source_language="en", target_language="ru")
|
||||
|
||||
@@ -161,7 +161,7 @@ class TestExportEntries:
|
||||
|
||||
# region test_import_with_default_language [C:2] [TYPE Function]
|
||||
def test_import_with_default_language(self, db_session: Session):
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Default Lang Import", source_dialect="a", target_dialect="b")
|
||||
d = DictionaryManager.create_dictionary(db_session, name="Default Lang Import")
|
||||
csv_content = "source_term,target_term\nhello,привет\nworld,мир"
|
||||
result = DictionaryManager.import_entries(
|
||||
db_session, d.id, csv_content, delimiter=",", on_conflict="overwrite",
|
||||
|
||||
@@ -45,8 +45,8 @@ class DictionaryCorrectionService:
|
||||
effective_context_source = "manual"
|
||||
|
||||
normalized = _normalize_term(source_term)
|
||||
entry_src_lang = dictionary.source_dialect or "und"
|
||||
entry_tgt_lang = dictionary.target_dialect or "und"
|
||||
entry_src_lang = "und"
|
||||
entry_tgt_lang = "und"
|
||||
|
||||
existing = (
|
||||
db.query(DictionaryEntry)
|
||||
@@ -139,8 +139,8 @@ class DictionaryCorrectionService:
|
||||
continue
|
||||
|
||||
normalized = _normalize_term(source_term)
|
||||
bulk_src_lang = dictionary.source_dialect or "und"
|
||||
bulk_tgt_lang = dictionary.target_dialect or "und"
|
||||
bulk_src_lang = "und"
|
||||
bulk_tgt_lang = "und"
|
||||
|
||||
existing = (
|
||||
db.query(DictionaryEntry)
|
||||
|
||||
@@ -24,15 +24,13 @@ class DictionaryCRUD:
|
||||
@staticmethod
|
||||
def create_dictionary(
|
||||
db: Session, name: str,
|
||||
source_dialect: str = "", target_dialect: str = "",
|
||||
created_by: str | None = None, description: str | None = None,
|
||||
is_active: bool = True,
|
||||
) -> TerminologyDictionary:
|
||||
with belief_scope("DictionaryCRUD.create_dictionary"):
|
||||
logger.reason("Creating dictionary", {"name": name, "source": source_dialect, "target": target_dialect})
|
||||
logger.reason("Creating dictionary", {"name": name})
|
||||
dictionary = TerminologyDictionary(
|
||||
name=name, description=description,
|
||||
source_dialect=source_dialect or "", target_dialect=target_dialect or "",
|
||||
is_active=is_active, created_by=created_by,
|
||||
)
|
||||
db.add(dictionary)
|
||||
@@ -47,8 +45,7 @@ class DictionaryCRUD:
|
||||
@staticmethod
|
||||
def update_dictionary(
|
||||
db: Session, dict_id: str, name: str | None = None,
|
||||
description: str | None = None, source_dialect: str | None = None,
|
||||
target_dialect: str | None = None, is_active: bool | None = None,
|
||||
description: str | None = None, is_active: bool | None = None,
|
||||
) -> TerminologyDictionary:
|
||||
with belief_scope("DictionaryCRUD.update_dictionary"):
|
||||
dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
|
||||
@@ -59,10 +56,6 @@ class DictionaryCRUD:
|
||||
dictionary.name = name
|
||||
if description is not None:
|
||||
dictionary.description = description
|
||||
if source_dialect is not None:
|
||||
dictionary.source_dialect = source_dialect
|
||||
if target_dialect is not None:
|
||||
dictionary.target_dialect = target_dialect
|
||||
if is_active is not None:
|
||||
dictionary.is_active = is_active
|
||||
db.commit()
|
||||
|
||||
@@ -173,8 +173,6 @@ class DuplicateJobResponse(BaseModel):
|
||||
class DictionaryCreate(BaseModel):
|
||||
name: str
|
||||
description: str | None = None
|
||||
source_dialect: str
|
||||
target_dialect: str
|
||||
is_active: bool = True
|
||||
# #endregion DictionaryCreate
|
||||
|
||||
@@ -197,8 +195,6 @@ class DictionaryResponse(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
source_dialect: str
|
||||
target_dialect: str
|
||||
is_active: bool
|
||||
created_by: str | None = None
|
||||
created_at: datetime
|
||||
|
||||
Reference in New Issue
Block a user