python-iso639 2024.4.27__tar.gz → 2025.1.27__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.
Files changed (25) hide show
  1. python_iso639-2025.1.27/CHANGELOG.md +102 -0
  2. python_iso639-2025.1.27/MANIFEST.in +1 -0
  3. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/PKG-INFO +20 -18
  4. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/README.md +9 -8
  5. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/pyproject.toml +11 -10
  6. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/src/iso639/__init__.py +14 -9
  7. python_iso639-2025.1.27/src/iso639/_data/__init__.py +119 -0
  8. python_iso639-2025.1.27/src/iso639/_data/iso-639-3-macrolanguages.tab +460 -0
  9. python_iso639-2025.1.27/src/iso639/_data/iso-639-3.tab +7923 -0
  10. python_iso639-2025.1.27/src/iso639/_data/iso-639-3_Name_Index.tab +8297 -0
  11. python_iso639-2025.1.27/src/iso639/_data/iso-639-3_Retirements.tab +389 -0
  12. python_iso639-2025.1.27/src/iso639/language.py +310 -0
  13. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/src/python_iso639.egg-info/PKG-INFO +20 -18
  14. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/src/python_iso639.egg-info/SOURCES.txt +7 -1
  15. python_iso639-2025.1.27/src/python_iso639.egg-info/requires.txt +9 -0
  16. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/tests/test_language.py +33 -15
  17. python_iso639-2024.4.27/src/iso639/language.py +0 -275
  18. python_iso639-2024.4.27/src/iso639/languages.db +0 -0
  19. python_iso639-2024.4.27/src/python_iso639.egg-info/requires.txt +0 -8
  20. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/LICENSE.txt +0 -0
  21. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/setup.cfg +0 -0
  22. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/src/python_iso639.egg-info/dependency_links.txt +0 -0
  23. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/src/python_iso639.egg-info/not-zip-safe +0 -0
  24. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/src/python_iso639.egg-info/top_level.txt +0 -0
  25. {python_iso639-2024.4.27 → python_iso639-2025.1.27}/tests/test_version_number.py +0 -0
