python-iso639 2025.1.28__tar.gz → 2025.2.18__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/CHANGELOG.md +11 -0
- {python_iso639-2025.1.28/src/python_iso639.egg-info → python_iso639-2025.2.18}/PKG-INFO +32 -7
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/README.md +29 -4
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/pyproject.toml +4 -4
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/language.py +72 -16
- python_iso639-2025.2.18/src/iso639/py.typed +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18/src/python_iso639.egg-info}/PKG-INFO +32 -7
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/python_iso639.egg-info/SOURCES.txt +1 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/python_iso639.egg-info/requires.txt +2 -2
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/tests/test_language.py +25 -9
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/LICENSE.txt +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/MANIFEST.in +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/setup.cfg +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/__init__.py +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/__init__.py +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/iso-639-3-macrolanguages.tab +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/iso-639-3.tab +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/iso-639-3_Name_Index.tab +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/iso-639-3_Retirements.tab +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/python_iso639.egg-info/dependency_links.txt +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/python_iso639.egg-info/not-zip-safe +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/python_iso639.egg-info/top_level.txt +0 -0
- {python_iso639-2025.1.28 → python_iso639-2025.2.18}/tests/test_version_number.py +0 -0
|
@@ -17,6 +17,17 @@ major/minor/micro version numbers like `05` (it'd have to be just `5`).
|
|
|
17
17
|
### Fixed
|
|
18
18
|
### Security
|
|
19
19
|
|
|
20
|
+
## [2025.2.18]
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
* `Language.match` now supports case-insensitive matching
|
|
24
|
+
and ignores leading/trailing whitespace by default.
|
|
25
|
+
|
|
26
|
+
## [2025.2.8]
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
* Explicitly indicated that the library is type-annotated.
|
|
30
|
+
|
|
20
31
|
## [2025.1.28]
|
|
21
32
|
|
|
22
33
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: python-iso639
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.2.18
|
|
4
4
|
Summary: ISO 639 language codes, names, and other associated information
|
|
5
5
|
Author-email: "Jackson L. Lee" <jacksonlunlee@gmail.com>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -28,10 +28,10 @@ Requires-Python: >=3.9
|
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
License-File: LICENSE.txt
|
|
30
30
|
Provides-Extra: dev
|
|
31
|
-
Requires-Dist: black==
|
|
31
|
+
Requires-Dist: black==25.1.0; extra == "dev"
|
|
32
32
|
Requires-Dist: build==1.2.2; extra == "dev"
|
|
33
33
|
Requires-Dist: flake8==7.1.1; extra == "dev"
|
|
34
|
-
Requires-Dist: mypy==1.
|
|
34
|
+
Requires-Dist: mypy==1.15.0; extra == "dev"
|
|
35
35
|
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
36
36
|
Requires-Dist: requests==2.32.3; extra == "dev"
|
|
37
37
|
Requires-Dist: twine==6.1.0; extra == "dev"
|
|
@@ -48,9 +48,10 @@ other associated information.
|
|
|
48
48
|
|
|
49
49
|
Current features:
|
|
50
50
|
|
|
51
|
-
* A representation of languages mapped across ISO 639-1, 639-2, and 639-3.
|
|
52
|
-
* Functionality to "guess" what a language is for a given
|
|
51
|
+
* 🌐 A representation of languages mapped across ISO 639-1, 639-2, and 639-3.
|
|
52
|
+
* 🔎 Functionality to "guess" what a language is for a given
|
|
53
53
|
unknown language code or name.
|
|
54
|
+
* 🚀 Optimized for speed in retrieving language information.
|
|
54
55
|
|
|
55
56
|
## Installation
|
|
56
57
|
|
|
@@ -82,6 +83,15 @@ Create a `Language` instance by one of the class methods.
|
|
|
82
83
|
Language(part3='fra', part2b='fre', part2t='fra', part1='fr', scope='I', type='L', name='French', comment=None, other_names=None, macrolanguage=None, retire_reason=None, retire_change_to=None, retire_remedy=None, retire_date=None)
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
Fast object instantiation for retrieving language information (run on Python 3.13, macOS 15.3.1, Apple M1 Pro)
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
In [1]: import iso639
|
|
90
|
+
|
|
91
|
+
In [2]: %timeit iso639.Language.from_part3("fra")
|
|
92
|
+
217 ns ± 0.139 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
|
|
93
|
+
```
|
|
94
|
+
|
|
85
95
|
#### From Another ISO 639 Code Set or a Reference Name
|
|
86
96
|
|
|
87
97
|
```python
|
|
@@ -144,11 +154,27 @@ Use the `match` classmethod:
|
|
|
144
154
|
True
|
|
145
155
|
```
|
|
146
156
|
|
|
157
|
+
By default, the classmethod `match` supports case-insensitive matching
|
|
158
|
+
and ignores leading/trailing whitespace.
|
|
159
|
+
To enforce exact matching instead, pass in `exact=True`:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
>>> lang5 = iso639.Language.match('FRA')
|
|
163
|
+
>>> lang6 = iso639.Language.match('fra ')
|
|
164
|
+
>>> lang7 = iso639.Language.match('french')
|
|
165
|
+
>>> lang4 == lang5 == lang6 == lang7
|
|
166
|
+
True
|
|
167
|
+
>>> iso639.Language.match("french", exact=True)
|
|
168
|
+
Traceback (most recent call last):
|
|
169
|
+
File "<stdin>", line 1, in <module>
|
|
170
|
+
LanguageNotFoundError: 'french' isn't an ISO language code or name
|
|
171
|
+
```
|
|
172
|
+
|
|
147
173
|
The classmethod `match` is particularly useful for consistently
|
|
148
174
|
accessing a specific attribute from unknown inputs, e.g., the ISO 639-3 code.
|
|
149
175
|
|
|
150
176
|
```python
|
|
151
|
-
>>> 'fra' == lang1.part3 == lang2.part3 == lang3.part3 == lang4.part3
|
|
177
|
+
>>> 'fra' == lang1.part3 == lang2.part3 == lang3.part3 == lang4.part3 == lang5.part3 == lang6.part3 == lang7.part3
|
|
152
178
|
True
|
|
153
179
|
```
|
|
154
180
|
|
|
@@ -251,7 +277,6 @@ Beyond that, the precise order in matching is as follows:
|
|
|
251
277
|
* ISO 639-3 alternative language names (the "print" ones)
|
|
252
278
|
* ISO 639-3 alternative language names (the "inverted" ones)
|
|
253
279
|
|
|
254
|
-
Only exact matching is done (there's no fuzzy string matching of any sort).
|
|
255
280
|
As soon as a match is found, `Language.match` returns a `Language` instance.
|
|
256
281
|
If there isn't a match, a `LanguageNotFoundError` is raised.
|
|
257
282
|
|
|
@@ -10,9 +10,10 @@ other associated information.
|
|
|
10
10
|
|
|
11
11
|
Current features:
|
|
12
12
|
|
|
13
|
-
* A representation of languages mapped across ISO 639-1, 639-2, and 639-3.
|
|
14
|
-
* Functionality to "guess" what a language is for a given
|
|
13
|
+
* 🌐 A representation of languages mapped across ISO 639-1, 639-2, and 639-3.
|
|
14
|
+
* 🔎 Functionality to "guess" what a language is for a given
|
|
15
15
|
unknown language code or name.
|
|
16
|
+
* 🚀 Optimized for speed in retrieving language information.
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -44,6 +45,15 @@ Create a `Language` instance by one of the class methods.
|
|
|
44
45
|
Language(part3='fra', part2b='fre', part2t='fra', part1='fr', scope='I', type='L', name='French', comment=None, other_names=None, macrolanguage=None, retire_reason=None, retire_change_to=None, retire_remedy=None, retire_date=None)
|
|
45
46
|
```
|
|
46
47
|
|
|
48
|
+
Fast object instantiation for retrieving language information (run on Python 3.13, macOS 15.3.1, Apple M1 Pro)
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
In [1]: import iso639
|
|
52
|
+
|
|
53
|
+
In [2]: %timeit iso639.Language.from_part3("fra")
|
|
54
|
+
217 ns ± 0.139 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
|
|
55
|
+
```
|
|
56
|
+
|
|
47
57
|
#### From Another ISO 639 Code Set or a Reference Name
|
|
48
58
|
|
|
49
59
|
```python
|
|
@@ -106,11 +116,27 @@ Use the `match` classmethod:
|
|
|
106
116
|
True
|
|
107
117
|
```
|
|
108
118
|
|
|
119
|
+
By default, the classmethod `match` supports case-insensitive matching
|
|
120
|
+
and ignores leading/trailing whitespace.
|
|
121
|
+
To enforce exact matching instead, pass in `exact=True`:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
>>> lang5 = iso639.Language.match('FRA')
|
|
125
|
+
>>> lang6 = iso639.Language.match('fra ')
|
|
126
|
+
>>> lang7 = iso639.Language.match('french')
|
|
127
|
+
>>> lang4 == lang5 == lang6 == lang7
|
|
128
|
+
True
|
|
129
|
+
>>> iso639.Language.match("french", exact=True)
|
|
130
|
+
Traceback (most recent call last):
|
|
131
|
+
File "<stdin>", line 1, in <module>
|
|
132
|
+
LanguageNotFoundError: 'french' isn't an ISO language code or name
|
|
133
|
+
```
|
|
134
|
+
|
|
109
135
|
The classmethod `match` is particularly useful for consistently
|
|
110
136
|
accessing a specific attribute from unknown inputs, e.g., the ISO 639-3 code.
|
|
111
137
|
|
|
112
138
|
```python
|
|
113
|
-
>>> 'fra' == lang1.part3 == lang2.part3 == lang3.part3 == lang4.part3
|
|
139
|
+
>>> 'fra' == lang1.part3 == lang2.part3 == lang3.part3 == lang4.part3 == lang5.part3 == lang6.part3 == lang7.part3
|
|
114
140
|
True
|
|
115
141
|
```
|
|
116
142
|
|
|
@@ -213,7 +239,6 @@ Beyond that, the precise order in matching is as follows:
|
|
|
213
239
|
* ISO 639-3 alternative language names (the "print" ones)
|
|
214
240
|
* ISO 639-3 alternative language names (the "inverted" ones)
|
|
215
241
|
|
|
216
|
-
Only exact matching is done (there's no fuzzy string matching of any sort).
|
|
217
242
|
As soon as a match is found, `Language.match` returns a `Language` instance.
|
|
218
243
|
If there isn't a match, a `LanguageNotFoundError` is raised.
|
|
219
244
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-iso639"
|
|
7
|
-
version = "2025.
|
|
7
|
+
version = "2025.2.18"
|
|
8
8
|
description = "ISO 639 language codes, names, and other associated information"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">= 3.9"
|
|
@@ -34,10 +34,10 @@ classifiers = [
|
|
|
34
34
|
|
|
35
35
|
[project.optional-dependencies]
|
|
36
36
|
dev = [
|
|
37
|
-
"black ==
|
|
37
|
+
"black == 25.1.0",
|
|
38
38
|
"build == 1.2.2",
|
|
39
39
|
"flake8 == 7.1.1",
|
|
40
|
-
"mypy == 1.
|
|
40
|
+
"mypy == 1.15.0",
|
|
41
41
|
"pytest == 8.3.4",
|
|
42
42
|
"requests == 2.32.3",
|
|
43
43
|
"twine == 6.1.0",
|
|
@@ -52,7 +52,7 @@ where = [ "src" ]
|
|
|
52
52
|
[tool.setuptools]
|
|
53
53
|
zip-safe = false
|
|
54
54
|
package-dir = { "" = "src" }
|
|
55
|
-
package-data = { "iso639" = ["_data/*.tab"] }
|
|
55
|
+
package-data = { "iso639" = ["_data/*.tab", "py.typed"] }
|
|
56
56
|
|
|
57
57
|
[tool.pytest.ini_options]
|
|
58
58
|
addopts = "-vv --durations=0 --strict-markers"
|
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import datetime
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
|
|
8
|
-
from typing import Dict, List, Union, Set
|
|
8
|
+
from typing import Dict, List, NoReturn, Optional, Union, Set
|
|
9
9
|
|
|
10
10
|
from ._data import (
|
|
11
11
|
_PART3_TO_CODES,
|
|
@@ -26,6 +26,12 @@ from ._data import (
|
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
_STRING_CLEANING_FUNCS = [
|
|
30
|
+
lambda x: x.strip().lower(),
|
|
31
|
+
lambda x: x.strip().title(),
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
29
35
|
class LanguageNotFoundError(Exception):
|
|
30
36
|
pass
|
|
31
37
|
|
|
@@ -100,13 +106,17 @@ class Language:
|
|
|
100
106
|
return isinstance(other, Language) and self.part3 == other.part3
|
|
101
107
|
|
|
102
108
|
@classmethod
|
|
103
|
-
def match(cls, user_input: str,
|
|
109
|
+
def match(cls, user_input: str, /, *, exact: bool = False) -> Language:
|
|
104
110
|
"""Return a ``Language`` instance by matching on the user input.
|
|
105
111
|
|
|
106
112
|
Parameters
|
|
107
113
|
----------
|
|
108
114
|
user_input : str
|
|
109
115
|
A language code or name.
|
|
116
|
+
exact : bool, optional
|
|
117
|
+
Whether to enforce exact matching against the user input.
|
|
118
|
+
Defaults to `False`. If `False`, matching is case-insensitive
|
|
119
|
+
and ignores leading/trailing whitespace.
|
|
110
120
|
|
|
111
121
|
Returns
|
|
112
122
|
-------
|
|
@@ -140,29 +150,29 @@ class Language:
|
|
|
140
150
|
_NameIndexColumn.PRINT_NAME,
|
|
141
151
|
_NameIndexColumn.INVERTED_NAME,
|
|
142
152
|
]
|
|
143
|
-
return _PART3_TO_LANGUAGES[_get_part3(user_input, query_order)]
|
|
153
|
+
return _PART3_TO_LANGUAGES[_get_part3(user_input, query_order, exact)]
|
|
144
154
|
|
|
145
155
|
@classmethod
|
|
146
156
|
def from_part3(cls, user_input: str, /) -> Language:
|
|
147
157
|
"""Return a ``Language`` instance from an ISO 639-3 code."""
|
|
148
158
|
return _PART3_TO_LANGUAGES[
|
|
149
|
-
|
|
159
|
+
_get_part3_exact(user_input, [_CodesColumn.ID, _RetirementsColumn.ID])
|
|
150
160
|
]
|
|
151
161
|
|
|
152
162
|
@classmethod
|
|
153
163
|
def from_part2b(cls, user_input: str, /) -> Language:
|
|
154
164
|
"""Return a ``Language`` instance from an ISO 639-2 (bibliographic) code."""
|
|
155
|
-
return _PART3_TO_LANGUAGES[
|
|
165
|
+
return _PART3_TO_LANGUAGES[_get_part3_exact(user_input, [_CodesColumn.PART2B])]
|
|
156
166
|
|
|
157
167
|
@classmethod
|
|
158
168
|
def from_part2t(cls, user_input: str, /) -> Language:
|
|
159
169
|
"""Return a ``Language`` instance from an ISO 639-2 (terminological) code."""
|
|
160
|
-
return _PART3_TO_LANGUAGES[
|
|
170
|
+
return _PART3_TO_LANGUAGES[_get_part3_exact(user_input, [_CodesColumn.PART2T])]
|
|
161
171
|
|
|
162
172
|
@classmethod
|
|
163
173
|
def from_part1(cls, user_input: str, /) -> Language:
|
|
164
174
|
"""Return a ``Language`` instance from an ISO 639-1 code."""
|
|
165
|
-
return _PART3_TO_LANGUAGES[
|
|
175
|
+
return _PART3_TO_LANGUAGES[_get_part3_exact(user_input, [_CodesColumn.PART1])]
|
|
166
176
|
|
|
167
177
|
@classmethod
|
|
168
178
|
def from_name(cls, user_input: str, /) -> Language:
|
|
@@ -172,10 +182,57 @@ class Language:
|
|
|
172
182
|
_NameIndexColumn.PRINT_NAME,
|
|
173
183
|
_NameIndexColumn.INVERTED_NAME,
|
|
174
184
|
]
|
|
175
|
-
return _PART3_TO_LANGUAGES[
|
|
185
|
+
return _PART3_TO_LANGUAGES[_get_part3_exact(user_input, query_order)]
|
|
186
|
+
|
|
176
187
|
|
|
188
|
+
def _raise_language_not_found_error(user_input: str) -> NoReturn:
|
|
189
|
+
raise LanguageNotFoundError(f"{user_input!r} isn't an ISO language code or name")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _get_part3(
|
|
193
|
+
user_input: str, query_order: List[_COLUMN_TYPE], exact: bool = True
|
|
194
|
+
) -> str:
|
|
195
|
+
"""Get the part 3 code of a language.
|
|
177
196
|
|
|
178
|
-
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
user_input : str
|
|
200
|
+
The user-provided language code or name.
|
|
201
|
+
query_order : List[_COLUMN_TYPE]
|
|
202
|
+
A list of columns to specify query order.
|
|
203
|
+
exact : bool, optional
|
|
204
|
+
Whether to enforce exact matching against the user input. Defaults to `True`.
|
|
205
|
+
If `False`, basic string cleaning is applied to the user input.
|
|
206
|
+
|
|
207
|
+
Returns
|
|
208
|
+
-------
|
|
209
|
+
str
|
|
210
|
+
|
|
211
|
+
Raises
|
|
212
|
+
------
|
|
213
|
+
LanguageNotFoundError
|
|
214
|
+
If `part3` isn't a language name or code
|
|
215
|
+
"""
|
|
216
|
+
try:
|
|
217
|
+
return _get_part3_exact(user_input, query_order)
|
|
218
|
+
except LanguageNotFoundError as e:
|
|
219
|
+
if exact:
|
|
220
|
+
raise e
|
|
221
|
+
else:
|
|
222
|
+
for func in _STRING_CLEANING_FUNCS:
|
|
223
|
+
try:
|
|
224
|
+
return _get_part3_exact(func(user_input), query_order, user_input)
|
|
225
|
+
except LanguageNotFoundError:
|
|
226
|
+
continue
|
|
227
|
+
else:
|
|
228
|
+
_raise_language_not_found_error(user_input)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _get_part3_exact(
|
|
232
|
+
user_input: str,
|
|
233
|
+
query_order: List[_COLUMN_TYPE],
|
|
234
|
+
original_user_input: Optional[str] = None,
|
|
235
|
+
) -> str:
|
|
179
236
|
"""Get the part 3 code of a language.
|
|
180
237
|
|
|
181
238
|
Parameters
|
|
@@ -184,6 +241,9 @@ def _get_part3(user_input: str, query_order: List[_COLUMN_TYPE]) -> str:
|
|
|
184
241
|
The user-provided language code or name.
|
|
185
242
|
query_order : List[_COLUMN_TYPE]
|
|
186
243
|
A list of columns to specify query order.
|
|
244
|
+
original_user_input : str, optional
|
|
245
|
+
The original user input. Default is `None`.
|
|
246
|
+
This argument is used when the user input has been cleaned.
|
|
187
247
|
|
|
188
248
|
Returns
|
|
189
249
|
-------
|
|
@@ -198,8 +258,7 @@ def _get_part3(user_input: str, query_order: List[_COLUMN_TYPE]) -> str:
|
|
|
198
258
|
for column in query_order:
|
|
199
259
|
if column == _CodesColumn.ID:
|
|
200
260
|
if user_input in _PART3_TO_CODES:
|
|
201
|
-
|
|
202
|
-
break
|
|
261
|
+
return user_input
|
|
203
262
|
elif column == _CodesColumn.PART2B:
|
|
204
263
|
part3 = _PART2B_TO_PART3.get(user_input)
|
|
205
264
|
elif column == _CodesColumn.PART2T:
|
|
@@ -208,8 +267,7 @@ def _get_part3(user_input: str, query_order: List[_COLUMN_TYPE]) -> str:
|
|
|
208
267
|
part3 = _PART1_TO_PART3.get(user_input)
|
|
209
268
|
elif column == _RetirementsColumn.ID:
|
|
210
269
|
if user_input in _PART3_TO_RETIREMENTS:
|
|
211
|
-
|
|
212
|
-
break
|
|
270
|
+
return user_input
|
|
213
271
|
elif column == _CodesColumn.REF_NAME:
|
|
214
272
|
part3 = _REF_NAME_TO_PART3.get(user_input)
|
|
215
273
|
elif column == _NameIndexColumn.PRINT_NAME:
|
|
@@ -222,9 +280,7 @@ def _get_part3(user_input: str, query_order: List[_COLUMN_TYPE]) -> str:
|
|
|
222
280
|
break
|
|
223
281
|
|
|
224
282
|
if part3 is None:
|
|
225
|
-
|
|
226
|
-
f"{user_input!r} isn't an ISO language code or name"
|
|
227
|
-
)
|
|
283
|
+
_raise_language_not_found_error(original_user_input or user_input)
|
|
228
284
|
|
|
229
285
|
return part3
|
|
230
286
|
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: python-iso639
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.2.18
|
|
4
4
|
Summary: ISO 639 language codes, names, and other associated information
|
|
5
5
|
Author-email: "Jackson L. Lee" <jacksonlunlee@gmail.com>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -28,10 +28,10 @@ Requires-Python: >=3.9
|
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
License-File: LICENSE.txt
|
|
30
30
|
Provides-Extra: dev
|
|
31
|
-
Requires-Dist: black==
|
|
31
|
+
Requires-Dist: black==25.1.0; extra == "dev"
|
|
32
32
|
Requires-Dist: build==1.2.2; extra == "dev"
|
|
33
33
|
Requires-Dist: flake8==7.1.1; extra == "dev"
|
|
34
|
-
Requires-Dist: mypy==1.
|
|
34
|
+
Requires-Dist: mypy==1.15.0; extra == "dev"
|
|
35
35
|
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
36
36
|
Requires-Dist: requests==2.32.3; extra == "dev"
|
|
37
37
|
Requires-Dist: twine==6.1.0; extra == "dev"
|
|
@@ -48,9 +48,10 @@ other associated information.
|
|
|
48
48
|
|
|
49
49
|
Current features:
|
|
50
50
|
|
|
51
|
-
* A representation of languages mapped across ISO 639-1, 639-2, and 639-3.
|
|
52
|
-
* Functionality to "guess" what a language is for a given
|
|
51
|
+
* 🌐 A representation of languages mapped across ISO 639-1, 639-2, and 639-3.
|
|
52
|
+
* 🔎 Functionality to "guess" what a language is for a given
|
|
53
53
|
unknown language code or name.
|
|
54
|
+
* 🚀 Optimized for speed in retrieving language information.
|
|
54
55
|
|
|
55
56
|
## Installation
|
|
56
57
|
|
|
@@ -82,6 +83,15 @@ Create a `Language` instance by one of the class methods.
|
|
|
82
83
|
Language(part3='fra', part2b='fre', part2t='fra', part1='fr', scope='I', type='L', name='French', comment=None, other_names=None, macrolanguage=None, retire_reason=None, retire_change_to=None, retire_remedy=None, retire_date=None)
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
Fast object instantiation for retrieving language information (run on Python 3.13, macOS 15.3.1, Apple M1 Pro)
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
In [1]: import iso639
|
|
90
|
+
|
|
91
|
+
In [2]: %timeit iso639.Language.from_part3("fra")
|
|
92
|
+
217 ns ± 0.139 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
|
|
93
|
+
```
|
|
94
|
+
|
|
85
95
|
#### From Another ISO 639 Code Set or a Reference Name
|
|
86
96
|
|
|
87
97
|
```python
|
|
@@ -144,11 +154,27 @@ Use the `match` classmethod:
|
|
|
144
154
|
True
|
|
145
155
|
```
|
|
146
156
|
|
|
157
|
+
By default, the classmethod `match` supports case-insensitive matching
|
|
158
|
+
and ignores leading/trailing whitespace.
|
|
159
|
+
To enforce exact matching instead, pass in `exact=True`:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
>>> lang5 = iso639.Language.match('FRA')
|
|
163
|
+
>>> lang6 = iso639.Language.match('fra ')
|
|
164
|
+
>>> lang7 = iso639.Language.match('french')
|
|
165
|
+
>>> lang4 == lang5 == lang6 == lang7
|
|
166
|
+
True
|
|
167
|
+
>>> iso639.Language.match("french", exact=True)
|
|
168
|
+
Traceback (most recent call last):
|
|
169
|
+
File "<stdin>", line 1, in <module>
|
|
170
|
+
LanguageNotFoundError: 'french' isn't an ISO language code or name
|
|
171
|
+
```
|
|
172
|
+
|
|
147
173
|
The classmethod `match` is particularly useful for consistently
|
|
148
174
|
accessing a specific attribute from unknown inputs, e.g., the ISO 639-3 code.
|
|
149
175
|
|
|
150
176
|
```python
|
|
151
|
-
>>> 'fra' == lang1.part3 == lang2.part3 == lang3.part3 == lang4.part3
|
|
177
|
+
>>> 'fra' == lang1.part3 == lang2.part3 == lang3.part3 == lang4.part3 == lang5.part3 == lang6.part3 == lang7.part3
|
|
152
178
|
True
|
|
153
179
|
```
|
|
154
180
|
|
|
@@ -251,7 +277,6 @@ Beyond that, the precise order in matching is as follows:
|
|
|
251
277
|
* ISO 639-3 alternative language names (the "print" ones)
|
|
252
278
|
* ISO 639-3 alternative language names (the "inverted" ones)
|
|
253
279
|
|
|
254
|
-
Only exact matching is done (there's no fuzzy string matching of any sort).
|
|
255
280
|
As soon as a match is found, `Language.match` returns a `Language` instance.
|
|
256
281
|
If there isn't a match, a `LanguageNotFoundError` is raised.
|
|
257
282
|
|
|
@@ -7,18 +7,34 @@ import pytest
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@pytest.mark.parametrize(
|
|
10
|
-
"user_input, expected_part3",
|
|
10
|
+
"user_input, exact, expected_part3",
|
|
11
11
|
[
|
|
12
|
-
("fra", "fra"),
|
|
13
|
-
("
|
|
14
|
-
("
|
|
15
|
-
("
|
|
16
|
-
("
|
|
12
|
+
("fra", True, "fra"),
|
|
13
|
+
("fra", False, "fra"),
|
|
14
|
+
("FRA", True, None),
|
|
15
|
+
("FRA", False, "fra"),
|
|
16
|
+
(" FRA ", False, "fra"),
|
|
17
|
+
("Fra", True, None),
|
|
18
|
+
("Fra", False, "fra"),
|
|
19
|
+
(" Fra ", False, "fra"),
|
|
20
|
+
("French", True, "fra"),
|
|
21
|
+
("French", False, "fra"),
|
|
22
|
+
("FRENCH", True, None),
|
|
23
|
+
("FRENCH", False, "fra"),
|
|
24
|
+
(" FRENCH ", False, "fra"),
|
|
25
|
+
("french", True, None),
|
|
26
|
+
("french", False, "fra"),
|
|
27
|
+
(" french ", False, "fra"),
|
|
28
|
+
("Castilian", True, "spa"),
|
|
17
29
|
],
|
|
18
30
|
)
|
|
19
|
-
def test_match(user_input, expected_part3):
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
def test_match(user_input, exact, expected_part3):
|
|
32
|
+
if expected_part3 is None:
|
|
33
|
+
with pytest.raises(LanguageNotFoundError):
|
|
34
|
+
Language.match(user_input, exact=exact)
|
|
35
|
+
else:
|
|
36
|
+
actual_part3 = Language.match(user_input, exact=exact).part3
|
|
37
|
+
assert actual_part3 == expected_part3
|
|
22
38
|
|
|
23
39
|
|
|
24
40
|
def test_name():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/iso-639-3-macrolanguages.tab
RENAMED
|
File without changes
|
|
File without changes
|
{python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/iso-639-3_Name_Index.tab
RENAMED
|
File without changes
|
{python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/iso639/_data/iso-639-3_Retirements.tab
RENAMED
|
File without changes
|
{python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/python_iso639.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{python_iso639-2025.1.28 → python_iso639-2025.2.18}/src/python_iso639.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|