hdx-python-country 3.7.1__tar.gz → 3.7.3__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.1 → hdx_python_country-3.7.3}/.config/pre-commit-config.yaml +4 -4
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/.github/workflows/publish.yaml +2 -1
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/.github/workflows/run-python-tests.yaml +4 -6
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/PKG-INFO +3 -3
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/documentation/main.md +13 -4
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/pyproject.toml +14 -18
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/requirements.txt +21 -25
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/_version.py +2 -2
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/adminlevel.py +115 -25
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/names.py +3 -1
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/phonetics.py +10 -10
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/fixtures/adminlevel.yaml +1 -0
- hdx_python_country-3.7.3/tests/fixtures/adminlevelparent.yaml +26 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/hdx/location/test_adminlevel.py +159 -5
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/.config/coveragerc +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/.config/pytest.ini +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/.config/ruff.toml +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/.gitignore +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/CONTRIBUTING.md +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/LICENSE +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/README.md +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/documentation/pydoc-markdown.yaml +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/country.py +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/currency.py +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/src/hdx/location/wfp_exchangerates.py +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/fixtures/global_pcode_lengths.csv +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/fixtures/global_pcodes_adm_1_2.csv +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/fixtures/secondary_historic_rates.csv +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/fixtures/secondary_rates.json +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/hdx/location/test_country.py +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/hdx/location/test_currency.py +0 -0
- {hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/hdx/location/test_wfp_exchangerates.py +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
default_language_version:
|
|
2
|
-
python: python3.
|
|
2
|
+
python: python3.12
|
|
3
3
|
repos:
|
|
4
4
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
-
rev: v4.
|
|
5
|
+
rev: v4.6.0
|
|
6
6
|
hooks:
|
|
7
7
|
- id: trailing-whitespace
|
|
8
8
|
- id: end-of-file-fixer
|
|
9
9
|
- id: check-ast
|
|
10
10
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
11
|
-
rev: v0.4.
|
|
11
|
+
rev: v0.4.8
|
|
12
12
|
hooks:
|
|
13
13
|
# Run the linter.
|
|
14
14
|
- id: ruff
|
|
@@ -17,7 +17,7 @@ repos:
|
|
|
17
17
|
- id: ruff-format
|
|
18
18
|
args: [--config, .config/ruff.toml]
|
|
19
19
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
20
|
-
rev: 0.
|
|
20
|
+
rev: 0.2.10
|
|
21
21
|
hooks:
|
|
22
22
|
# Run the pip compile
|
|
23
23
|
- id: pip-compile
|
{hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/.github/workflows/run-python-tests.yaml
RENAMED
|
@@ -26,17 +26,15 @@ jobs:
|
|
|
26
26
|
- name: Install dependencies
|
|
27
27
|
run: |
|
|
28
28
|
python -m pip install --upgrade pip
|
|
29
|
-
|
|
29
|
+
- name: Install Hatch
|
|
30
|
+
uses: pypa/hatch@install
|
|
30
31
|
- name: Test with hatch/pytest
|
|
31
|
-
env:
|
|
32
|
-
WFP_KEY: ${{ secrets.WFP_KEY }}
|
|
33
|
-
WFP_SECRET: ${{ secrets.WFP_SECRET }}
|
|
34
32
|
run: |
|
|
35
|
-
hatch
|
|
33
|
+
hatch test
|
|
36
34
|
- name: Check styling
|
|
37
35
|
if: always()
|
|
38
36
|
run: |
|
|
39
|
-
hatch
|
|
37
|
+
hatch fmt --check
|
|
40
38
|
- name: Publish Unit Test Results
|
|
41
39
|
uses: EnricoMi/publish-unit-test-result-action@v2
|
|
42
40
|
if: always()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: hdx-python-country
|
|
3
|
-
Version: 3.7.
|
|
3
|
+
Version: 3.7.3
|
|
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,9 +25,9 @@ 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.
|
|
28
|
+
Requires-Dist: hdx-python-utilities>=3.7.0
|
|
29
29
|
Requires-Dist: libhxl>=5.2.1
|
|
30
|
-
Requires-Dist:
|
|
30
|
+
Requires-Dist: rapidfuzz
|
|
31
31
|
Provides-Extra: dev
|
|
32
32
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
33
33
|
Provides-Extra: test
|
|
@@ -113,10 +113,19 @@ The administration level mappings takes input configuration dictionary,
|
|
|
113
113
|
|
|
114
114
|
*admin_config* can have the following optional keys:
|
|
115
115
|
|
|
116
|
-
*countries_fuzzy_try* are countries (iso3 codes) for which to try fuzzy
|
|
117
|
-
|
|
118
|
-
*
|
|
119
|
-
|
|
116
|
+
*countries_fuzzy_try* are countries (iso3 codes) for which to try fuzzy
|
|
117
|
+
matching. Default is all countries.
|
|
118
|
+
*admin_name_mappings* is a dictionary of mappings from name to pcode. These can
|
|
119
|
+
be global or they can be restricted by country or parent (if the AdminLevel
|
|
120
|
+
object has been set up with parents). Keys take the form "MAPPING",
|
|
121
|
+
"AFG|MAPPING" or "AF01|MAPPING".
|
|
122
|
+
*admin_name_replacements* is a dictionary of textual replacements to try when
|
|
123
|
+
fuzzy matching. It maps from string to string replacement. The replacements can
|
|
124
|
+
be global or they can be restricted by country or parent (if the AdminLevel
|
|
125
|
+
object has been set up with parents). Keys take the form "STRING_TO_REPLACE",
|
|
126
|
+
"AFG|STRING_TO_REPLACE" or "AF01|STRING_TO_REPLACE".
|
|
127
|
+
*admin_fuzzy_dont* is a list of names for which fuzzy matching should not be
|
|
128
|
+
tried
|
|
120
129
|
|
|
121
130
|
Once an AdminLevel object is constructed, one of three setup methods must be
|
|
122
131
|
called: *setup_from_admin_info*, *setup_from_libhxl_dataset* or
|
|
@@ -34,9 +34,9 @@ classifiers = [
|
|
|
34
34
|
requires-python = ">=3.8"
|
|
35
35
|
|
|
36
36
|
dependencies = [
|
|
37
|
-
"hdx-python-utilities>=3.
|
|
37
|
+
"hdx-python-utilities>=3.7.0",
|
|
38
38
|
"libhxl>=5.2.1",
|
|
39
|
-
"
|
|
39
|
+
"rapidfuzz",
|
|
40
40
|
]
|
|
41
41
|
dynamic = ["version"]
|
|
42
42
|
|
|
@@ -79,25 +79,21 @@ version_scheme = "python-simplified-semver"
|
|
|
79
79
|
|
|
80
80
|
# Tests
|
|
81
81
|
|
|
82
|
-
[tool.hatch.envs.test]
|
|
83
|
-
features = ["test"]
|
|
82
|
+
[tool.hatch.envs.hatch-test]
|
|
83
|
+
features = ["test"]
|
|
84
84
|
|
|
85
|
-
[tool.hatch.envs.test.
|
|
86
|
-
|
|
85
|
+
[[tool.hatch.envs.hatch-test.matrix]]
|
|
86
|
+
python = ["3.12"]
|
|
87
|
+
|
|
88
|
+
[tool.hatch.envs.hatch-test.scripts]
|
|
89
|
+
run = """
|
|
87
90
|
pytest -c .config/pytest.ini --rootdir=. --junitxml=test-results.xml \
|
|
88
91
|
--cov --cov-config=.config/coveragerc --no-cov-on-fail \
|
|
89
92
|
--cov-report=lcov --cov-report=term-missing
|
|
90
93
|
"""
|
|
91
94
|
|
|
92
|
-
[
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
[
|
|
96
|
-
|
|
97
|
-
dependencies = ["ruff"]
|
|
98
|
-
|
|
99
|
-
[tool.hatch.envs.lint.scripts]
|
|
100
|
-
style = [
|
|
101
|
-
"ruff check --config .config/ruff.toml --diff {args:.}",
|
|
102
|
-
"ruff format --config .config/ruff.toml --diff {args:.}",
|
|
103
|
-
]
|
|
95
|
+
[tool.hatch.envs.hatch-static-analysis.scripts]
|
|
96
|
+
format-check = ["ruff format --config .config/ruff.toml --check --diff {args:.}",]
|
|
97
|
+
format-fix = ["ruff format --config .config/ruff.toml {args:.}",]
|
|
98
|
+
lint-check = ["ruff check --config .config/ruff.toml {args:.}",]
|
|
99
|
+
lint-fix = ["ruff check --config .config/ruff.toml --fix {args:.}",]
|
|
@@ -8,7 +8,7 @@ attrs==23.2.0
|
|
|
8
8
|
# jsonlines
|
|
9
9
|
# jsonschema
|
|
10
10
|
# referencing
|
|
11
|
-
certifi==2024.
|
|
11
|
+
certifi==2024.6.2
|
|
12
12
|
# via requests
|
|
13
13
|
cfgv==3.4.0
|
|
14
14
|
# via pre-commit
|
|
@@ -18,17 +18,17 @@ charset-normalizer==3.3.2
|
|
|
18
18
|
# via requests
|
|
19
19
|
click==8.1.7
|
|
20
20
|
# via typer
|
|
21
|
-
coverage==7.5.
|
|
21
|
+
coverage==7.5.3
|
|
22
22
|
# via pytest-cov
|
|
23
23
|
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.15.3
|
|
28
28
|
# via virtualenv
|
|
29
29
|
frictionless==5.17.0
|
|
30
30
|
# via hdx-python-utilities
|
|
31
|
-
hdx-python-utilities==3.
|
|
31
|
+
hdx-python-utilities==3.7.0
|
|
32
32
|
# via hdx-python-country (pyproject.toml)
|
|
33
33
|
humanize==4.9.0
|
|
34
34
|
# via frictionless
|
|
@@ -36,7 +36,7 @@ identify==2.5.36
|
|
|
36
36
|
# via pre-commit
|
|
37
37
|
idna==3.7
|
|
38
38
|
# via requests
|
|
39
|
-
ijson==3.
|
|
39
|
+
ijson==3.3.0
|
|
40
40
|
# via hdx-python-utilities
|
|
41
41
|
iniconfig==2.0.0
|
|
42
42
|
# via pytest
|
|
@@ -60,17 +60,17 @@ loguru==0.7.2
|
|
|
60
60
|
# via hdx-python-utilities
|
|
61
61
|
markdown-it-py==3.0.0
|
|
62
62
|
# via rich
|
|
63
|
-
marko==2.
|
|
63
|
+
marko==2.1.1
|
|
64
64
|
# via frictionless
|
|
65
65
|
markupsafe==2.1.5
|
|
66
66
|
# via jinja2
|
|
67
67
|
mdurl==0.1.2
|
|
68
68
|
# via markdown-it-py
|
|
69
|
-
nodeenv==1.
|
|
69
|
+
nodeenv==1.9.1
|
|
70
70
|
# via pre-commit
|
|
71
|
-
openpyxl==3.1.
|
|
71
|
+
openpyxl==3.1.4
|
|
72
72
|
# via hdx-python-utilities
|
|
73
|
-
packaging==24.
|
|
73
|
+
packaging==24.1
|
|
74
74
|
# via pytest
|
|
75
75
|
petl==1.7.15
|
|
76
76
|
# via frictionless
|
|
@@ -84,21 +84,19 @@ ply==3.11
|
|
|
84
84
|
# libhxl
|
|
85
85
|
pre-commit==3.7.1
|
|
86
86
|
# via hdx-python-country (pyproject.toml)
|
|
87
|
-
pydantic==2.7.
|
|
87
|
+
pydantic==2.7.4
|
|
88
88
|
# via frictionless
|
|
89
|
-
pydantic-core==2.18.
|
|
89
|
+
pydantic-core==2.18.4
|
|
90
90
|
# via pydantic
|
|
91
91
|
pygments==2.18.0
|
|
92
92
|
# via rich
|
|
93
|
-
|
|
94
|
-
# via hdx-python-country (pyproject.toml)
|
|
95
|
-
pytest==8.2.1
|
|
93
|
+
pytest==8.2.2
|
|
96
94
|
# via
|
|
97
95
|
# hdx-python-country (pyproject.toml)
|
|
98
96
|
# pytest-cov
|
|
99
97
|
pytest-cov==5.0.0
|
|
100
98
|
# via hdx-python-country (pyproject.toml)
|
|
101
|
-
python-dateutil==2.
|
|
99
|
+
python-dateutil==2.9.0.post0
|
|
102
100
|
# via
|
|
103
101
|
# frictionless
|
|
104
102
|
# hdx-python-utilities
|
|
@@ -112,13 +110,15 @@ pyyaml==6.0.1
|
|
|
112
110
|
# frictionless
|
|
113
111
|
# pre-commit
|
|
114
112
|
# tableschema-to-template
|
|
113
|
+
rapidfuzz==3.9.3
|
|
114
|
+
# via hdx-python-country (pyproject.toml)
|
|
115
115
|
ratelimit==2.2.1
|
|
116
116
|
# via hdx-python-utilities
|
|
117
117
|
referencing==0.35.1
|
|
118
118
|
# via
|
|
119
119
|
# jsonschema
|
|
120
120
|
# jsonschema-specifications
|
|
121
|
-
requests==2.32.
|
|
121
|
+
requests==2.32.3
|
|
122
122
|
# via
|
|
123
123
|
# frictionless
|
|
124
124
|
# libhxl
|
|
@@ -137,8 +137,6 @@ ruamel-yaml==0.18.6
|
|
|
137
137
|
# via hdx-python-utilities
|
|
138
138
|
ruamel-yaml-clib==0.2.8
|
|
139
139
|
# via ruamel-yaml
|
|
140
|
-
setuptools==70.0.0
|
|
141
|
-
# via nodeenv
|
|
142
140
|
shellingham==1.5.4
|
|
143
141
|
# via typer
|
|
144
142
|
simpleeval==0.9.13
|
|
@@ -149,7 +147,7 @@ six==1.16.0
|
|
|
149
147
|
# python-dateutil
|
|
150
148
|
stringcase==1.2.0
|
|
151
149
|
# via frictionless
|
|
152
|
-
structlog==24.
|
|
150
|
+
structlog==24.2.0
|
|
153
151
|
# via libhxl
|
|
154
152
|
tableschema-to-template==0.0.13
|
|
155
153
|
# via hdx-python-utilities
|
|
@@ -159,21 +157,19 @@ text-unidecode==1.3
|
|
|
159
157
|
# via python-slugify
|
|
160
158
|
typer==0.12.3
|
|
161
159
|
# via frictionless
|
|
162
|
-
typing-extensions==4.
|
|
160
|
+
typing-extensions==4.12.2
|
|
163
161
|
# via
|
|
164
162
|
# frictionless
|
|
165
163
|
# pydantic
|
|
166
164
|
# pydantic-core
|
|
167
165
|
# typer
|
|
168
166
|
unidecode==1.3.8
|
|
169
|
-
# via
|
|
170
|
-
|
|
171
|
-
# pyphonetics
|
|
172
|
-
urllib3==2.2.1
|
|
167
|
+
# via libhxl
|
|
168
|
+
urllib3==2.2.2
|
|
173
169
|
# via
|
|
174
170
|
# libhxl
|
|
175
171
|
# requests
|
|
176
|
-
validators==0.28.
|
|
172
|
+
validators==0.28.3
|
|
177
173
|
# via frictionless
|
|
178
174
|
virtualenv==20.26.2
|
|
179
175
|
# via pre-commit
|
|
@@ -5,7 +5,6 @@ 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
10
|
from hdx.location.names import clean_name
|
|
@@ -147,7 +146,7 @@ class AdminLevel:
|
|
|
147
146
|
self.pcode_to_name[pcode] = adm_name
|
|
148
147
|
|
|
149
148
|
name_to_pcode = self.name_to_pcode.get(countryiso3, {})
|
|
150
|
-
name_to_pcode[
|
|
149
|
+
name_to_pcode[clean_name(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[clean_name(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
|
|
@@ -306,7 +305,7 @@ class AdminLevel:
|
|
|
306
305
|
"""Get admin level for country
|
|
307
306
|
|
|
308
307
|
Args:
|
|
309
|
-
countryiso3 (str):
|
|
308
|
+
countryiso3 (str): ISO3 country code
|
|
310
309
|
|
|
311
310
|
Returns:
|
|
312
311
|
int: Admin level
|
|
@@ -320,7 +319,7 @@ class AdminLevel:
|
|
|
320
319
|
"""Get pcode length for country
|
|
321
320
|
|
|
322
321
|
Args:
|
|
323
|
-
countryiso3 (str):
|
|
322
|
+
countryiso3 (str): ISO3 country code
|
|
324
323
|
|
|
325
324
|
Returns:
|
|
326
325
|
Optional[int]: Country's pcode length or None
|
|
@@ -517,6 +516,41 @@ class AdminLevel:
|
|
|
517
516
|
return pcode
|
|
518
517
|
return None
|
|
519
518
|
|
|
519
|
+
def get_admin_name_replacements(
|
|
520
|
+
self, countryiso3: str, parent: Optional[str]
|
|
521
|
+
) -> Dict[str, str]:
|
|
522
|
+
"""Get relevant admin name replacements from admin name replacements
|
|
523
|
+
which is a dictionary of mappings from string to string replacement.
|
|
524
|
+
These can be global or they can be restricted by
|
|
525
|
+
country or parent (if the AdminLevel object has been set up with
|
|
526
|
+
parents). Keys take the form "STRING_TO_REPLACE",
|
|
527
|
+
"AFG|STRING_TO_REPLACE" or "AF01|STRING_TO_REPLACE".
|
|
528
|
+
|
|
529
|
+
Args:
|
|
530
|
+
countryiso3 (str): ISO3 country code
|
|
531
|
+
parent (Optional[str]): Parent admin code
|
|
532
|
+
|
|
533
|
+
Returns:
|
|
534
|
+
Dict[str, str]: Relevant admin name replacements
|
|
535
|
+
"""
|
|
536
|
+
relevant_name_replacements = {}
|
|
537
|
+
for key, value in self.admin_name_replacements.items():
|
|
538
|
+
if "|" not in key:
|
|
539
|
+
if key not in relevant_name_replacements:
|
|
540
|
+
relevant_name_replacements[key] = value
|
|
541
|
+
continue
|
|
542
|
+
prefix, name = key.split("|")
|
|
543
|
+
if parent:
|
|
544
|
+
if prefix == parent:
|
|
545
|
+
if name not in relevant_name_replacements:
|
|
546
|
+
relevant_name_replacements[name] = value
|
|
547
|
+
continue
|
|
548
|
+
if prefix == countryiso3:
|
|
549
|
+
if name not in relevant_name_replacements:
|
|
550
|
+
relevant_name_replacements[name] = value
|
|
551
|
+
continue
|
|
552
|
+
return relevant_name_replacements
|
|
553
|
+
|
|
520
554
|
def fuzzy_pcode(
|
|
521
555
|
self,
|
|
522
556
|
countryiso3: str,
|
|
@@ -526,7 +560,7 @@ class AdminLevel:
|
|
|
526
560
|
"""Fuzzy match name to pcode
|
|
527
561
|
|
|
528
562
|
Args:
|
|
529
|
-
countryiso3 (str):
|
|
563
|
+
countryiso3 (str): ISO3 country code
|
|
530
564
|
name (str): Name to match
|
|
531
565
|
**kwargs:
|
|
532
566
|
parent (Optional[str]): Parent admin code
|
|
@@ -543,8 +577,17 @@ class AdminLevel:
|
|
|
543
577
|
if logname:
|
|
544
578
|
self.ignored.add((logname, countryiso3))
|
|
545
579
|
return None
|
|
546
|
-
if self.use_parent
|
|
547
|
-
parent = kwargs
|
|
580
|
+
if self.use_parent:
|
|
581
|
+
parent = kwargs.get("parent")
|
|
582
|
+
else:
|
|
583
|
+
parent = None
|
|
584
|
+
if parent is None:
|
|
585
|
+
name_to_pcode = self.name_to_pcode.get(countryiso3)
|
|
586
|
+
if not name_to_pcode:
|
|
587
|
+
if logname:
|
|
588
|
+
self.errors.add((logname, countryiso3))
|
|
589
|
+
return None
|
|
590
|
+
else:
|
|
548
591
|
name_parent_to_pcode = self.name_parent_to_pcode.get(countryiso3)
|
|
549
592
|
if not name_parent_to_pcode:
|
|
550
593
|
if logname:
|
|
@@ -555,15 +598,10 @@ class AdminLevel:
|
|
|
555
598
|
if logname:
|
|
556
599
|
self.errors.add((logname, countryiso3, parent))
|
|
557
600
|
return None
|
|
558
|
-
else:
|
|
559
|
-
name_to_pcode = self.name_to_pcode.get(countryiso3)
|
|
560
|
-
if not name_to_pcode:
|
|
561
|
-
if logname:
|
|
562
|
-
self.errors.add((logname, countryiso3))
|
|
563
|
-
return None
|
|
564
601
|
adm_name_lookup = clean_name(name)
|
|
565
602
|
adm_name_lookup2 = multiple_replace(
|
|
566
|
-
adm_name_lookup,
|
|
603
|
+
adm_name_lookup,
|
|
604
|
+
self.get_admin_name_replacements(countryiso3, parent),
|
|
567
605
|
)
|
|
568
606
|
pcode = name_to_pcode.get(
|
|
569
607
|
adm_name_lookup, name_to_pcode.get(adm_name_lookup2)
|
|
@@ -603,22 +641,25 @@ class AdminLevel:
|
|
|
603
641
|
break
|
|
604
642
|
if not pcode:
|
|
605
643
|
map_names = list(name_to_pcode.keys())
|
|
606
|
-
lower_mapnames = [x.lower() for x in map_names]
|
|
607
644
|
|
|
608
645
|
def al_transform_1(name):
|
|
609
|
-
|
|
646
|
+
prefix = name[:3]
|
|
647
|
+
if prefix == "al ":
|
|
610
648
|
return f"ad {name[3:]}"
|
|
649
|
+
elif prefix == "ad ":
|
|
650
|
+
return f"al {name[3:]}"
|
|
611
651
|
else:
|
|
612
652
|
return None
|
|
613
653
|
|
|
614
654
|
def al_transform_2(name):
|
|
615
|
-
|
|
655
|
+
prefix = name[:3]
|
|
656
|
+
if prefix == "al " or prefix == "ad ":
|
|
616
657
|
return name[3:]
|
|
617
658
|
else:
|
|
618
659
|
return None
|
|
619
660
|
|
|
620
661
|
matching_index = self.phonetics.match(
|
|
621
|
-
|
|
662
|
+
map_names,
|
|
622
663
|
adm_name_lookup,
|
|
623
664
|
alternative_name=adm_name_lookup2,
|
|
624
665
|
transform_possible_names=[al_transform_1, al_transform_2],
|
|
@@ -643,19 +684,48 @@ class AdminLevel:
|
|
|
643
684
|
)
|
|
644
685
|
return pcode
|
|
645
686
|
|
|
687
|
+
def get_name_mapped_pcode(
|
|
688
|
+
self, countryiso3: str, name: str, parent: Optional[str]
|
|
689
|
+
) -> Optional[str]:
|
|
690
|
+
"""Get pcode from admin name mappings which is a dictionary of mappings
|
|
691
|
+
from name to pcode. These can be global or they can be restricted by
|
|
692
|
+
country or parent (if the AdminLevel object has been set up with
|
|
693
|
+
parents). Keys take the form "MAPPING", "AFG|MAPPING" or
|
|
694
|
+
"AF01|MAPPING".
|
|
695
|
+
|
|
696
|
+
Args:
|
|
697
|
+
countryiso3 (str): ISO3 country code
|
|
698
|
+
name (str): Name to match
|
|
699
|
+
parent (Optional[str]): Parent admin code
|
|
700
|
+
|
|
701
|
+
Returns:
|
|
702
|
+
Optional[str]: P code match from admin name mappings or None if no match
|
|
703
|
+
"""
|
|
704
|
+
if parent:
|
|
705
|
+
pcode = self.admin_name_mappings.get(f"{parent}|{name}")
|
|
706
|
+
if pcode is None:
|
|
707
|
+
pcode = self.admin_name_mappings.get(f"{countryiso3}|{name}")
|
|
708
|
+
else:
|
|
709
|
+
pcode = self.admin_name_mappings.get(f"{countryiso3}|{name}")
|
|
710
|
+
if pcode is None:
|
|
711
|
+
pcode = self.admin_name_mappings.get(name)
|
|
712
|
+
return pcode
|
|
713
|
+
|
|
646
714
|
def get_pcode(
|
|
647
715
|
self,
|
|
648
716
|
countryiso3: str,
|
|
649
717
|
name: str,
|
|
650
718
|
fuzzy_match: bool = True,
|
|
719
|
+
fuzzy_length: int = 4,
|
|
651
720
|
**kwargs: Any,
|
|
652
721
|
) -> Tuple[Optional[str], bool]:
|
|
653
722
|
"""Get pcode for a given name
|
|
654
723
|
|
|
655
724
|
Args:
|
|
656
|
-
countryiso3 (str):
|
|
725
|
+
countryiso3 (str): ISO3 country code
|
|
657
726
|
name (str): Name to match
|
|
658
727
|
fuzzy_match (bool): Whether to try fuzzy matching. Defaults to True.
|
|
728
|
+
fuzzy_length (int): Minimum length for fuzzy matching. Defaults to 4.
|
|
659
729
|
**kwargs:
|
|
660
730
|
parent (Optional[str]): Parent admin code
|
|
661
731
|
logname (str): Log using this identifying name. Defaults to not logging.
|
|
@@ -663,9 +733,17 @@ class AdminLevel:
|
|
|
663
733
|
Returns:
|
|
664
734
|
Tuple[Optional[str], bool]: (Matched P code or None if no match, True if exact match or False if not)
|
|
665
735
|
"""
|
|
666
|
-
|
|
736
|
+
if self.use_parent:
|
|
737
|
+
parent = kwargs.get("parent")
|
|
738
|
+
else:
|
|
739
|
+
parent = None
|
|
740
|
+
pcode = self.get_name_mapped_pcode(countryiso3, name, parent)
|
|
667
741
|
if pcode and self.pcode_to_iso3[pcode] == countryiso3:
|
|
668
|
-
|
|
742
|
+
if parent:
|
|
743
|
+
if self.pcode_to_parent[pcode] == parent:
|
|
744
|
+
return pcode, True
|
|
745
|
+
else:
|
|
746
|
+
return pcode, True
|
|
669
747
|
if self.looks_like_pcode(name):
|
|
670
748
|
pcode = name.upper()
|
|
671
749
|
if pcode in self.pcodes: # name is a p-code
|
|
@@ -677,8 +755,7 @@ class AdminLevel:
|
|
|
677
755
|
)
|
|
678
756
|
return pcode, True
|
|
679
757
|
else:
|
|
680
|
-
if
|
|
681
|
-
parent = kwargs["parent"]
|
|
758
|
+
if parent:
|
|
682
759
|
name_parent_to_pcode = self.name_parent_to_pcode.get(
|
|
683
760
|
countryiso3
|
|
684
761
|
)
|
|
@@ -694,7 +771,7 @@ class AdminLevel:
|
|
|
694
771
|
pcode = name_to_pcode.get(name.lower())
|
|
695
772
|
if pcode:
|
|
696
773
|
return pcode, True
|
|
697
|
-
if not fuzzy_match:
|
|
774
|
+
if not fuzzy_match or len(name) < fuzzy_length:
|
|
698
775
|
return None, True
|
|
699
776
|
pcode = self.fuzzy_pcode(countryiso3, name, **kwargs)
|
|
700
777
|
return pcode, False
|
|
@@ -756,3 +833,16 @@ class AdminLevel:
|
|
|
756
833
|
logger.info(line)
|
|
757
834
|
output.append(line)
|
|
758
835
|
return output
|
|
836
|
+
|
|
837
|
+
def output_admin_name_replacements(self) -> List[str]:
|
|
838
|
+
"""Output log of name replacements
|
|
839
|
+
|
|
840
|
+
Returns:
|
|
841
|
+
List[str]: List of name replacements
|
|
842
|
+
"""
|
|
843
|
+
output = []
|
|
844
|
+
for name, replacement in self.admin_name_replacements.items():
|
|
845
|
+
line = f"{name}: {replacement}"
|
|
846
|
+
logger.info(line)
|
|
847
|
+
output.append(line)
|
|
848
|
+
return output
|
|
@@ -3,7 +3,7 @@ import unicodedata
|
|
|
3
3
|
|
|
4
4
|
from unidecode import unidecode
|
|
5
5
|
|
|
6
|
-
non_ascii = "([^\x00-\x7f])+"
|
|
6
|
+
non_ascii = r"([^\x00-\x7f])+"
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def clean_name(name: str) -> str:
|
|
@@ -25,5 +25,7 @@ def clean_name(name: str) -> str:
|
|
|
25
25
|
)
|
|
26
26
|
# Remove all non-ASCII characters
|
|
27
27
|
clean_name = re.sub(non_ascii, " ", clean_name)
|
|
28
|
+
clean_name = clean_name.replace("'", "")
|
|
29
|
+
clean_name = re.sub(r"[\W_]", " ", clean_name)
|
|
28
30
|
clean_name = unidecode(clean_name)
|
|
29
31
|
return clean_name.strip().lower()
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
from typing import Callable, Optional
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from rapidfuzz import fuzz
|
|
4
4
|
|
|
5
5
|
from hdx.utilities.typehint import ListTuple
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class Phonetics
|
|
8
|
+
class Phonetics:
|
|
9
9
|
def match(
|
|
10
10
|
self,
|
|
11
11
|
possible_names: ListTuple,
|
|
12
12
|
name: str,
|
|
13
13
|
alternative_name: Optional[str] = None,
|
|
14
14
|
transform_possible_names: ListTuple[Callable] = [],
|
|
15
|
-
threshold:
|
|
15
|
+
threshold: float = 60,
|
|
16
16
|
) -> Optional[int]:
|
|
17
17
|
"""
|
|
18
18
|
Match name to one of the given possible names. Returns None if no match
|
|
@@ -23,22 +23,22 @@ class Phonetics(pyphonetics.RefinedSoundex):
|
|
|
23
23
|
name (str): Name to match
|
|
24
24
|
alternative_name (str): Alternative name to match. Defaults to None.
|
|
25
25
|
transform_possible_names (ListTuple[Callable]): Functions to transform possible names.
|
|
26
|
-
threshold: Match threshold. Defaults to
|
|
26
|
+
threshold (float): Match threshold. Value is 0-100. Defaults to 60.
|
|
27
27
|
|
|
28
28
|
Returns:
|
|
29
29
|
Optional[int]: Index of matching name from possible names or None
|
|
30
30
|
"""
|
|
31
|
-
|
|
31
|
+
max_similarity = 0
|
|
32
32
|
matching_index = None
|
|
33
33
|
|
|
34
34
|
transform_possible_names.insert(0, lambda x: x)
|
|
35
35
|
|
|
36
36
|
def check_name(name, possible_name):
|
|
37
|
-
nonlocal
|
|
37
|
+
nonlocal max_similarity, matching_index # noqa: E999
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
if
|
|
41
|
-
|
|
39
|
+
similarity = fuzz.token_sort_ratio(name, possible_name)
|
|
40
|
+
if similarity > max_similarity:
|
|
41
|
+
max_similarity = similarity
|
|
42
42
|
matching_index = i
|
|
43
43
|
|
|
44
44
|
for i, possible_name in enumerate(possible_names):
|
|
@@ -51,6 +51,6 @@ class Phonetics(pyphonetics.RefinedSoundex):
|
|
|
51
51
|
check_name(name, transformed_possible_name)
|
|
52
52
|
if alternative_name:
|
|
53
53
|
check_name(alternative_name, transformed_possible_name)
|
|
54
|
-
if
|
|
54
|
+
if max_similarity < threshold:
|
|
55
55
|
return None
|
|
56
56
|
return matching_index
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
admin_info_with_parent:
|
|
2
|
+
- {pcode: AF0101, name: Kabul, iso3: AFG, parent: AF01}
|
|
3
|
+
- {pcode: AF0102, name: Paghman, iso3: AFG, parent: AF01}
|
|
4
|
+
- {pcode: AF0201, name: Kabul, iso3: AFG, parent: AF02} # testing purposes
|
|
5
|
+
- {pcode: AF0301, name: Charikar, iso3: AFG, parent: AF03}
|
|
6
|
+
- {pcode: AF0401, name: Maydan Shahr, iso3: AFG, parent: AF04}
|
|
7
|
+
- {pcode: AF0501, name: Pul-e-Alam, iso3: AFG, parent: AF05}
|
|
8
|
+
- {pcode: AF0501, name: Pul-e-Alam, iso3: AFG, parent: AF05}
|
|
9
|
+
- {pcode: CD2013, name: Mbanza-Ngungu, iso3: COD, parent: CD20}
|
|
10
|
+
- {pcode: CD3102, name: Kenge, iso3: COD, parent: CD31}
|
|
11
|
+
- {pcode: MW305, name: Blantyre, iso3: MWI, parent: MW3}
|
|
12
|
+
|
|
13
|
+
admin_name_mappings:
|
|
14
|
+
"MyMapping": "AF0301"
|
|
15
|
+
"AFG|MyMapping2": "AF0401"
|
|
16
|
+
"AF05|MyMapping3": "AF0501"
|
|
17
|
+
|
|
18
|
+
admin_name_replacements:
|
|
19
|
+
"wx": "an"
|
|
20
|
+
|
|
21
|
+
alt1_admin_name_replacements:
|
|
22
|
+
"COD|wx": "an"
|
|
23
|
+
|
|
24
|
+
alt2_admin_name_replacements:
|
|
25
|
+
"CD20|wx": "an"
|
|
26
|
+
"CD31|wx": "en"
|
|
@@ -14,6 +14,10 @@ class TestAdminLevel:
|
|
|
14
14
|
def config(self):
|
|
15
15
|
return load_yaml(join("tests", "fixtures", "adminlevel.yaml"))
|
|
16
16
|
|
|
17
|
+
@pytest.fixture(scope="function")
|
|
18
|
+
def config_parent(self):
|
|
19
|
+
return load_yaml(join("tests", "fixtures", "adminlevelparent.yaml"))
|
|
20
|
+
|
|
17
21
|
@pytest.fixture(scope="function")
|
|
18
22
|
def url(self):
|
|
19
23
|
return "https://raw.githubusercontent.com/OCHA-DAP/hdx-python-country/main/tests/fixtures/global_pcodes_adm_1_2.csv"
|
|
@@ -161,9 +165,27 @@ class TestAdminLevel:
|
|
|
161
165
|
assert output[31] == "Juba Dhexe: Middle Juba (SO27)"
|
|
162
166
|
assert output[61] == "CU Niamey: Niamey (NER008)"
|
|
163
167
|
|
|
168
|
+
output = adminone.output_admin_name_replacements()
|
|
169
|
+
assert output == [
|
|
170
|
+
" urban: ",
|
|
171
|
+
"sud: south",
|
|
172
|
+
"ouest: west",
|
|
173
|
+
"est: east",
|
|
174
|
+
"nord: north",
|
|
175
|
+
"': ",
|
|
176
|
+
"/: ",
|
|
177
|
+
".: ",
|
|
178
|
+
" region: ",
|
|
179
|
+
" oblast: ",
|
|
180
|
+
]
|
|
181
|
+
|
|
164
182
|
def test_adminlevel_fuzzy(self, config):
|
|
165
183
|
adminone = AdminLevel(config)
|
|
166
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
|
+
)
|
|
167
189
|
assert adminone.get_pcode("YEM", "Al Dali", logname="test") == (
|
|
168
190
|
"YE30",
|
|
169
191
|
False,
|
|
@@ -174,20 +196,30 @@ class TestAdminLevel:
|
|
|
174
196
|
"YE30",
|
|
175
197
|
False,
|
|
176
198
|
)
|
|
199
|
+
assert adminone.get_pcode("YEM", "Ad Jauf", logname="test") == (
|
|
200
|
+
"YE16",
|
|
201
|
+
False,
|
|
202
|
+
)
|
|
203
|
+
assert adminone.get_pcode("AFG", "Sar-E-Pul", logname="test") == (
|
|
204
|
+
"AF22",
|
|
205
|
+
False,
|
|
206
|
+
)
|
|
177
207
|
assert adminone.get_pcode("SOM", "Bay", logname="test") == (
|
|
178
208
|
"SO24",
|
|
179
209
|
True,
|
|
180
210
|
)
|
|
181
211
|
output = adminone.output_matches()
|
|
182
212
|
assert output == [
|
|
213
|
+
"test - YEM: Matching (fuzzy) Ad Jauf to Al Jawf on map",
|
|
183
214
|
"test - YEM: Matching (fuzzy) Al Dali to Ad Dali on map",
|
|
184
215
|
"test - YEM: Matching (fuzzy) Al Dhale'e / الضالع to Ad Dali on map",
|
|
216
|
+
"test - YEM: Matching (fuzzy) Al_Dhale'a to Ad Dali on map",
|
|
185
217
|
]
|
|
186
218
|
|
|
187
|
-
def test_adminlevel_parent(self,
|
|
188
|
-
admintwo = AdminLevel(
|
|
219
|
+
def test_adminlevel_parent(self, config_parent):
|
|
220
|
+
admintwo = AdminLevel(config_parent)
|
|
189
221
|
admintwo.countries_fuzzy_try = None
|
|
190
|
-
admintwo.setup_from_admin_info(
|
|
222
|
+
admintwo.setup_from_admin_info(config_parent["admin_info_with_parent"])
|
|
191
223
|
assert admintwo.use_parent is True
|
|
192
224
|
assert admintwo.pcode_to_parent["AF0101"] == "AF01"
|
|
193
225
|
assert admintwo.get_pcode("AFG", "AF0101", logname="test") == (
|
|
@@ -223,6 +255,129 @@ class TestAdminLevel:
|
|
|
223
255
|
"ABC", "Kabull", parent="AF02", logname="test"
|
|
224
256
|
) == (None, False)
|
|
225
257
|
|
|
258
|
+
output = admintwo.output_admin_name_mappings()
|
|
259
|
+
assert output == [
|
|
260
|
+
"MyMapping: Charikar (AF0301)",
|
|
261
|
+
"AFG|MyMapping2: Maydan Shahr (AF0401)",
|
|
262
|
+
"AF05|MyMapping3: Pul-e-Alam (AF0501)",
|
|
263
|
+
]
|
|
264
|
+
assert admintwo.get_pcode("AFG", "MyMapping", logname="test") == (
|
|
265
|
+
"AF0301",
|
|
266
|
+
True,
|
|
267
|
+
)
|
|
268
|
+
assert admintwo.get_pcode(
|
|
269
|
+
"AFG", "MyMapping", parent="AF03", logname="test"
|
|
270
|
+
) == ("AF0301", True)
|
|
271
|
+
assert admintwo.get_pcode(
|
|
272
|
+
"AFG", "MyMapping", parent="AF04", logname="test"
|
|
273
|
+
) == (None, False)
|
|
274
|
+
|
|
275
|
+
assert admintwo.get_pcode("AFG", "MyMapping2", logname="test") == (
|
|
276
|
+
"AF0401",
|
|
277
|
+
True,
|
|
278
|
+
)
|
|
279
|
+
assert admintwo.get_pcode(
|
|
280
|
+
"AFG", "MyMapping2", parent="AF04", logname="test"
|
|
281
|
+
) == ("AF0401", True)
|
|
282
|
+
assert admintwo.get_pcode(
|
|
283
|
+
"AFG", "MyMapping2", parent="AF05", logname="test"
|
|
284
|
+
) == (None, False)
|
|
285
|
+
|
|
286
|
+
assert admintwo.get_pcode("AFG", "MyMapping3", logname="test") == (
|
|
287
|
+
None,
|
|
288
|
+
False,
|
|
289
|
+
)
|
|
290
|
+
assert admintwo.get_pcode(
|
|
291
|
+
"AFG", "MyMapping3", parent="AF05", logname="test"
|
|
292
|
+
) == ("AF0501", True)
|
|
293
|
+
assert admintwo.get_pcode(
|
|
294
|
+
"AFG", "MyMapping3", parent="AF04", logname="test"
|
|
295
|
+
) == (None, False)
|
|
296
|
+
|
|
297
|
+
output = admintwo.output_admin_name_replacements()
|
|
298
|
+
assert output == ["wx: an"]
|
|
299
|
+
assert admintwo.get_pcode(
|
|
300
|
+
"COD", "City of Mbwxza-Nanga", logname="test"
|
|
301
|
+
) == ("CD2013", False)
|
|
302
|
+
assert admintwo.get_pcode(
|
|
303
|
+
"COD", "City of Mbwxza-Nanga", parent="CD20", logname="test"
|
|
304
|
+
) == ("CD2013", False)
|
|
305
|
+
assert admintwo.get_pcode(
|
|
306
|
+
"COD", "City of Mbwxza-Nanga", parent="CD19", logname="test"
|
|
307
|
+
) == (None, False)
|
|
308
|
+
assert admintwo.get_pcode(
|
|
309
|
+
"MWI", "City of Blwxtyre", logname="test"
|
|
310
|
+
) == (
|
|
311
|
+
"MW305",
|
|
312
|
+
False,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
admintwo.admin_name_replacements = config_parent[
|
|
316
|
+
"alt1_admin_name_replacements"
|
|
317
|
+
]
|
|
318
|
+
output = admintwo.output_admin_name_replacements()
|
|
319
|
+
assert output == ["COD|wx: an"]
|
|
320
|
+
assert admintwo.get_pcode(
|
|
321
|
+
"COD", "City of Mbwxza-Nanga", logname="test"
|
|
322
|
+
) == ("CD2013", False)
|
|
323
|
+
assert admintwo.get_pcode(
|
|
324
|
+
"COD", "City of Mbwxza-Nanga", parent="CD20", logname="test"
|
|
325
|
+
) == ("CD2013", False)
|
|
326
|
+
assert admintwo.get_pcode(
|
|
327
|
+
"COD", "City of Mbwxza-Nanga", parent="CD19", logname="test"
|
|
328
|
+
) == (None, False)
|
|
329
|
+
assert admintwo.get_pcode("COD", "Kenge City", logname="test") == (
|
|
330
|
+
"CD3102",
|
|
331
|
+
False,
|
|
332
|
+
)
|
|
333
|
+
assert admintwo.get_pcode("COD", "Kwxge City", logname="test") == (
|
|
334
|
+
None,
|
|
335
|
+
False,
|
|
336
|
+
)
|
|
337
|
+
assert admintwo.get_pcode(
|
|
338
|
+
"COD", "Kwxge City", parent="CD31", logname="test"
|
|
339
|
+
) == (None, False)
|
|
340
|
+
assert admintwo.get_pcode(
|
|
341
|
+
"MWI", "City of Blwxtyre", logname="test"
|
|
342
|
+
) == (
|
|
343
|
+
None,
|
|
344
|
+
False,
|
|
345
|
+
)
|
|
346
|
+
assert admintwo.get_pcode(
|
|
347
|
+
"MWI", "City of Blwxtyre", parent="MW3", logname="test"
|
|
348
|
+
) == (None, False)
|
|
349
|
+
|
|
350
|
+
admintwo.admin_name_replacements = config_parent[
|
|
351
|
+
"alt2_admin_name_replacements"
|
|
352
|
+
]
|
|
353
|
+
output = admintwo.output_admin_name_replacements()
|
|
354
|
+
assert output == ["CD20|wx: an", "CD31|wx: en"]
|
|
355
|
+
assert admintwo.get_pcode(
|
|
356
|
+
"COD", "City of Mbwxza-Nanga", logname="test"
|
|
357
|
+
) == (None, False)
|
|
358
|
+
assert admintwo.get_pcode(
|
|
359
|
+
"COD", "City of Mbwxza-Nanga", parent="CD20", logname="test"
|
|
360
|
+
) == ("CD2013", False)
|
|
361
|
+
assert admintwo.get_pcode(
|
|
362
|
+
"COD", "City of Mbwxza-Nanga", parent="CD19", logname="test"
|
|
363
|
+
) == (None, False)
|
|
364
|
+
assert admintwo.get_pcode("COD", "Kwxge City", logname="test") == (
|
|
365
|
+
None,
|
|
366
|
+
False,
|
|
367
|
+
)
|
|
368
|
+
assert admintwo.get_pcode(
|
|
369
|
+
"COD", "Kwxge City", parent="CD31", logname="test"
|
|
370
|
+
) == ("CD3102", False)
|
|
371
|
+
assert admintwo.get_pcode(
|
|
372
|
+
"MWI", "City of Blwxtyre", logname="test"
|
|
373
|
+
) == (
|
|
374
|
+
None,
|
|
375
|
+
False,
|
|
376
|
+
)
|
|
377
|
+
assert admintwo.get_pcode(
|
|
378
|
+
"MWI", "City of Blwxtyre", parent="MW3", logname="test"
|
|
379
|
+
) == (None, False)
|
|
380
|
+
|
|
226
381
|
def test_adminlevel_with_url(self, config, url):
|
|
227
382
|
adminone = AdminLevel(config)
|
|
228
383
|
with pytest.raises(HXLIOException):
|
|
@@ -322,7 +477,7 @@ class TestAdminLevel:
|
|
|
322
477
|
)
|
|
323
478
|
assert adminone.get_pcode("YEM", "Ad Dali", logname="test") == (
|
|
324
479
|
"YE30",
|
|
325
|
-
|
|
480
|
+
True,
|
|
326
481
|
)
|
|
327
482
|
assert adminone.get_pcode("YEM", "Ad Dal", logname="test") == (
|
|
328
483
|
"YE30",
|
|
@@ -365,7 +520,6 @@ class TestAdminLevel:
|
|
|
365
520
|
"test - NGA: Matching (pcode length conversion) NG015 to Federal Capital Territory on map",
|
|
366
521
|
"test - UKR: Matching (substring) Chernihiv Oblast to Chernihivska on map",
|
|
367
522
|
"test - YEM: Matching (substring) Ad Dal to Ad Dali' on map",
|
|
368
|
-
"test - YEM: Matching (substring) Ad Dali to Ad Dali' on map",
|
|
369
523
|
"test - YEM: Matching (pcode length conversion) YE30 to Ad Dali' on map",
|
|
370
524
|
]
|
|
371
525
|
output = adminone.output_ignored()
|
|
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.1 → hdx_python_country-3.7.3}/tests/fixtures/global_pcode_lengths.csv
RENAMED
|
File without changes
|
{hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/fixtures/global_pcodes_adm_1_2.csv
RENAMED
|
File without changes
|
{hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/tests/fixtures/secondary_historic_rates.csv
RENAMED
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.7.1 → hdx_python_country-3.7.3}/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.1 → hdx_python_country-3.7.3}/tests/hdx/location/test_wfp_exchangerates.py
RENAMED
|
File without changes
|