hdx-python-country 3.7.8__tar.gz → 3.8.0__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.
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/PKG-INFO +2 -2
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/documentation/main.md +4 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/pyproject.toml +1 -1
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/requirements.txt +15 -17
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/_version.py +2 -2
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/adminlevel.py +40 -10
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/test_adminlevel.py +53 -12
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.config/coveragerc +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.config/pre-commit-config.yaml +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.config/pytest.ini +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.config/ruff.toml +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.github/workflows/publish.yaml +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.gitignore +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/CONTRIBUTING.md +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/LICENSE +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/README.md +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/documentation/pydoc-markdown.yaml +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/country.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/currency.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/phonetics.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/src/hdx/location/wfp_exchangerates.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/fixtures/adminlevel.yaml +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/fixtures/adminlevelparent.yaml +0 -0
- /hdx_python_country-3.7.8/tests/fixtures/global_pcode_lengths.csv → /hdx_python_country-3.8.0/tests/fixtures/download-global-pcode-lengths.csv +0 -0
- /hdx_python_country-3.7.8/tests/fixtures/global_pcodes_adm_1_2.csv → /hdx_python_country-3.8.0/tests/fixtures/download-global-pcodes-adm-1-2.csv +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/fixtures/secondary_historic_rates.csv +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/fixtures/secondary_rates.json +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/test_country.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/test_currency.py +0 -0
- {hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/test_wfp_exchangerates.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: hdx-python-country
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.8.0
|
|
4
4
|
Summary: HDX Python country code and exchange rate (fx) utilities
|
|
5
5
|
Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-country
|
|
6
6
|
Author: Michael Rans
|
|
@@ -25,7 +25,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
25
25
|
Classifier: Programming Language :: Python :: 3.12
|
|
26
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
27
|
Requires-Python: >=3.8
|
|
28
|
-
Requires-Dist: hdx-python-utilities>=3.7.
|
|
28
|
+
Requires-Dist: hdx-python-utilities>=3.7.4
|
|
29
29
|
Requires-Dist: libhxl>=5.2.1
|
|
30
30
|
Requires-Dist: pyphonetics
|
|
31
31
|
Provides-Extra: dev
|
|
@@ -130,6 +130,10 @@ object has been set up with parents). Keys take the form "STRING_TO_REPLACE",
|
|
|
130
130
|
*admin_fuzzy_dont* is a list of names for which fuzzy matching should not be
|
|
131
131
|
tried
|
|
132
132
|
|
|
133
|
+
A Retrieve object can be passed in the *retriever* parameter that enables
|
|
134
|
+
saving data downloaded to a file or loading previously saved data depending
|
|
135
|
+
on how the Retrieve object is configured.
|
|
136
|
+
|
|
133
137
|
Once an AdminLevel object is constructed, one of three setup methods must be
|
|
134
138
|
called: *setup_from_admin_info*, *setup_from_libhxl_dataset* or
|
|
135
139
|
*setup_from_url*.
|
|
@@ -24,17 +24,17 @@ distlib==0.3.8
|
|
|
24
24
|
# via virtualenv
|
|
25
25
|
et-xmlfile==1.1.0
|
|
26
26
|
# via openpyxl
|
|
27
|
-
filelock==3.
|
|
27
|
+
filelock==3.16.1
|
|
28
28
|
# via virtualenv
|
|
29
|
-
frictionless==5.
|
|
29
|
+
frictionless==5.18.0
|
|
30
30
|
# via hdx-python-utilities
|
|
31
|
-
hdx-python-utilities==3.7.
|
|
31
|
+
hdx-python-utilities==3.7.4
|
|
32
32
|
# via hdx-python-country (pyproject.toml)
|
|
33
|
-
humanize==4.
|
|
33
|
+
humanize==4.11.0
|
|
34
34
|
# via frictionless
|
|
35
|
-
identify==2.6.
|
|
35
|
+
identify==2.6.1
|
|
36
36
|
# via pre-commit
|
|
37
|
-
idna==3.
|
|
37
|
+
idna==3.10
|
|
38
38
|
# via requests
|
|
39
39
|
ijson==3.3.0
|
|
40
40
|
# via hdx-python-utilities
|
|
@@ -74,7 +74,7 @@ packaging==24.1
|
|
|
74
74
|
# via pytest
|
|
75
75
|
petl==1.7.15
|
|
76
76
|
# via frictionless
|
|
77
|
-
platformdirs==4.
|
|
77
|
+
platformdirs==4.3.6
|
|
78
78
|
# via virtualenv
|
|
79
79
|
pluggy==1.5.0
|
|
80
80
|
# via pytest
|
|
@@ -82,17 +82,17 @@ ply==3.11
|
|
|
82
82
|
# via
|
|
83
83
|
# jsonpath-ng
|
|
84
84
|
# libhxl
|
|
85
|
-
pre-commit==
|
|
85
|
+
pre-commit==4.0.0
|
|
86
86
|
# via hdx-python-country (pyproject.toml)
|
|
87
|
-
pydantic==2.9.
|
|
87
|
+
pydantic==2.9.2
|
|
88
88
|
# via frictionless
|
|
89
|
-
pydantic-core==2.23.
|
|
89
|
+
pydantic-core==2.23.4
|
|
90
90
|
# via pydantic
|
|
91
91
|
pygments==2.18.0
|
|
92
92
|
# via rich
|
|
93
93
|
pyphonetics==0.5.3
|
|
94
94
|
# via hdx-python-country (pyproject.toml)
|
|
95
|
-
pytest==8.3.
|
|
95
|
+
pytest==8.3.3
|
|
96
96
|
# via
|
|
97
97
|
# hdx-python-country (pyproject.toml)
|
|
98
98
|
# pytest-cov
|
|
@@ -127,7 +127,7 @@ requests-file==2.1.0
|
|
|
127
127
|
# via hdx-python-utilities
|
|
128
128
|
rfc3986==2.0.0
|
|
129
129
|
# via frictionless
|
|
130
|
-
rich==13.
|
|
130
|
+
rich==13.9.2
|
|
131
131
|
# via typer
|
|
132
132
|
rpds-py==0.20.0
|
|
133
133
|
# via
|
|
@@ -139,7 +139,7 @@ ruamel-yaml-clib==0.2.8
|
|
|
139
139
|
# via ruamel-yaml
|
|
140
140
|
shellingham==1.5.4
|
|
141
141
|
# via typer
|
|
142
|
-
simpleeval==0.
|
|
142
|
+
simpleeval==1.0.0
|
|
143
143
|
# via frictionless
|
|
144
144
|
six==1.16.0
|
|
145
145
|
# via
|
|
@@ -163,19 +163,17 @@ typing-extensions==4.12.2
|
|
|
163
163
|
# pydantic
|
|
164
164
|
# pydantic-core
|
|
165
165
|
# typer
|
|
166
|
-
tzdata==2024.1
|
|
167
|
-
# via pydantic
|
|
168
166
|
unidecode==1.3.8
|
|
169
167
|
# via
|
|
170
168
|
# libhxl
|
|
171
169
|
# pyphonetics
|
|
172
|
-
urllib3==2.2.
|
|
170
|
+
urllib3==2.2.3
|
|
173
171
|
# via
|
|
174
172
|
# libhxl
|
|
175
173
|
# requests
|
|
176
174
|
validators==0.34.0
|
|
177
175
|
# via frictionless
|
|
178
|
-
virtualenv==20.26.
|
|
176
|
+
virtualenv==20.26.6
|
|
179
177
|
# via pre-commit
|
|
180
178
|
wheel==0.44.0
|
|
181
179
|
# via libhxl
|
|
@@ -8,7 +8,9 @@ from hxl.input import HXLIOException
|
|
|
8
8
|
|
|
9
9
|
from hdx.location.country import Country
|
|
10
10
|
from hdx.location.phonetics import Phonetics
|
|
11
|
+
from hdx.utilities.base_downloader import DownloadError
|
|
11
12
|
from hdx.utilities.dictandlist import dict_of_sets_add
|
|
13
|
+
from hdx.utilities.retriever import Retrieve
|
|
12
14
|
from hdx.utilities.text import multiple_replace, normalise
|
|
13
15
|
from hdx.utilities.typehint import ListTuple
|
|
14
16
|
|
|
@@ -30,10 +32,20 @@ class AdminLevel:
|
|
|
30
32
|
admin_fuzzy_dont is a list of names for which fuzzy matching should not be
|
|
31
33
|
tried
|
|
32
34
|
|
|
35
|
+
The admin_level_overrides parameter allows manually overriding the returned
|
|
36
|
+
admin level for given countries. It is a dictionary with iso3s as keys and
|
|
37
|
+
admin level numbers as values.
|
|
38
|
+
|
|
39
|
+
The retriever parameter accepts an object of type Retrieve (or inherited
|
|
40
|
+
classes). It is used to allow either that admin data from urls is saved
|
|
41
|
+
to files or to enable already saved files to be used instead of downloading
|
|
42
|
+
from urls.
|
|
43
|
+
|
|
33
44
|
Args:
|
|
34
45
|
admin_config (Dict): Configuration dictionary. Defaults to {}.
|
|
35
46
|
admin_level (int): Admin level. Defaults to 1.
|
|
36
47
|
admin_level_overrides (Dict): Countries at other admin levels.
|
|
48
|
+
retriever (Optional[Retrieve]): Retriever object to use for loading/saving files. Defaults to None.
|
|
37
49
|
"""
|
|
38
50
|
|
|
39
51
|
pcode_regex = re.compile(r"^([a-zA-Z]{2,3})(\d+)$")
|
|
@@ -47,9 +59,11 @@ class AdminLevel:
|
|
|
47
59
|
admin_config: Dict = {},
|
|
48
60
|
admin_level: int = 1,
|
|
49
61
|
admin_level_overrides: Dict = {},
|
|
62
|
+
retriever: Optional[Retrieve] = None,
|
|
50
63
|
) -> None:
|
|
51
64
|
self.admin_level = admin_level
|
|
52
65
|
self.admin_level_overrides = admin_level_overrides
|
|
66
|
+
self.retriever: Optional[Retrieve] = retriever
|
|
53
67
|
self.countries_fuzzy_try = admin_config.get("countries_fuzzy_try")
|
|
54
68
|
self.admin_name_mappings = admin_config.get("admin_name_mappings", {})
|
|
55
69
|
self.admin_name_replacements = admin_config.get(
|
|
@@ -101,23 +115,39 @@ class AdminLevel:
|
|
|
101
115
|
admin_url = cls._admin_url_default
|
|
102
116
|
cls._admin_url = admin_url
|
|
103
117
|
|
|
104
|
-
@
|
|
105
|
-
def get_libhxl_dataset(
|
|
118
|
+
@staticmethod
|
|
119
|
+
def get_libhxl_dataset(
|
|
120
|
+
url: str = _admin_url, retriever: Optional[Retrieve] = None
|
|
121
|
+
) -> hxl.Dataset:
|
|
106
122
|
"""
|
|
107
123
|
Get libhxl Dataset object given a URL which defaults to global p-codes
|
|
108
124
|
dataset on HDX.
|
|
109
125
|
|
|
110
126
|
Args:
|
|
111
|
-
|
|
127
|
+
url (str): URL from which to load data. Defaults to internal admin url.
|
|
128
|
+
retriever (Optional[Retrieve]): Retriever object to use for loading file. Defaults to None.
|
|
112
129
|
|
|
113
130
|
Returns:
|
|
114
|
-
|
|
115
|
-
"""
|
|
131
|
+
hxl.Dataset: HXL Dataset object
|
|
132
|
+
"""
|
|
133
|
+
if retriever:
|
|
134
|
+
try:
|
|
135
|
+
url_to_use = retriever.download_file(url)
|
|
136
|
+
except DownloadError:
|
|
137
|
+
logger.exception(
|
|
138
|
+
f"Setup of libhxl Dataset object with {url} failed!"
|
|
139
|
+
)
|
|
140
|
+
raise
|
|
141
|
+
else:
|
|
142
|
+
url_to_use = url
|
|
116
143
|
try:
|
|
117
|
-
return hxl.data(
|
|
118
|
-
|
|
144
|
+
return hxl.data(
|
|
145
|
+
url_to_use,
|
|
146
|
+
InputOptions(InputOptions(allow_local=True, encoding="utf-8")),
|
|
147
|
+
)
|
|
148
|
+
except (FileNotFoundError, HXLIOException):
|
|
119
149
|
logger.exception(
|
|
120
|
-
f"Setup of libhxl Dataset object with {
|
|
150
|
+
f"Setup of libhxl Dataset object with {url} failed!"
|
|
121
151
|
)
|
|
122
152
|
raise
|
|
123
153
|
|
|
@@ -245,7 +275,7 @@ class AdminLevel:
|
|
|
245
275
|
Returns:
|
|
246
276
|
None
|
|
247
277
|
"""
|
|
248
|
-
admin_info = self.get_libhxl_dataset(admin_url)
|
|
278
|
+
admin_info = self.get_libhxl_dataset(admin_url, self.retriever)
|
|
249
279
|
self.setup_from_libhxl_dataset(admin_info, countryiso3s)
|
|
250
280
|
|
|
251
281
|
def load_pcode_formats(self, formats_url: str = _formats_url) -> None:
|
|
@@ -258,7 +288,7 @@ class AdminLevel:
|
|
|
258
288
|
Returns:
|
|
259
289
|
None
|
|
260
290
|
"""
|
|
261
|
-
formats_info = self.get_libhxl_dataset(formats_url)
|
|
291
|
+
formats_info = self.get_libhxl_dataset(formats_url, self.retriever)
|
|
262
292
|
for row in formats_info:
|
|
263
293
|
pcode_format = [int(row.get("#country+len"))]
|
|
264
294
|
for admin_no in range(1, 4):
|
|
@@ -3,28 +3,35 @@
|
|
|
3
3
|
from os.path import join
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
|
-
from hxl.input import HXLIOException
|
|
7
6
|
|
|
8
7
|
from hdx.location.adminlevel import AdminLevel
|
|
8
|
+
from hdx.utilities.base_downloader import DownloadError
|
|
9
|
+
from hdx.utilities.downloader import Download
|
|
9
10
|
from hdx.utilities.loader import load_yaml
|
|
11
|
+
from hdx.utilities.path import temp_dir
|
|
12
|
+
from hdx.utilities.retriever import Retrieve
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
class TestAdminLevel:
|
|
16
|
+
@pytest.fixture(scope="class")
|
|
17
|
+
def fixtures_dir(self):
|
|
18
|
+
return join("tests", "fixtures")
|
|
19
|
+
|
|
13
20
|
@pytest.fixture(scope="function")
|
|
14
|
-
def config(self):
|
|
15
|
-
return load_yaml(join(
|
|
21
|
+
def config(self, fixtures_dir):
|
|
22
|
+
return load_yaml(join(fixtures_dir, "adminlevel.yaml"))
|
|
16
23
|
|
|
17
24
|
@pytest.fixture(scope="function")
|
|
18
|
-
def config_parent(self):
|
|
19
|
-
return load_yaml(join(
|
|
25
|
+
def config_parent(self, fixtures_dir):
|
|
26
|
+
return load_yaml(join(fixtures_dir, "adminlevelparent.yaml"))
|
|
20
27
|
|
|
21
28
|
@pytest.fixture(scope="function")
|
|
22
|
-
def url(self):
|
|
23
|
-
return "
|
|
29
|
+
def url(self, fixtures_dir):
|
|
30
|
+
return join(fixtures_dir, "download-global-pcodes-adm-1-2.csv")
|
|
24
31
|
|
|
25
32
|
@pytest.fixture(scope="function")
|
|
26
|
-
def formats_url(self):
|
|
27
|
-
return "
|
|
33
|
+
def formats_url(self, fixtures_dir):
|
|
34
|
+
return join(fixtures_dir, "download-global-pcode-lengths.csv")
|
|
28
35
|
|
|
29
36
|
def test_adminlevel(self, config):
|
|
30
37
|
adminone = AdminLevel(config)
|
|
@@ -367,16 +374,50 @@ class TestAdminLevel:
|
|
|
367
374
|
"MWI", "Blantyre city", parent="MW3", logname="test"
|
|
368
375
|
) == (None, False)
|
|
369
376
|
|
|
370
|
-
def test_adminlevel_with_url(self, config, url):
|
|
371
|
-
adminone = AdminLevel(config)
|
|
372
|
-
|
|
377
|
+
def test_adminlevel_with_url(self, config, url, fixtures_dir):
|
|
378
|
+
adminone = AdminLevel(config, admin_level_overrides={"YEM": 5})
|
|
379
|
+
assert adminone.get_admin_level("YEM") == 5
|
|
380
|
+
with pytest.raises(FileNotFoundError):
|
|
373
381
|
adminone.setup_from_url("fake_url")
|
|
382
|
+
adminone = AdminLevel(config)
|
|
374
383
|
AdminLevel.set_default_admin_url()
|
|
375
384
|
assert AdminLevel._admin_url == AdminLevel._admin_url_default
|
|
376
385
|
AdminLevel.set_default_admin_url(url)
|
|
377
386
|
assert AdminLevel._admin_url == url
|
|
378
387
|
adminone.setup_from_url(countryiso3s=("YEM",))
|
|
379
388
|
assert len(adminone.get_pcode_list()) == 22
|
|
389
|
+
|
|
390
|
+
with temp_dir(
|
|
391
|
+
"TestAdminLevelRetriever",
|
|
392
|
+
delete_on_success=True,
|
|
393
|
+
delete_on_failure=False,
|
|
394
|
+
) as tempdir:
|
|
395
|
+
with Download(user_agent="test") as downloader:
|
|
396
|
+
retriever = Retrieve(
|
|
397
|
+
downloader,
|
|
398
|
+
tempdir,
|
|
399
|
+
fixtures_dir,
|
|
400
|
+
tempdir,
|
|
401
|
+
save=False,
|
|
402
|
+
use_saved=False,
|
|
403
|
+
)
|
|
404
|
+
adminone = AdminLevel(config, retriever=retriever)
|
|
405
|
+
with pytest.raises(DownloadError):
|
|
406
|
+
adminone.setup_from_url("fake_url")
|
|
407
|
+
retriever = Retrieve(
|
|
408
|
+
downloader,
|
|
409
|
+
tempdir,
|
|
410
|
+
fixtures_dir,
|
|
411
|
+
tempdir,
|
|
412
|
+
save=False,
|
|
413
|
+
use_saved=True,
|
|
414
|
+
)
|
|
415
|
+
adminone = AdminLevel(config, retriever=retriever)
|
|
416
|
+
with pytest.raises(FileNotFoundError):
|
|
417
|
+
adminone.setup_from_url("fake_url")
|
|
418
|
+
adminone.setup_from_url(countryiso3s=("YEM",))
|
|
419
|
+
assert len(adminone.get_pcode_list()) == 22
|
|
420
|
+
|
|
380
421
|
adminone = AdminLevel(config)
|
|
381
422
|
adminone.setup_from_url()
|
|
382
423
|
assert adminone.get_admin_level("YEM") == 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/.github/workflows/run-python-tests.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/fixtures/secondary_historic_rates.csv
RENAMED
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/Countries_UZB_Deleted.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.7.8 → hdx_python_country-3.8.0}/tests/hdx/location/test_wfp_exchangerates.py
RENAMED
|
File without changes
|