hdx-python-country 3.7.4__tar.gz → 3.7.6__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.4 → hdx_python_country-3.7.6}/PKG-INFO +2 -2
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/documentation/main.md +3 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/pyproject.toml +1 -1
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/requirements.txt +7 -7
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/_version.py +2 -2
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/adminlevel.py +29 -21
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/hdx/location/test_adminlevel.py +6 -2
- hdx_python_country-3.7.4/src/hdx/location/names.py +0 -29
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.config/coveragerc +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.config/pre-commit-config.yaml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.config/pytest.ini +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.config/ruff.toml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.github/workflows/publish.yaml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.gitignore +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/CONTRIBUTING.md +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/LICENSE +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/README.md +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/documentation/pydoc-markdown.yaml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/country.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/currency.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/phonetics.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/src/hdx/location/wfp_exchangerates.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/adminlevel.yaml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/adminlevelparent.yaml +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/global_pcode_lengths.csv +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/global_pcodes_adm_1_2.csv +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/secondary_historic_rates.csv +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/secondary_rates.json +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/hdx/location/test_country.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/hdx/location/test_currency.py +0 -0
- {hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/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.7.
|
|
3
|
+
Version: 3.7.6
|
|
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.2
|
|
29
29
|
Requires-Dist: libhxl>=5.2.1
|
|
30
30
|
Requires-Dist: pyphonetics
|
|
31
31
|
Provides-Extra: dev
|
|
@@ -42,6 +42,9 @@ The code for the library is [here](https://github.com/OCHA-DAP/hdx-python-countr
|
|
|
42
42
|
The library has detailed API documentation which can be found in the menu at the top.
|
|
43
43
|
|
|
44
44
|
## Breaking Changes
|
|
45
|
+
From 3.7.5, removed clean_name function. There is now a function normalise in
|
|
46
|
+
HDX Python Utilities.
|
|
47
|
+
|
|
45
48
|
From 3.5.5, after creating an Adminlevel, call either setup_from_admin_info,
|
|
46
49
|
setup_from_libhxl_dataset or setup_from_url.
|
|
47
50
|
|
|
@@ -8,7 +8,7 @@ attrs==23.2.0
|
|
|
8
8
|
# jsonlines
|
|
9
9
|
# jsonschema
|
|
10
10
|
# referencing
|
|
11
|
-
certifi==2024.
|
|
11
|
+
certifi==2024.7.4
|
|
12
12
|
# via requests
|
|
13
13
|
cfgv==3.4.0
|
|
14
14
|
# via pre-commit
|
|
@@ -28,11 +28,11 @@ filelock==3.15.4
|
|
|
28
28
|
# via virtualenv
|
|
29
29
|
frictionless==5.17.0
|
|
30
30
|
# via hdx-python-utilities
|
|
31
|
-
hdx-python-utilities==3.7.
|
|
31
|
+
hdx-python-utilities==3.7.2
|
|
32
32
|
# via hdx-python-country (pyproject.toml)
|
|
33
33
|
humanize==4.9.0
|
|
34
34
|
# via frictionless
|
|
35
|
-
identify==2.
|
|
35
|
+
identify==2.6.0
|
|
36
36
|
# via pre-commit
|
|
37
37
|
idna==3.7
|
|
38
38
|
# via requests
|
|
@@ -68,7 +68,7 @@ mdurl==0.1.2
|
|
|
68
68
|
# via markdown-it-py
|
|
69
69
|
nodeenv==1.9.1
|
|
70
70
|
# via pre-commit
|
|
71
|
-
openpyxl==3.1.
|
|
71
|
+
openpyxl==3.1.5
|
|
72
72
|
# via hdx-python-utilities
|
|
73
73
|
packaging==24.1
|
|
74
74
|
# via pytest
|
|
@@ -84,9 +84,9 @@ ply==3.11
|
|
|
84
84
|
# libhxl
|
|
85
85
|
pre-commit==3.7.1
|
|
86
86
|
# via hdx-python-country (pyproject.toml)
|
|
87
|
-
pydantic==2.
|
|
87
|
+
pydantic==2.8.2
|
|
88
88
|
# via frictionless
|
|
89
|
-
pydantic-core==2.
|
|
89
|
+
pydantic-core==2.20.1
|
|
90
90
|
# via pydantic
|
|
91
91
|
pygments==2.18.0
|
|
92
92
|
# via rich
|
|
@@ -171,7 +171,7 @@ urllib3==2.2.2
|
|
|
171
171
|
# via
|
|
172
172
|
# libhxl
|
|
173
173
|
# requests
|
|
174
|
-
validators==0.
|
|
174
|
+
validators==0.30.0
|
|
175
175
|
# via frictionless
|
|
176
176
|
virtualenv==20.26.3
|
|
177
177
|
# via pre-commit
|
|
@@ -5,13 +5,11 @@ from typing import Any, Dict, List, Optional, Tuple
|
|
|
5
5
|
import hxl
|
|
6
6
|
from hxl import InputOptions
|
|
7
7
|
from hxl.input import HXLIOException
|
|
8
|
-
from unidecode import unidecode
|
|
9
8
|
|
|
10
9
|
from hdx.location.country import Country
|
|
11
|
-
from hdx.location.names import clean_name
|
|
12
10
|
from hdx.location.phonetics import Phonetics
|
|
13
11
|
from hdx.utilities.dictandlist import dict_of_sets_add
|
|
14
|
-
from hdx.utilities.text import multiple_replace
|
|
12
|
+
from hdx.utilities.text import multiple_replace, normalise
|
|
15
13
|
from hdx.utilities.typehint import ListTuple
|
|
16
14
|
|
|
17
15
|
logger = logging.getLogger(__name__)
|
|
@@ -146,8 +144,9 @@ class AdminLevel:
|
|
|
146
144
|
self.pcodes.append(pcode)
|
|
147
145
|
self.pcode_to_name[pcode] = adm_name
|
|
148
146
|
|
|
147
|
+
adm_name = normalise(adm_name)
|
|
149
148
|
name_to_pcode = self.name_to_pcode.get(countryiso3, {})
|
|
150
|
-
name_to_pcode[
|
|
149
|
+
name_to_pcode[adm_name] = pcode
|
|
151
150
|
self.name_to_pcode[countryiso3] = name_to_pcode
|
|
152
151
|
self.pcode_to_iso3[pcode] = countryiso3
|
|
153
152
|
self.pcode_to_iso3[pcode] = countryiso3
|
|
@@ -157,7 +156,7 @@ class AdminLevel:
|
|
|
157
156
|
countryiso3, {}
|
|
158
157
|
)
|
|
159
158
|
name_to_pcode = name_parent_to_pcode.get(parent, {})
|
|
160
|
-
name_to_pcode[
|
|
159
|
+
name_to_pcode[adm_name] = pcode
|
|
161
160
|
name_parent_to_pcode[parent] = name_to_pcode
|
|
162
161
|
self.name_parent_to_pcode[countryiso3] = name_parent_to_pcode
|
|
163
162
|
self.pcode_to_parent[pcode] = parent
|
|
@@ -556,6 +555,7 @@ class AdminLevel:
|
|
|
556
555
|
self,
|
|
557
556
|
countryiso3: str,
|
|
558
557
|
name: str,
|
|
558
|
+
normalised_name: str,
|
|
559
559
|
**kwargs: Any,
|
|
560
560
|
) -> Optional[str]:
|
|
561
561
|
"""Fuzzy match name to pcode
|
|
@@ -563,6 +563,7 @@ class AdminLevel:
|
|
|
563
563
|
Args:
|
|
564
564
|
countryiso3 (str): ISO3 country code
|
|
565
565
|
name (str): Name to match
|
|
566
|
+
normalised_name (str): Normalised name
|
|
566
567
|
**kwargs:
|
|
567
568
|
parent (Optional[str]): Parent admin code
|
|
568
569
|
logname (str): Log using this identifying name. Defaults to not logging.
|
|
@@ -599,13 +600,12 @@ class AdminLevel:
|
|
|
599
600
|
if logname:
|
|
600
601
|
self.errors.add((logname, countryiso3, parent))
|
|
601
602
|
return None
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
adm_name_lookup,
|
|
603
|
+
alt_normalised_name = multiple_replace(
|
|
604
|
+
normalised_name,
|
|
605
605
|
self.get_admin_name_replacements(countryiso3, parent),
|
|
606
606
|
)
|
|
607
607
|
pcode = name_to_pcode.get(
|
|
608
|
-
|
|
608
|
+
normalised_name, name_to_pcode.get(alt_normalised_name)
|
|
609
609
|
)
|
|
610
610
|
if not pcode and name.lower() in self.admin_fuzzy_dont:
|
|
611
611
|
if logname:
|
|
@@ -613,7 +613,7 @@ class AdminLevel:
|
|
|
613
613
|
return None
|
|
614
614
|
if not pcode:
|
|
615
615
|
for map_name in name_to_pcode:
|
|
616
|
-
if
|
|
616
|
+
if normalised_name in map_name:
|
|
617
617
|
pcode = name_to_pcode[map_name]
|
|
618
618
|
if logname:
|
|
619
619
|
self.matches.add(
|
|
@@ -627,7 +627,7 @@ class AdminLevel:
|
|
|
627
627
|
)
|
|
628
628
|
break
|
|
629
629
|
for map_name in name_to_pcode:
|
|
630
|
-
if
|
|
630
|
+
if alt_normalised_name in map_name:
|
|
631
631
|
pcode = name_to_pcode[map_name]
|
|
632
632
|
if logname:
|
|
633
633
|
self.matches.add(
|
|
@@ -642,24 +642,27 @@ class AdminLevel:
|
|
|
642
642
|
break
|
|
643
643
|
if not pcode:
|
|
644
644
|
map_names = list(name_to_pcode.keys())
|
|
645
|
-
lower_mapnames = [x.lower() for x in map_names]
|
|
646
645
|
|
|
647
646
|
def al_transform_1(name):
|
|
648
|
-
|
|
647
|
+
prefix = name[:3]
|
|
648
|
+
if prefix == "al ":
|
|
649
649
|
return f"ad {name[3:]}"
|
|
650
|
+
elif prefix == "ad ":
|
|
651
|
+
return f"al {name[3:]}"
|
|
650
652
|
else:
|
|
651
653
|
return None
|
|
652
654
|
|
|
653
655
|
def al_transform_2(name):
|
|
654
|
-
|
|
656
|
+
prefix = name[:3]
|
|
657
|
+
if prefix == "al " or prefix == "ad ":
|
|
655
658
|
return name[3:]
|
|
656
659
|
else:
|
|
657
660
|
return None
|
|
658
661
|
|
|
659
662
|
matching_index = self.phonetics.match(
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
alternative_name=
|
|
663
|
+
map_names,
|
|
664
|
+
normalised_name,
|
|
665
|
+
alternative_name=alt_normalised_name,
|
|
663
666
|
transform_possible_names=[al_transform_1, al_transform_2],
|
|
664
667
|
)
|
|
665
668
|
|
|
@@ -714,6 +717,7 @@ class AdminLevel:
|
|
|
714
717
|
countryiso3: str,
|
|
715
718
|
name: str,
|
|
716
719
|
fuzzy_match: bool = True,
|
|
720
|
+
fuzzy_length: int = 4,
|
|
717
721
|
**kwargs: Any,
|
|
718
722
|
) -> Tuple[Optional[str], bool]:
|
|
719
723
|
"""Get pcode for a given name
|
|
@@ -722,6 +726,7 @@ class AdminLevel:
|
|
|
722
726
|
countryiso3 (str): ISO3 country code
|
|
723
727
|
name (str): Name to match
|
|
724
728
|
fuzzy_match (bool): Whether to try fuzzy matching. Defaults to True.
|
|
729
|
+
fuzzy_length (int): Minimum length for fuzzy matching. Defaults to 4.
|
|
725
730
|
**kwargs:
|
|
726
731
|
parent (Optional[str]): Parent admin code
|
|
727
732
|
logname (str): Log using this identifying name. Defaults to not logging.
|
|
@@ -751,6 +756,7 @@ class AdminLevel:
|
|
|
751
756
|
)
|
|
752
757
|
return pcode, True
|
|
753
758
|
else:
|
|
759
|
+
normalised_name = normalise(name)
|
|
754
760
|
if parent:
|
|
755
761
|
name_parent_to_pcode = self.name_parent_to_pcode.get(
|
|
756
762
|
countryiso3
|
|
@@ -758,18 +764,20 @@ class AdminLevel:
|
|
|
758
764
|
if name_parent_to_pcode:
|
|
759
765
|
name_to_pcode = name_parent_to_pcode.get(parent)
|
|
760
766
|
if name_to_pcode is not None:
|
|
761
|
-
pcode = name_to_pcode.get(
|
|
767
|
+
pcode = name_to_pcode.get(normalised_name)
|
|
762
768
|
if pcode:
|
|
763
769
|
return pcode, True
|
|
764
770
|
else:
|
|
765
771
|
name_to_pcode = self.name_to_pcode.get(countryiso3)
|
|
766
772
|
if name_to_pcode is not None:
|
|
767
|
-
pcode = name_to_pcode.get(
|
|
773
|
+
pcode = name_to_pcode.get(normalised_name)
|
|
768
774
|
if pcode:
|
|
769
775
|
return pcode, True
|
|
770
|
-
if not fuzzy_match:
|
|
776
|
+
if not fuzzy_match or len(normalised_name) < fuzzy_length:
|
|
771
777
|
return None, True
|
|
772
|
-
pcode = self.fuzzy_pcode(
|
|
778
|
+
pcode = self.fuzzy_pcode(
|
|
779
|
+
countryiso3, name, normalised_name, **kwargs
|
|
780
|
+
)
|
|
773
781
|
return pcode, False
|
|
774
782
|
|
|
775
783
|
def output_matches(self) -> List[str]:
|
|
@@ -182,6 +182,10 @@ class TestAdminLevel:
|
|
|
182
182
|
def test_adminlevel_fuzzy(self, config):
|
|
183
183
|
adminone = AdminLevel(config)
|
|
184
184
|
adminone.setup_from_admin_info(config["admin_info"])
|
|
185
|
+
assert adminone.get_pcode("YEM", "Al_Dhale'a", logname="test") == (
|
|
186
|
+
"YE30",
|
|
187
|
+
False,
|
|
188
|
+
)
|
|
185
189
|
assert adminone.get_pcode("YEM", "Al Dali", logname="test") == (
|
|
186
190
|
"YE30",
|
|
187
191
|
False,
|
|
@@ -200,6 +204,7 @@ class TestAdminLevel:
|
|
|
200
204
|
assert output == [
|
|
201
205
|
"test - YEM: Matching (fuzzy) Al Dali to Ad Dali on map",
|
|
202
206
|
"test - YEM: Matching (fuzzy) Al Dhale'e / الضالع to Ad Dali on map",
|
|
207
|
+
"test - YEM: Matching (fuzzy) Al_Dhale'a to Ad Dali on map",
|
|
203
208
|
]
|
|
204
209
|
|
|
205
210
|
def test_adminlevel_parent(self, config_parent):
|
|
@@ -457,7 +462,7 @@ class TestAdminLevel:
|
|
|
457
462
|
)
|
|
458
463
|
assert adminone.get_pcode("YEM", "Ad Dali", logname="test") == (
|
|
459
464
|
"YE30",
|
|
460
|
-
|
|
465
|
+
True,
|
|
461
466
|
)
|
|
462
467
|
assert adminone.get_pcode("YEM", "Ad Dal", logname="test") == (
|
|
463
468
|
"YE30",
|
|
@@ -500,7 +505,6 @@ class TestAdminLevel:
|
|
|
500
505
|
"test - NGA: Matching (pcode length conversion) NG015 to Federal Capital Territory on map",
|
|
501
506
|
"test - UKR: Matching (substring) Chernihiv Oblast to Chernihivska on map",
|
|
502
507
|
"test - YEM: Matching (substring) Ad Dal to Ad Dali' on map",
|
|
503
|
-
"test - YEM: Matching (substring) Ad Dali to Ad Dali' on map",
|
|
504
508
|
"test - YEM: Matching (pcode length conversion) YE30 to Ad Dali' on map",
|
|
505
509
|
]
|
|
506
510
|
output = adminone.output_ignored()
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import unicodedata
|
|
3
|
-
|
|
4
|
-
from unidecode import unidecode
|
|
5
|
-
|
|
6
|
-
non_ascii = "([^\x00-\x7f])+"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def clean_name(name: str) -> str:
|
|
10
|
-
"""
|
|
11
|
-
Replace accented characters with non-accented ones in given name. Also
|
|
12
|
-
strip whitespace from start and end and make lwoercase.
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
name (str): Name to change
|
|
16
|
-
|
|
17
|
-
Returns:
|
|
18
|
-
str: Name without accented characters
|
|
19
|
-
"""
|
|
20
|
-
#
|
|
21
|
-
clean_name = "".join(
|
|
22
|
-
c
|
|
23
|
-
for c in unicodedata.normalize("NFD", name)
|
|
24
|
-
if unicodedata.category(c) != "Mn"
|
|
25
|
-
)
|
|
26
|
-
# Remove all non-ASCII characters
|
|
27
|
-
clean_name = re.sub(non_ascii, " ", clean_name)
|
|
28
|
-
clean_name = unidecode(clean_name)
|
|
29
|
-
return clean_name.strip().lower()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/.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
|
{hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/global_pcode_lengths.csv
RENAMED
|
File without changes
|
{hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/global_pcodes_adm_1_2.csv
RENAMED
|
File without changes
|
{hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/tests/fixtures/secondary_historic_rates.csv
RENAMED
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.7.4 → hdx_python_country-3.7.6}/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.4 → hdx_python_country-3.7.6}/tests/hdx/location/test_wfp_exchangerates.py
RENAMED
|
File without changes
|