hdx-python-country 3.7.0__tar.gz → 3.7.2__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 (37) hide show
  1. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/.config/pre-commit-config.yaml +5 -4
  2. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/.config/ruff.toml +0 -1
  3. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/PKG-INFO +2 -2
  4. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/documentation/.readthedocs.yaml +1 -0
  5. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/documentation/main.md +13 -4
  6. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/documentation/pydoc-markdown.yaml +3 -3
  7. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/pyproject.toml +1 -1
  8. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/requirements.txt +37 -35
  9. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/_version.py +2 -2
  10. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/adminlevel.py +116 -17
  11. hdx_python_country-3.7.2/tests/fixtures/adminlevelparent.yaml +25 -0
  12. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/hdx/location/test_adminlevel.py +144 -4
  13. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/.config/coveragerc +0 -0
  14. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/.config/pytest.ini +0 -0
  15. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/.github/workflows/publish.yaml +0 -0
  16. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/.github/workflows/run-python-tests.yaml +0 -0
  17. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/.gitignore +0 -0
  18. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/CONTRIBUTING.md +0 -0
  19. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/LICENSE +0 -0
  20. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/README.md +0 -0
  21. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv +0 -0
  22. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/__init__.py +0 -0
  23. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/country.py +0 -0
  24. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/currency.py +0 -0
  25. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/names.py +0 -0
  26. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/phonetics.py +0 -0
  27. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/src/hdx/location/wfp_exchangerates.py +0 -0
  28. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/fixtures/adminlevel.yaml +0 -0
  29. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/fixtures/global_pcode_lengths.csv +0 -0
  30. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/fixtures/global_pcodes_adm_1_2.csv +0 -0
  31. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/fixtures/secondary_historic_rates.csv +0 -0
  32. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/fixtures/secondary_rates.json +0 -0
  33. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
  34. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/hdx/location/__init__.py +0 -0
  35. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/hdx/location/test_country.py +0 -0
  36. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/hdx/location/test_currency.py +0 -0
  37. {hdx_python_country-3.7.0 → hdx_python_country-3.7.2}/tests/hdx/location/test_wfp_exchangerates.py +0 -0
@@ -8,7 +8,7 @@ repos:
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.3.2
11
+ rev: v0.4.4
12
12
  hooks:
13
13
  # Run the linter.
14
14
  - id: ruff
@@ -16,10 +16,11 @@ repos:
16
16
  # Run the formatter.
17
17
  - id: ruff-format
18
18
  args: [--config, .config/ruff.toml]
19
- - repo: https://github.com/jazzband/pip-tools
20
- rev: 7.4.1
19
+ - repo: https://github.com/astral-sh/uv-pre-commit
20
+ rev: 0.1.45
21
21
  hooks:
22
+ # Run the pip compile
22
23
  - id: pip-compile
23
24
  name: pip-compile requirements.txt
24
25
  files: pyproject.toml
25
- args: [pyproject.toml, --resolver=backtracking, --all-extras, --upgrade, -q, -o, requirements.txt]
26
+ args: [ pyproject.toml, --resolver=backtracking, --all-extras, --upgrade, -q, -o, requirements.txt ]
@@ -12,6 +12,5 @@ ignore = [
12
12
  "E501" # Line too long
13
13
  ]
14
14
 
15
-
16
15
  [lint.isort]
