Repository navigation
Expand file tree
/
Copy pathutil.py
More file actions
116 lines (95 loc) · 3.71 KB
/
Copy pathutil.py
File metadata and controls
116 lines (95 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Copyright 2022 DeepL SE (https://www.deepl.com)
# Use of this source code is governed by an MIT
# license that can be found in the LICENSE file.
import itertools
import logging
from typing import Dict, Optional
logger = logging.getLogger("deepl")
def _get_log_text(message, **kwargs):
return (
message
+ " "
+ " ".join(f"{key}={value}" for key, value in sorted(kwargs.items()))
)
def log_debug(message, **kwargs):
text = _get_log_text(message, **kwargs)
logger.debug(text)
def log_info(message, **kwargs):
text = _get_log_text(message, **kwargs)
logger.info(text)
def get_int_safe(d: dict, key: str) -> Optional[int]:
"""Returns value in dictionary with given key as int, or None."""
try:
return int(d.get(key))
except (TypeError, ValueError):
return None
def auth_key_is_free_account(auth_key: str) -> bool:
"""Returns True if the given authentication key belongs to a DeepL API Free
account, otherwise False."""
return auth_key.endswith(":fx")
def validate_glossary_term(term: str) -> None:
"""Checks if the given glossary term contains any disallowed characters.
:param term: Glossary term to check for validity.
:raises ValueError: If the term is not valid or a disallowed character is
found."""
if len(term) == 0:
raise ValueError(f'Term "{term}" is not a valid string')
if any(
(
0 <= ord(char) <= 31 # C0 control characters
or 128 <= ord(char) <= 159 # C1 control characters
or char in "\u2028\u2029" # Unicode newlines
)
for char in term
):
raise ValueError(f'Term "{term}" contains invalid character')
def convert_tsv_to_dict(
tsv: str, term_separator: str = "\t", skip_checks: bool = False
) -> dict:
"""Converts the given tab-separated values (TSV) string to an entries
dictionary for use in a glossary. Each line should contain a source and
target term separated by a tab. Empty lines are ignored.
:param tsv: string containing TSV to parse.
:param term_separator: optional term separator to use.
:param skip_checks: set to True to override entry validation.
:return: dictionary containing parsed entries.
"""
entries_dict = {}
for line, index in zip(tsv.splitlines(), itertools.count(1)):
if not line:
continue
if term_separator not in line:
raise ValueError(
f"Entry {index} does not contain separator: {line}"
)
source, target = line.split(term_separator, 1)
source, target = source.strip(), target.strip()
if source in entries_dict:
raise ValueError(
f'Entry {index} duplicates source term "{source}"'
)
if term_separator in target:
raise ValueError(
f"Entry {index} contains more than one term separator: {line}"
)
if not skip_checks:
validate_glossary_term(source)
validate_glossary_term(target)
entries_dict[source] = target
return entries_dict
def convert_dict_to_tsv(
entry_dict: Dict[str, str], skip_checks: bool = False
) -> str:
"""Converts the given glossary entries dictionary to a tab-separated values
(TSV) string.
:param entry_dict: dictionary containing glossary entries.
:param skip_checks: set to True to override entry validation.
:return: string containing entries in TSV format.
"""
if not skip_checks:
for source, target in entry_dict.items():
validate_glossary_term(source.strip())
validate_glossary_term(target.strip())
return "\n".join(
f"{s.strip()}\t{t.strip()}" for s, t in entry_dict.items()
)