Skip to content

Commit c06900f

Browse files
hive-botclaude
andcommitted
fix: strip spoken terms before validating and sending them
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent d119c76 commit c06900f

3 files changed

Lines changed: 36 additions & 12 deletions

File tree

‎README.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -641,10 +641,11 @@ The `translate_document()`, `translate_document_from_filepath()` and
641641
A spoken-terms collection holds terms, such as product names or technical
642642
words, that improve speech transcription. Each collection has one term list
643643
per language; a term list is a list of strings. Before sending, the library
644-
checks each term like a glossary term (`validate_glossary_term()`): an empty
645-
term or one with a control character, such as a newline, raises `ValueError`.
646-
The API validates the rest (at most 300 characters per list, no duplicates, no
647-
leading or trailing whitespace). Methods that take a collection accept either its ID or a
644+
strips leading and trailing whitespace from each term and sends the stripped
645+
term, then checks it like a glossary term (`validate_glossary_term()`): an
646+
empty term or one with a control character, such as a newline, raises
647+
`ValueError`. The API validates the rest (at most 300 characters per list, no
648+
duplicates). Methods that take a collection accept either its ID or a
648649
`SpokenTerms` object.
649650

650651
```python

‎deepl/deepl_client.py‎

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -736,8 +736,9 @@ def create_spoken_terms(
736736
terms of one language.
737737
:return: SpokenTerms containing information about the created
738738
collection.
739-
:raises ValueError: If a term is empty or contains a control
740-
character, as validate_glossary_term() checks.
739+
:raises ValueError: If a term, after stripping leading and trailing
740+
whitespace, is empty or contains a control character, as
741+
validate_glossary_term() checks.
741742
"""
742743
request_data = {
743744
"name": name,
@@ -797,8 +798,9 @@ def update_spoken_terms(
797798
are merged into the term list of the same language.
798799
:return: SpokenTerms containing information about the updated
799800
collection.
800-
:raises ValueError: If a term is empty or contains a control
801-
character, as validate_glossary_term() checks.
801+
:raises ValueError: If a term, after stripping leading and trailing
802+
whitespace, is empty or contains a control character, as
803+
validate_glossary_term() checks.
802804
"""
803805
spoken_terms_id = self._spoken_terms_id(spoken_terms)
804806
request_data: Dict[str, Any] = {}
@@ -846,8 +848,9 @@ def replace_spoken_terms_list(
846848
:param spoken_terms: SpokenTerms or ID of the collection.
847849
:param entries: SpokenTermsEntries with the language and its terms.
848850
:return: SpokenTermsList containing information about the term list.
849-
:raises ValueError: If a term is empty or contains a control
850-
character, as validate_glossary_term() checks.
851+
:raises ValueError: If a term, after stripping leading and trailing
852+
whitespace, is empty or contains a control character, as
853+
validate_glossary_term() checks.
851854
"""
852855
spoken_terms_id = self._spoken_terms_id(spoken_terms)
853856
status, content, json = self._api_call(
@@ -892,9 +895,10 @@ def delete_spoken_terms_list(
892895
def _spoken_terms_json(entries: SpokenTermsEntries) -> dict:
893896
# Terms are sent newline-separated: a term with a newline would
894897
# silently become several terms.
895-
for term in entries.entries:
898+
terms = [term.strip() for term in entries.entries]
899+
for term in terms:
896900
util.validate_glossary_term(term)
897-
return entries.to_json()
901+
return SpokenTermsEntries(entries.lang, terms).to_json()
898902

899903
@staticmethod
900904
def _spoken_terms_id(spoken_terms: Union[str, SpokenTerms]) -> str:

‎tests/offline/test_spoken_terms.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,22 @@ def test_url_encodes_the_id_in_the_path(mocked):
7171
mocked.delete(url("v3/spoken-terms/a%2Fb%3Fc"), status=204)
7272

7373
make_deepl_client().delete_spoken_terms("a/b?c")
74+
75+
76+
def test_strips_terms_before_sending(mocked):
77+
mocked.put(
78+
url("v3/spoken-terms/st-1/term-lists"),
79+
json={"lang": "en", "entry_count": 2},
80+
match=json_request({"lang": "en", "entries": "DeepL\nwebhook"}),
81+
)
82+
83+
make_deepl_client().replace_spoken_terms_list(
84+
"st-1", deepl.SpokenTermsEntries("en", [" DeepL ", "webhook\t"])
85+
)
86+
87+
88+
def test_rejects_a_whitespace_only_term(mocked):
89+
with pytest.raises(ValueError, match="not a valid string"):
90+
make_deepl_client().create_spoken_terms(
91+
"terms", [deepl.SpokenTermsEntries("en", ["a", " "])]
92+
)

0 commit comments

Comments
 (0)