@@ -0,0 +1,102 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
+
6
+ The version number is based on [calendar versioning](https://calver.org/).
7
+ The specific format is `YYYY.(M)M.(D)D`,
8
+ where the month and day may be single-digit because Python doesn't allow zero-padded
9
+ major/minor/micro version numbers like `05` (it'd have to be just `5`).
10
+
11
+ ## [Unreleased]
12
+
13
+ ### Added
14
+ ### Changed
15
+ ### Deprecated
16
+ ### Removed
17
+ ### Fixed
18
+ ### Security
19
+
20
+ ## [2025.1.27]
21
+
22
+ ### Changed
23
+ * Updated the ISO 639 data from SIL to the latest 2025-01-15 release.
24
+ * The data tables are now included as the original tab-separated value files
25
+ instead of a compiled SQLite database.
26
+
27
+ ### Fixed
28
+ * Fixed `Language.from_part3` so that it now also works for a retired ISO 639-3 code.
29
+
30
+ ## [2024.10.22]
31
+
32
+ ### Added
33
+ * Added support for Python 3.13.
34
+
35
+ ### Removed
36
+ * Dropped support for Python 3.8.
37
+
38
+ ### Fixed
39
+ * Added `CHANGELOG.md` to the PyPI source distribution.
40
+
41
+ ## [2024.4.27]
42
+
43
+ ### Changed
44
+ * Updated the ISO 639 data from SIL to the latest 2024-04-15 release.
45
+
46
+ ## [2024.2.7]
47
+
48
+ ### Changed
49
+ * Updated the ISO 639 data from SIL to the latest 2024-01-10 release.
50
+
51
+ ## [2024.1.2]
52
+
53
+ ### Changed
54
+ * Updated the ISO 639 data from SIL to the latest 2023-12-20 release.
55
+
56
+ ## [2023.12.11]
57
+
58
+ ### Added
59
+ * Added support for Python 3.12.
60
+
61
+ ## [2023.6.15]
62
+
63
+ ### Fixed
64
+ * Made `Language` class instances actually hashable (#3).
65
+
66
+ ## [2023.4.13]
67
+
68
+ ### Changed
69
+ * Disabled thread checking for the database, as it's read-only (#1).
70
+
71
+ ## [2023.2.4]
72
+
73
+ ### Changed
74
+ * Updated the ISO 639 data from SIL to the latest 2023-01-23 release.
75
+
76
+ ## [2022.11.27]
77
+
78
+ ### Added
79
+ * Defined the `LanguageNotFoundError` exception.
80
+ * Added support for Python 3.11.
81
+
82
+ ### Changed
83
+ * If the `Language` class methods `match`, `from_part3`, etc. receive an invalid
84
+ input language code or name, a `LanguageNotFoundError` is now raised.
85
+ (Previously, `None` was returned with no exception raised.)
86
+
87
+ ### Removed
88
+ * Dropped support for Python 3.7.
89
+
90
+ ## [2022.9.17]
91
+
92
+ ### Added
93
+ * Added constants `DATA_LAST_UPDATED` and `ALL_LANGUAGES`.
94
+
95
+ ## [2022.5.16]
96
+
97
+ ### Fixed
98
+ * Corrected repo name in package metadata and documentation.
99
+
100
+ ## [2022.5.15]
101
+
102
+ * First release!
@@ -0,0 +1 @@
1
+ include CHANGELOG.md
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: python-iso639
3
- Version: 2024.4.27
3
+ Version: 2025.1.27
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
@@ -15,25 +15,26 @@ Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Programming Language :: Python :: 3 :: Only
18
- Classifier: Programming Language :: Python :: 3.8
19
18
  Classifier: Programming Language :: Python :: 3.9
20
19
  Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
22
21
  Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
23
  Classifier: Topic :: Text Processing
24
24
  Classifier: Topic :: Text Processing :: General
25
25
  Classifier: Topic :: Text Processing :: Indexing
26
26
  Classifier: Topic :: Text Processing :: Linguistic
27
- Requires-Python: >=3.8
27
+ 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==24.4.2; extra == "dev"
32
- Requires-Dist: build==1.2.1; extra == "dev"
33
- Requires-Dist: flake8==7.0.0; extra == "dev"
34
- Requires-Dist: pytest==8.1.2; extra == "dev"
35
- Requires-Dist: requests==2.31.0; extra == "dev"
36
- Requires-Dist: twine==5.0.0; extra == "dev"
31
+ Requires-Dist: black==24.10.0; extra == "dev"
32
+ Requires-Dist: build==1.2.2; extra == "dev"
33
+ Requires-Dist: flake8==7.1.1; extra == "dev"
34
+ Requires-Dist: mypy==1.14.1; extra == "dev"
35
+ Requires-Dist: pytest==8.3.4; extra == "dev"
36
+ Requires-Dist: requests==2.32.3; extra == "dev"
37
+ Requires-Dist: twine==6.1.0; extra == "dev"
37
38
 
38
39
  # python-iso639
39
40
 
@@ -68,7 +69,7 @@ the actual import name during runtime is `iso639`
68
69
 
69
70
  ### Creating `Language` Instances
70
71
 
71
- Create a `Language` instance by one of the methods.
72
+ Create a `Language` instance by one of the class methods.
72
73
 
73
74
  #### `from_part3`, with an ISO 639-3 code
74
75
 
@@ -276,7 +277,7 @@ e.g., [`dataclasses.asdict`](https://docs.python.org/3/library/dataclasses.html#
276
277
  ```python
277
278
  >>> import iso639
278
279
  >>> iso639.DATA_LAST_UPDATED
279
- datetime.date(2024, 4, 15)
280
+ datetime.date(2025, 1, 15)
280
281
  ```
281
282
 
282
283
  * `ALL_LANGUAGES`: The list of all `Language` objects based on the included language code data
@@ -284,11 +285,9 @@ e.g., [`dataclasses.asdict`](https://docs.python.org/3/library/dataclasses.html#
284
285
  ```python
285
286
  >>> import iso639
286
287
  >>> type(iso639.ALL_LANGUAGES)
287
- <class 'list'>
288
+ <class 'set'>
288
289
  >>> len(iso639.ALL_LANGUAGES)
289
- 7920
290
- >>> iso639.ALL_LANGUAGES[0]
291
- Language(part3='aaa', scope='I', type='L', status='A', name='Ghotuo', ...)
290
+ 8307
292
291
  ```
293
292
 
294
293
  ## Links
@@ -304,9 +303,12 @@ for details.
304
303
 
305
304
  The data source that backs this package is the
306
305
  [language code tables published by SIL](https://iso639-3.sil.org/code_tables/download_tables).
306
+ The tables are included in this package under [`src/iso639/_data/`](src/iso639/_data/).
307
+ They are the UTF8-encoded `*.tab` tab-separated files bundled as a ZIP archive file,
308
+ typically found at a URL that looks like
309
+ `https://iso639-3.sil.org/sites/iso639-3/files/downloads/iso-639-3_Code_Tables_YYYYMMDD.zip`
310
+ (replace `YYYYMMDD` with the data release date).
307
311
  Note that SIL resources have their [terms of use](https://www.sil.org/terms-use).
308
- For exactly how the data is included in the package,
309
- see the script at [`scripts/create_languages_db.py`](scripts/create_languages_db.py).
310
312
 
311
313
  ## Why Another ISO 639 Package?
312
314
 
@@ -31,7 +31,7 @@ the actual import name during runtime is `iso639`
31
31
 
32
32
  ### Creating `Language` Instances
33
33
 
34
- Create a `Language` instance by one of the methods.
34
+ Create a `Language` instance by one of the class methods.
35
35
 
36
36
  #### `from_part3`, with an ISO 639-3 code
37
37
 
@@ -239,7 +239,7 @@ e.g., [`dataclasses.asdict`](https://docs.python.org/3/library/dataclasses.html#
239
239
  ```python
240
240
  >>> import iso639
241
241
  >>> iso639.DATA_LAST_UPDATED
242
- datetime.date(2024, 4, 15)
242
+ datetime.date(2025, 1, 15)
243
243
  ```
244
244
 
245
245
  * `ALL_LANGUAGES`: The list of all `Language` objects based on the included language code data
@@ -247,11 +247,9 @@ e.g., [`dataclasses.asdict`](https://docs.python.org/3/library/dataclasses.html#
247
247
  ```python
248
248
  >>> import iso639
249
249
  >>> type(iso639.ALL_LANGUAGES)
250
- <class 'list'>
250
+ <class 'set'>
251
251
  >>> len(iso639.ALL_LANGUAGES)
252
- 7920
253
- >>> iso639.ALL_LANGUAGES[0]
254
- Language(part3='aaa', scope='I', type='L', status='A', name='Ghotuo', ...)
252
+ 8307
255
253
  ```
256
254
 
257
255
  ## Links
@@ -267,9 +265,12 @@ for details.
267
265
 
268
266
  The data source that backs this package is the
269
267
  [language code tables published by SIL](https://iso639-3.sil.org/code_tables/download_tables).
268
+ The tables are included in this package under [`src/iso639/_data/`](src/iso639/_data/).
269
+ They are the UTF8-encoded `*.tab` tab-separated files bundled as a ZIP archive file,
270
+ typically found at a URL that looks like
271
+ `https://iso639-3.sil.org/sites/iso639-3/files/downloads/iso-639-3_Code_Tables_YYYYMMDD.zip`
272
+ (replace `YYYYMMDD` with the data release date).
270
273
  Note that SIL resources have their [terms of use](https://www.sil.org/terms-use).
271
- For exactly how the data is included in the package,
272
- see the script at [`scripts/create_languages_db.py`](scripts/create_languages_db.py).
273
274
 
274
275
  ## Why Another ISO 639 Package?
275
276
 
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-iso639"
7
- version = "2024.4.27"
7
+ version = "2025.1.27"
8
8
  description = "ISO 639 language codes, names, and other associated information"
9
9
  readme = "README.md"
10
- requires-python = ">= 3.8"
10
+ requires-python = ">= 3.9"
11
11
  license = { text = "Apache 2.0" }
12
12
  authors = [ { name = "Jackson L. Lee", email = "jacksonlunlee@gmail.com" } ]
13
13
  keywords = ["ISO 639", "language codes", "languages", "linguistics"]
@@ -21,11 +21,11 @@ classifiers = [
21
21
  "Operating System :: OS Independent",
22
22
  "Programming Language :: Python :: 3",
23
23
  "Programming Language :: Python :: 3 :: Only",
24
- "Programming Language :: Python :: 3.8",
25
24
  "Programming Language :: Python :: 3.9",
26
25
  "Programming Language :: Python :: 3.10",
27
26
  "Programming Language :: Python :: 3.11",
28
27
  "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
29
  "Topic :: Text Processing",
30
30
  "Topic :: Text Processing :: General",
31
31
  "Topic :: Text Processing :: Indexing",
@@ -34,12 +34,13 @@ classifiers = [
34
34
 
35
35
  [project.optional-dependencies]
36
36
  dev = [
37
- "black == 24.4.2",
38
- "build == 1.2.1",
39
- "flake8 == 7.0.0",
40
- "pytest == 8.1.2",
41
- "requests == 2.31.0",
42
- "twine == 5.0.0",
37
+ "black == 24.10.0",
38
+ "build == 1.2.2",
39
+ "flake8 == 7.1.1",
40
+ "mypy == 1.14.1",
41
+ "pytest == 8.3.4",
42
+ "requests == 2.32.3",
43
+ "twine == 6.1.0",
43
44
  ]
44
45
 
45
46
  [project.urls]
@@ -51,7 +52,7 @@ where = [ "src" ]
51
52
  [tool.setuptools]
52
53
  zip-safe = false
53
54
  package-dir = { "" = "src" }
54
- package-data = { "iso639" = ["languages.db"] }
55
+ package-data = { "iso639" = ["_data/*.tab"] }
55
56
 
56
57
  [tool.pytest.ini_options]
57
58
  addopts = "-vv --durations=0 --strict-markers"
@@ -4,16 +4,12 @@ from importlib.metadata import version
4
4
  from .language import Language, LanguageNotFoundError, _get_all_languages
5
5
 
6
6
 
7
+ # __version__ is based on calendar versioning (https://calver.org/).
8
+ # __version__ and DATA_LAST_UPDATED are intentionally kept separate.
9
+ # While DATA_LAST_UPDATED is strictly the date for the ISO 639-3 data release,
10
+ # __version__ can be bumped for changes other than data updates.
7
11
  __version__ = version("python-iso639")
8
- __all__ = [
9
- "__version__",
10
- "ALL_LANGUAGES",
11
- "DATA_LAST_UPDATED",
12
- "Language",
13
- "LanguageNotFoundError",
14
- ]
15
-
16
- DATA_LAST_UPDATED = datetime.date(2024, 4, 15)
12
+ DATA_LAST_UPDATED = datetime.date(2025, 1, 15)
17
13
 
18
14
 
19
15
  def __getattr__(name):
@@ -21,3 +17,12 @@ def __getattr__(name):
21
17
  return _get_all_languages()
22
18
  else:
23
19
  raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
20
+
21
+
22
+ __all__ = [
23
+ "__version__",
24
+ "ALL_LANGUAGES",
25
+ "DATA_LAST_UPDATED",
26
+ "Language",
27
+ "LanguageNotFoundError",
28
+ ]
@@ -0,0 +1,119 @@
1
+ from __future__ import annotations
2
+
3
+ import csv
4
+ import os
5
+ from collections import defaultdict
6
+ from enum import Enum
7
+
8
+ from typing import Dict, List, Union
9
+
10
+
11
+ class _CodesColumn(Enum):
12
+ ID = "Id"
13
+ PART2B = "Part2b"
14
+ PART2T = "Part2t"
15
+ PART1 = "Part1"
16
+ SCOPE = "Scope"
17
+ TYPE = "Language_Type"
18
+ REF_NAME = "Ref_Name"
19
+ COMMENT = "Comment"
20
+
21
+
22
+ class _NameIndexColumn(Enum):
23
+ ID = "Id"
24
+ PRINT_NAME = "Print_Name"
25
+ INVERTED_NAME = "Inverted_Name"
26
+
27
+
28
+ class _RetirementsColumn(Enum):
29
+ ID = "Id"
30
+ REF_NAME = "Ref_Name"
31
+ RET_REASON = "Ret_Reason"
32
+ CHANGE_TO = "Change_To"
33
+ REMEDY = "Ret_Remedy"
34
+ EFFECTIVE = "Effective"
35
+
36
+
37
+ class _MacrolanguagesColumn(Enum):
38
+ ID = "I_Id"
39
+ MID = "M_Id"
40
+ STATUS = "I_Status"
41
+
42
+
43
+ _COLUMN_TYPE = Union[
44
+ _CodesColumn, _NameIndexColumn, _RetirementsColumn, _MacrolanguagesColumn
45
+ ]
46
+ _ROW_TYPE = Dict[_COLUMN_TYPE, str]
47
+
48
+
49
+ class _Table(Enum):
50
+ CODES = _CodesColumn
51
+ NAME_INDEX = _NameIndexColumn
52
+ RETIREMENTS = _RetirementsColumn
53
+ MACROLANGUAGES = _MacrolanguagesColumn
54
+
55
+
56
+ _THIS_DIR = os.path.dirname(__file__)
57
+ _DATA_TSV_PATHS = {
58
+ _Table.CODES: os.path.join(_THIS_DIR, "iso-639-3.tab"),
59
+ _Table.NAME_INDEX: os.path.join(_THIS_DIR, "iso-639-3_Name_Index.tab"),
60
+ _Table.MACROLANGUAGES: os.path.join(_THIS_DIR, "iso-639-3-macrolanguages.tab"),
61
+ _Table.RETIREMENTS: os.path.join(_THIS_DIR, "iso-639-3_Retirements.tab"),
62
+ }
63
+
64
+
65
+ def _load_tsv(table: _Table) -> List[_ROW_TYPE]:
66
+ column = table.value
67
+ with open(_DATA_TSV_PATHS[table], encoding="utf-8", newline="") as tsv_file:
68
+ tsv_reader = csv.DictReader(tsv_file, delimiter="\t")
69
+ return [{column(k): v for k, v in row.items()} for row in tsv_reader]
70
+
71
+
72
+ _PART3_TO_CODES: Dict[str, _ROW_TYPE] = {
73
+ row[_CodesColumn.ID]: row for row in _load_tsv(_Table.CODES)
74
+ }
75
+
76
+ _part3_to_name_index: defaultdict[str, List[_ROW_TYPE]] = defaultdict(list)
77
+ for row in _load_tsv(_Table.NAME_INDEX):
78
+ _part3_to_name_index[row[_NameIndexColumn.ID]].append(row)
79
+ _PART3_TO_NAME_INDEX: Dict[str, List[_ROW_TYPE]] = dict(_part3_to_name_index)
80
+
81
+ _PART3_TO_RETIREMENTS: Dict[str, _ROW_TYPE] = {
82
+ row[_RetirementsColumn.ID]: row for row in _load_tsv(_Table.RETIREMENTS)
83
+ }
84
+ _PART3_TO_MACROLANGUAGES: Dict[str, _ROW_TYPE] = {
85
+ row[_MacrolanguagesColumn.ID]: row for row in _load_tsv(_Table.MACROLANGUAGES)
86
+ }
87
+
88
+ _PART2B_TO_PART3: Dict[str, str] = {
89
+ row[_CodesColumn.PART2B]: part3
90
+ for part3, row in _PART3_TO_CODES.items()
91
+ if row[_CodesColumn.PART2B]
92
+ }
93
+ _PART2T_TO_PART3: Dict[str, str] = {
94
+ row[_CodesColumn.PART2T]: part3
95
+ for part3, row in _PART3_TO_CODES.items()
96
+ if row[_CodesColumn.PART2T]
97
+ }
98
+ _PART1_TO_PART3: Dict[str, str] = {
99
+ row[_CodesColumn.PART1]: part3
100
+ for part3, row in _PART3_TO_CODES.items()
101
+ if row[_CodesColumn.PART1]
102
+ }
103
+ _REF_NAME_TO_PART3: Dict[str, str] = {
104
+ row[_CodesColumn.REF_NAME]: part3
105
+ for part3, row in _PART3_TO_CODES.items()
106
+ if row[_CodesColumn.REF_NAME]
107
+ }
108
+ _PRINT_NAME_TO_PART3: Dict[str, str] = {
109
+ row[_NameIndexColumn.PRINT_NAME]: part3
110
+ for part3, rows in _PART3_TO_NAME_INDEX.items()
111
+ for row in rows
112
+ if row[_NameIndexColumn.PRINT_NAME]
113
+ }
114
+ _INVERTED_NAME_TO_PART3: Dict[str, str] = {
115
+ row[_NameIndexColumn.INVERTED_NAME]: part3
116
+ for part3, rows in _PART3_TO_NAME_INDEX.items()
117
+ for row in rows
118
+ if row[_NameIndexColumn.INVERTED_NAME]
119
+ }