17
16
  known-local-folder = ["hdx"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: hdx-python-country
3
- Version: 3.7.0
3
+ Version: 3.7.2
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.6.7
28
+ Requires-Dist: hdx-python-utilities>=3.6.8
29
29
  Requires-Dist: libhxl>=5.2.1
30
30
  Requires-Dist: pyphonetics
31
31
  Provides-Extra: dev
@@ -11,5 +11,6 @@ build:
11
11
  jobs:
12
12
  pre_build:
13
13
  - pip install --upgrade mkdocs
14
+ - pip install mkdocs-material
14
15
  - pip install pydoc-markdown
15
16
  - pydoc-markdown documentation/pydoc-markdown.yaml
@@ -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 matching. Default is all countries.
117
- *admin_name_mappings* is a dictionary of mappings from name to pcode (for where fuzzy matching fails)
118
- *admin_name_replacements* is a dictionary of textual replacements to try when fuzzy matching
119
- *admin_fuzzy_dont* is a list of names for which fuzzy matching should not be tried
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
@@ -9,7 +9,7 @@ renderer:
9
9
  output_directory: docs
10
10
  mkdocs_config:
11
11
  site_name: HDX Python Country
12
- theme: mkdocs
12
+ theme: material
13
13
  repo_url: "https://github.com/OCHA-DAP/hdx-python-country"
14
14
  markdown:
15
15
  source_linker:
@@ -24,9 +24,9 @@ renderer:
24
24
  - title: Countries
25
25
  contents:
26
26
  - hdx.location.country.*
27
- - title: Administration level one
27
+ - title: Administration Level
28
28
  contents:
29
- - hdx.location.adminone.*
29
+ - hdx.location.adminlevel.*
30
30
  - title: Currencies
31
31
  contents:
32
32
  - hdx.location.currency.*
@@ -34,7 +34,7 @@ classifiers = [
34
34
  requires-python = ">=3.8"
35
35
 
36
36
  dependencies = [
37
- "hdx-python-utilities>=3.6.7",
37
+ "hdx-python-utilities>=3.6.8",
38
38
  "libhxl>=5.2.1",
39
39
  "pyphonetics",
40
40
  ]
@@ -1,16 +1,13 @@
1
- #
2
- # This file is autogenerated by pip-compile with Python 3.11
3
- # by the following command:
4
- #
5
- # pip-compile --all-extras --output-file=requirements.txt pyproject.toml
6
- #
7
- annotated-types==0.6.0
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv pip compile pyproject.toml --resolver=backtracking --all-extras -o requirements.txt
3
+ annotated-types==0.7.0
8
4
  # via pydantic
9
5
  attrs==23.2.0
10
6
  # via
11
7
  # frictionless
12
8
  # jsonlines
13
9
  # jsonschema
10
+ # referencing
14
11
  certifi==2024.2.2
15
12
  # via requests
16
13
  cfgv==3.4.0
@@ -21,25 +18,23 @@ charset-normalizer==3.3.2
21
18
  # via requests
22
19
  click==8.1.7
23
20
  # via typer
24
- colorama==0.4.6
25
- # via typer
26
- coverage[toml]==7.4.4
21
+ coverage==7.5.1
27
22
  # via pytest-cov
28
23
  distlib==0.3.8
29
24
  # via virtualenv
30
25
  et-xmlfile==1.1.0
31
26
  # via openpyxl
32
- filelock==3.13.3
27
+ filelock==3.14.0
33
28
  # via virtualenv
34
- frictionless==5.16.1
29
+ frictionless==5.17.0
35
30
  # via hdx-python-utilities
36
- hdx-python-utilities==3.6.7
31
+ hdx-python-utilities==3.6.8
37
32
  # via hdx-python-country (pyproject.toml)
38
33
  humanize==4.9.0
39
34
  # via frictionless
40
- identify==2.5.35
35
+ identify==2.5.36
41
36
  # via pre-commit
42
- idna==3.6
37
+ idna==3.7
43
38
  # via requests
44
39
  ijson==3.2.3
45
40
  # via hdx-python-utilities
@@ -47,16 +42,18 @@ iniconfig==2.0.0
47
42
  # via pytest
48
43
  isodate==0.6.1
49
44
  # via frictionless
50
- jinja2==3.1.3
45
+ jinja2==3.1.4
51
46
  # via frictionless
52
47
  jsonlines==4.0.0
53
48
  # via hdx-python-utilities
54
49
  jsonpath-ng==1.6.1
55
50
  # via libhxl
56
- jsonschema==4.17.3
51
+ jsonschema==4.22.0
57
52
  # via
58
53
  # frictionless
59
54
  # tableschema-to-template
55
+ jsonschema-specifications==2023.12.1
56
+ # via jsonschema
60
57
  libhxl==5.2.1
61
58
  # via hdx-python-country (pyproject.toml)
62
59
  loguru==0.7.2
@@ -77,27 +74,25 @@ packaging==24.0
77
74
  # via pytest
78
75
  petl==1.7.15
79
76
  # via frictionless
80
- platformdirs==4.2.0
77
+ platformdirs==4.2.2
81
78
  # via virtualenv
82
- pluggy==1.4.0
79
+ pluggy==1.5.0
83
80
  # via pytest
84
81
  ply==3.11
85
82
  # via
86
83
  # jsonpath-ng
87
84
  # libhxl
88
- pre-commit==3.7.0
85
+ pre-commit==3.7.1
89
86
  # via hdx-python-country (pyproject.toml)
90
- pydantic==2.6.4
87
+ pydantic==2.7.1
91
88
  # via frictionless
92
- pydantic-core==2.16.3
89
+ pydantic-core==2.18.2
93
90
  # via pydantic
94
- pygments==2.17.2
91
+ pygments==2.18.0
95
92
  # via rich
96
93
  pyphonetics==0.5.3
97
94
  # via hdx-python-country (pyproject.toml)
98
- pyrsistent==0.20.0
99
- # via jsonschema
100
- pytest==8.1.1
95
+ pytest==8.2.1
101
96
  # via
102
97
  # hdx-python-country (pyproject.toml)
103
98
  # pytest-cov
@@ -119,21 +114,31 @@ pyyaml==6.0.1
119
114
  # tableschema-to-template
120
115
  ratelimit==2.2.1
121
116
  # via hdx-python-utilities
122
- requests==2.31.0
117
+ referencing==0.35.1
118
+ # via
119
+ # jsonschema
120
+ # jsonschema-specifications
121
+ requests==2.32.2
123
122
  # via
124
123
  # frictionless
125
124
  # libhxl
126
125
  # requests-file
127
- requests-file==2.0.0
126
+ requests-file==2.1.0
128
127
  # via hdx-python-utilities
129
128
  rfc3986==2.0.0
130
129
  # via frictionless
131
130
  rich==13.7.1
132
131
  # via typer
132
+ rpds-py==0.18.1
133
+ # via
134
+ # jsonschema
135
+ # referencing
133
136
  ruamel-yaml==0.18.6
134
137
  # via hdx-python-utilities
135
138
  ruamel-yaml-clib==0.2.8
136
139
  # via ruamel-yaml
140
+ setuptools==70.0.0
141
+ # via nodeenv
137
142
  shellingham==1.5.4
138
143
  # via typer
139
144
  simpleeval==0.9.13
@@ -152,9 +157,9 @@ tabulate==0.9.0
152
157
  # via frictionless
153
158
  text-unidecode==1.3
154
159
  # via python-slugify
155
- typer[all]==0.10.0
160
+ typer==0.12.3
156
161
  # via frictionless
157
- typing-extensions==4.10.0
162
+ typing-extensions==4.11.0
158
163
  # via
159
164
  # frictionless
160
165
  # pydantic
@@ -168,9 +173,9 @@ urllib3==2.2.1
168
173
  # via
169
174
  # libhxl
170
175
  # requests
171
- validators==0.24.0
176
+ validators==0.28.1
172
177
  # via frictionless
173
- virtualenv==20.25.1
178
+ virtualenv==20.26.2
174
179
  # via pre-commit
175
180
  wheel==0.43.0
176
181
  # via libhxl
@@ -182,6 +187,3 @@ xlsxwriter==3.2.0
182
187
  # via tableschema-to-template
183
188
  xlwt==1.3.0
184
189
  # via hdx-python-utilities
185
-
186
- # The following packages are considered to be unsafe in a requirements file:
187
- # setuptools
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '3.7.0'
16
- __version_tuple__ = version_tuple = (3, 7, 0)
15
+ __version__ = version = '3.7.2'
16
+ __version_tuple__ = version_tuple = (3, 7, 2)
@@ -306,7 +306,7 @@ class AdminLevel:
306
306
  """Get admin level for country
307
307
 
308
308
  Args:
309
- countryiso3 (str): Iso3 country code
309
+ countryiso3 (str): ISO3 country code
310
310
 
311
311
  Returns:
312
312
  int: Admin level
@@ -320,7 +320,7 @@ class AdminLevel:
320
320
  """Get pcode length for country
321
321
 
322
322
  Args:
323
- countryiso3 (str): Iso3 country code
323
+ countryiso3 (str): ISO3 country code
324
324
 
325
325
  Returns:
326
326
  Optional[int]: Country's pcode length or None
@@ -517,6 +517,41 @@ class AdminLevel:
517
517
  return pcode
518
518
  return None
519
519
 
520
+ def get_admin_name_replacements(
521
+ self, countryiso3: str, parent: Optional[str]
522
+ ) -> Dict[str, str]:
523
+ """Get relevant admin name replacements from admin name replacements
524
+ which is a dictionary of mappings from string to string replacement.
525
+ These can be global or they can be restricted by
526
+ country or parent (if the AdminLevel object has been set up with
527
+ parents). Keys take the form "STRING_TO_REPLACE",
528
+ "AFG|STRING_TO_REPLACE" or "AF01|STRING_TO_REPLACE".
529
+
530
+ Args:
531
+ countryiso3 (str): ISO3 country code
532
+ parent (Optional[str]): Parent admin code
533
+
534
+ Returns:
535
+ Dict[str, str]: Relevant admin name replacements
536
+ """
537
+ relevant_name_replacements = {}
538
+ for key, value in self.admin_name_replacements.items():
539
+ if "|" not in key:
540
+ if key not in relevant_name_replacements:
541
+ relevant_name_replacements[key] = value
542
+ continue
543
+ prefix, name = key.split("|")
544
+ if parent:
545
+ if prefix == parent:
546
+ if name not in relevant_name_replacements:
547
+ relevant_name_replacements[name] = value
548
+ continue
549
+ if prefix == countryiso3:
550
+ if name not in relevant_name_replacements:
551
+ relevant_name_replacements[name] = value
552
+ continue
553
+ return relevant_name_replacements
554
+
520
555
  def fuzzy_pcode(
521
556
  self,
522
557
  countryiso3: str,
@@ -526,7 +561,7 @@ class AdminLevel:
526
561
  """Fuzzy match name to pcode
527
562
 
528
563
  Args:
529
- countryiso3 (str): Iso3 country code
564
+ countryiso3 (str): ISO3 country code
530
565
  name (str): Name to match
531
566
  **kwargs:
532
567
  parent (Optional[str]): Parent admin code
@@ -543,8 +578,17 @@ class AdminLevel:
543
578
  if logname:
544
579
  self.ignored.add((logname, countryiso3))
545
580
  return None
546
- if self.use_parent and "parent" in kwargs:
547
- parent = kwargs["parent"]
581
+ if self.use_parent:
582
+ parent = kwargs.get("parent")
583
+ else:
584
+ parent = None
585
+ if parent is None:
586
+ name_to_pcode = self.name_to_pcode.get(countryiso3)
587
+ if not name_to_pcode:
588
+ if logname:
589
+ self.errors.add((logname, countryiso3))
590
+ return None
591
+ else:
548
592
  name_parent_to_pcode = self.name_parent_to_pcode.get(countryiso3)
549
593
  if not name_parent_to_pcode:
550
594
  if logname:
@@ -555,15 +599,10 @@ class AdminLevel:
555
599
  if logname:
556
600
  self.errors.add((logname, countryiso3, parent))
557
601
  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
602
  adm_name_lookup = clean_name(name)
565
603
  adm_name_lookup2 = multiple_replace(
566
- adm_name_lookup, self.admin_name_replacements
604
+ adm_name_lookup,
605
+ self.get_admin_name_replacements(countryiso3, parent),
567
606
  )
568
607
  pcode = name_to_pcode.get(
569
608
  adm_name_lookup, name_to_pcode.get(adm_name_lookup2)
@@ -643,6 +682,33 @@ class AdminLevel:
643
682
  )
644
683
  return pcode
645
684
 
685
+ def get_name_mapped_pcode(
686
+ self, countryiso3: str, name: str, parent: Optional[str]
687
+ ) -> Optional[str]:
688
+ """Get pcode from admin name mappings which is a dictionary of mappings
689
+ from name to pcode. These can be global or they can be restricted by
690
+ country or parent (if the AdminLevel object has been set up with
691
+ parents). Keys take the form "MAPPING", "AFG|MAPPING" or
692
+ "AF01|MAPPING".
693
+
694
+ Args:
695
+ countryiso3 (str): ISO3 country code
696
+ name (str): Name to match
697
+ parent (Optional[str]): Parent admin code
698
+
699
+ Returns:
700
+ Optional[str]: P code match from admin name mappings or None if no match
701
+ """
702
+ if parent:
703
+ pcode = self.admin_name_mappings.get(f"{parent}|{name}")
704
+ if pcode is None:
705
+ pcode = self.admin_name_mappings.get(f"{countryiso3}|{name}")
706
+ else:
707
+ pcode = self.admin_name_mappings.get(f"{countryiso3}|{name}")
708
+ if pcode is None:
709
+ pcode = self.admin_name_mappings.get(name)
710
+ return pcode
711
+
646
712
  def get_pcode(
647
713
  self,
648
714
  countryiso3: str,
@@ -653,7 +719,7 @@ class AdminLevel:
653
719
  """Get pcode for a given name
654
720
 
655
721
  Args:
656
- countryiso3 (str): Iso3 country code
722
+ countryiso3 (str): ISO3 country code
657
723
  name (str): Name to match
658
724
  fuzzy_match (bool): Whether to try fuzzy matching. Defaults to True.
659
725
  **kwargs:
@@ -663,9 +729,17 @@ class AdminLevel:
663
729
  Returns:
664
730
  Tuple[Optional[str], bool]: (Matched P code or None if no match, True if exact match or False if not)
665
731
  """
666
- pcode = self.admin_name_mappings.get(name)
732
+ if self.use_parent:
733
+ parent = kwargs.get("parent")
734
+ else:
735
+ parent = None
736
+ pcode = self.get_name_mapped_pcode(countryiso3, name, parent)
667
737
  if pcode and self.pcode_to_iso3[pcode] == countryiso3:
668
- return pcode, True
738
+ if parent:
739
+ if self.pcode_to_parent[pcode] == parent:
740
+ return pcode, True
741
+ else:
742
+ return pcode, True
669
743
  if self.looks_like_pcode(name):
670
744
  pcode = name.upper()
671
745
  if pcode in self.pcodes: # name is a p-code
@@ -677,8 +751,7 @@ class AdminLevel:
677
751
  )
678
752
  return pcode, True
679
753
  else:
680
- if self.use_parent and "parent" in kwargs:
681
- parent = kwargs["parent"]
754
+ if parent:
682
755
  name_parent_to_pcode = self.name_parent_to_pcode.get(
683
756
  countryiso3
684
757
  )
@@ -743,3 +816,29 @@ class AdminLevel:
743
816
  logger.error(line)
744
817
  output.append(line)
745
818
  return output
819
+
820
+ def output_admin_name_mappings(self) -> List[str]:
821
+ """Output log of name mappings
822
+
823
+ Returns:
824
+ List[str]: List of mappings
825
+ """
826
+ output = []
827
+ for name, pcode in self.admin_name_mappings.items():
828
+ line = f"{name}: {self.pcode_to_name[pcode]} ({pcode})"
829
+ logger.info(line)
830
+ output.append(line)
831
+ return output
832
+
833
+ def output_admin_name_replacements(self) -> List[str]:
834
+ """Output log of name replacements
835
+
836
+ Returns:
837
+ List[str]: List of name replacements
838
+ """
839
+ output = []
840
+ for name, replacement in self.admin_name_replacements.items():
841
+ line = f"{name}: {replacement}"
842
+ logger.info(line)
843
+ output.append(line)
844
+ return output
@@ -0,0 +1,25 @@
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
+ " city": ""
20
+
21
+ alt1_admin_name_replacements:
22
+ "COD| city": ""
23
+
24
+ alt2_admin_name_replacements:
25
+ "CD20| city": ""
@@ -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"
@@ -155,6 +159,25 @@ class TestAdminLevel:
155
159
  "test - Could not find ABC in map names!",
156
160
  "test - NER: Could not find ABCDEFGH in map names!",
157
161
  ]
162
+ output = adminone.output_admin_name_mappings()
163
+ assert len(output) == 62
164
+ assert output[0] == "Nord-Ouest: North West (HT09)"
165
+ assert output[31] == "Juba Dhexe: Middle Juba (SO27)"
166
+ assert output[61] == "CU Niamey: Niamey (NER008)"
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
+ ]
158
181
 
159
182
  def test_adminlevel_fuzzy(self, config):
160
183
  adminone = AdminLevel(config)
@@ -179,10 +202,10 @@ class TestAdminLevel:
179
202
  "test - YEM: Matching (fuzzy) Al Dhale'e / الضالع to Ad Dali on map",
180
203
  ]
181
204
 
182
- def test_adminlevel_parent(self, config):
183
- admintwo = AdminLevel(config)
205
+ def test_adminlevel_parent(self, config_parent):
206
+ admintwo = AdminLevel(config_parent)
184
207
  admintwo.countries_fuzzy_try = None
185
- admintwo.setup_from_admin_info(config["admin_info_with_parent"])
208
+ admintwo.setup_from_admin_info(config_parent["admin_info_with_parent"])
186
209
  assert admintwo.use_parent is True
187
210
  assert admintwo.pcode_to_parent["AF0101"] == "AF01"
188
211
  assert admintwo.get_pcode("AFG", "AF0101", logname="test") == (
@@ -218,6 +241,123 @@ class TestAdminLevel:
218
241
  "ABC", "Kabull", parent="AF02", logname="test"
219
242
  ) == (None, False)
220
243
 
244
+ output = admintwo.output_admin_name_mappings()
245
+ assert output == [
246
+ "MyMapping: Charikar (AF0301)",
247
+ "AFG|MyMapping2: Maydan Shahr (AF0401)",
248
+ "AF05|MyMapping3: Pul-e-Alam (AF0501)",
249
+ ]
250
+ assert admintwo.get_pcode("AFG", "MyMapping", logname="test") == (
251
+ "AF0301",
252
+ True,
253
+ )
254
+ assert admintwo.get_pcode(
255
+ "AFG", "MyMapping", parent="AF03", logname="test"
256
+ ) == ("AF0301", True)
257
+ assert admintwo.get_pcode(
258
+ "AFG", "MyMapping", parent="AF04", logname="test"
259
+ ) == (None, False)
260
+
261
+ assert admintwo.get_pcode("AFG", "MyMapping2", logname="test") == (
262
+ "AF0401",
263
+ True,
264
+ )
265
+ assert admintwo.get_pcode(
266
+ "AFG", "MyMapping2", parent="AF04", logname="test"
267
+ ) == ("AF0401", True)
268
+ assert admintwo.get_pcode(
269
+ "AFG", "MyMapping2", parent="AF05", logname="test"
270
+ ) == (None, False)
271
+
272
+ assert admintwo.get_pcode("AFG", "MyMapping3", logname="test") == (
273
+ None,
274
+ False,
275
+ )
276
+ assert admintwo.get_pcode(
277
+ "AFG", "MyMapping3", parent="AF05", logname="test"
278
+ ) == ("AF0501", True)
279
+ assert admintwo.get_pcode(
280
+ "AFG", "MyMapping3", parent="AF04", logname="test"
281
+ ) == (None, False)
282
+
283
+ output = admintwo.output_admin_name_replacements()
284
+ assert output == [" city: "]
285
+ assert admintwo.get_pcode(
286
+ "COD", "Mbanza-Ngungu city", logname="test"
287
+ ) == ("CD2013", False)
288
+ assert admintwo.get_pcode(
289
+ "COD", "Mbanza-Ngungu city", parent="CD20", logname="test"
290
+ ) == ("CD2013", False)
291
+ assert admintwo.get_pcode(
292
+ "COD", "Mbanza-Ngungu city", parent="CD19", logname="test"
293
+ ) == (None, False)
294
+ assert admintwo.get_pcode("COD", "Kenge city", logname="test") == (
295
+ "CD3102",
296
+ False,
297
+ )
298
+ assert admintwo.get_pcode("MWI", "Blantyre city", logname="test") == (
299
+ "MW305",
300
+ False,
301
+ )
302
+
303
+ admintwo.admin_name_replacements = config_parent[
304
+ "alt1_admin_name_replacements"
305
+ ]
306
+ output = admintwo.output_admin_name_replacements()
307
+ assert output == ["COD| city: "]
308
+ assert admintwo.get_pcode(
309
+ "COD", "Mbanza-Ngungu city", logname="test"
310
+ ) == ("CD2013", False)
311
+ assert admintwo.get_pcode(
312
+ "COD", "Mbanza-Ngungu city", parent="CD20", logname="test"
313
+ ) == ("CD2013", False)
314
+ assert admintwo.get_pcode(
315
+ "COD", "Mbanza-Ngungu city", parent="CD19", logname="test"
316
+ ) == (None, False)
317
+ assert admintwo.get_pcode("COD", "Kenge city", logname="test") == (
318
+ "CD3102",
319
+ False,
320
+ )
321
+ assert admintwo.get_pcode(
322
+ "COD", "Kenge city", parent="CD31", logname="test"
323
+ ) == ("CD3102", False)
324
+ assert admintwo.get_pcode("MWI", "Blantyre city", logname="test") == (
325
+ None,
326
+ False,
327
+ )
328
+ assert admintwo.get_pcode(
329
+ "MWI", "Blantyre city", parent="MW3", logname="test"
330
+ ) == (None, False)
331
+
332
+ admintwo.admin_name_replacements = config_parent[
333
+ "alt2_admin_name_replacements"
334
+ ]
335
+ output = admintwo.output_admin_name_replacements()
336
+ assert output == ["CD20| city: "]
337
+ assert admintwo.get_pcode(
338
+ "COD", "Mbanza-Ngungu city", logname="test"
339
+ ) == (None, False)
340
+ assert admintwo.get_pcode(
341
+ "COD", "Mbanza-Ngungu city", parent="CD20", logname="test"
342
+ ) == ("CD2013", False)
343
+ assert admintwo.get_pcode(
344
+ "COD", "Mbanza-Ngungu city", parent="CD19", logname="test"
345
+ ) == (None, False)
346
+ assert admintwo.get_pcode("COD", "Kenge city", logname="test") == (
347
+ None,
348
+ False,
349
+ )
350
+ assert admintwo.get_pcode(
351
+ "COD", "Kenge city", parent="CD31", logname="test"
352
+ ) == (None, False)
353
+ assert admintwo.get_pcode("MWI", "Blantyre city", logname="test") == (
354
+ None,
355
+ False,
356
+ )
357
+ assert admintwo.get_pcode(
358
+ "MWI", "Blantyre city", parent="MW3", logname="test"
359
+ ) == (None, False)
360
+
221
361
  def test_adminlevel_with_url(self, config, url):
222
362
  adminone = AdminLevel(config)
223
363
  with pytest.raises(HXLIOException):
@@ -231,7 +371,7 @@ class TestAdminLevel:
231
371
  adminone = AdminLevel(config)
232
372
  adminone.setup_from_url()
233
373
  assert adminone.get_admin_level("YEM") == 1
234
- assert len(adminone.get_pcode_list()) == 2506
374
+ assert len(adminone.get_pcode_list()) == 2509
235
375
  assert adminone.get_pcode_length("YEM") == 4
236
376
  assert adminone.get_pcode("YEM", "YE30", logname="test") == (
237
377
  "YE30",