hdx-python-country 3.8.1__tar.gz → 3.8.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.
Files changed (51) hide show
  1. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/.config/pre-commit-config.yaml +3 -3
  2. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/PKG-INFO +3 -2
  3. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/pyproject.toml +5 -5
  4. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/requirements.txt +20 -18
  5. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/src/hdx/location/_version.py +2 -2
  6. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/src/hdx/location/adminlevel.py +35 -1
  7. hdx_python_country-3.8.3/src/hdx/location/wfp_api.py +157 -0
  8. hdx_python_country-3.8.3/src/hdx/location/wfp_exchangerates.py +73 -0
  9. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/fixtures/adminlevel.yaml +1 -1
  10. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_List_1.json +1 -0
  11. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_List_2.json +1 -0
  12. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_1.json +1 -0
  13. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_10.json +1 -0
  14. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_2.json +1 -0
  15. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_3.json +1 -0
  16. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_4.json +1 -0
  17. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_5.json +1 -0
  18. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_6.json +1 -0
  19. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_7.json +1 -0
  20. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_8.json +1 -0
  21. hdx_python_country-3.8.3/tests/fixtures/wfp/Currency_UsdIndirectQuotation_9.json +1 -0
  22. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/hdx/location/test_adminlevel.py +1 -1
  23. hdx_python_country-3.8.3/tests/hdx/location/test_wfp_exchangerates.py +66 -0
  24. hdx_python_country-3.8.1/src/hdx/location/wfp_exchangerates.py +0 -101
  25. hdx_python_country-3.8.1/tests/hdx/location/test_wfp_exchangerates.py +0 -42
  26. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/.config/coveragerc +0 -0
  27. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/.config/pytest.ini +0 -0
  28. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/.config/ruff.toml +0 -0
  29. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/.github/workflows/publish.yaml +0 -0
  30. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/.github/workflows/run-python-tests.yaml +0 -0
  31. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/.gitignore +0 -0
  32. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/CONTRIBUTING.md +0 -0
  33. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/LICENSE +0 -0
  34. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/README.md +0 -0
  35. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/documentation/.readthedocs.yaml +0 -0
  36. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/documentation/main.md +0 -0
  37. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/documentation/pydoc-markdown.yaml +0 -0
  38. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/src/hdx/location/Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv +0 -0
  39. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/src/hdx/location/__init__.py +0 -0
  40. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/src/hdx/location/country.py +0 -0
  41. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/src/hdx/location/currency.py +0 -0
  42. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/src/hdx/location/phonetics.py +0 -0
  43. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/fixtures/adminlevelparent.yaml +0 -0
  44. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/fixtures/download-global-pcode-lengths.csv +0 -0
  45. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/fixtures/download-global-pcodes-adm-1-2.csv +0 -0
  46. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/fixtures/secondary_historic_rates.csv +0 -0
  47. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/fixtures/secondary_rates.json +0 -0
  48. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
  49. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/hdx/location/__init__.py +0 -0
  50. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/hdx/location/test_country.py +0 -0
  51. {hdx_python_country-3.8.1 → hdx_python_country-3.8.3}/tests/hdx/location/test_currency.py +0 -0
@@ -2,13 +2,13 @@ default_language_version:
2
2
  python: python3.12
3
3
  repos:
4
4
  - repo: https://github.com/pre-commit/pre-commit-hooks
5
- rev: v4.6.0
5
+ rev: v5.0.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.6.4
11
+ rev: v0.7.0
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.4.5
20
+ rev: 0.4.24
21
21
  hooks:
22
22
  # Run the pip compile
23
23
  - id: pip-compile
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: hdx-python-country
3
- Version: 3.8.1
3
+ Version: 3.8.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
@@ -26,8 +26,9 @@ Classifier: Programming Language :: Python :: 3.12
26
26
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
27
  Requires-Python: >=3.8
28
28
  Requires-Dist: hdx-python-utilities>=3.7.4
29
- Requires-Dist: libhxl>=5.2.1
29
+ Requires-Dist: libhxl>=5.2.2
30
30
  Requires-Dist: pyphonetics
31
+ Requires-Dist: tenacity
31
32
  Provides-Extra: dev
32
33
  Requires-Dist: pre-commit; extra == 'dev'
33
34
  Provides-Extra: test
@@ -35,8 +35,9 @@ requires-python = ">=3.8"
35
35
 
36
36
  dependencies = [
37
37
  "hdx-python-utilities>=3.7.4",
38
- "libhxl>=5.2.1",
38
+ "libhxl>=5.2.2",
39
39
  "pyphonetics",
40
+ "tenacity",
40
41
  ]
41
42
  dynamic = ["version"]
42
43
 
@@ -50,16 +51,12 @@ Homepage = "https://github.com/OCHA-DAP/hdx-python-country"
50
51
  [project.optional-dependencies]
51
52
  test = ["pytest", "pytest-cov"]
52
53
  dev = ["pre-commit"]
53
- #wfp = ["data-bridges-client@git+https://github.com/WFP-VAM/DataBridgesAPI@dev#egg=data-bridges-client"]
54
54
 
55
55
 
56
56
  #########
57
57
  # Hatch #
58
58
  #########
59
59
 
60
- #[tool.hatch.metadata]
61
- #allow-direct-references = true
62
-
63
60
  # Build
64
61
 
65
62
  [tool.hatch.build.targets.wheel]
@@ -92,6 +89,9 @@ run = """
92
89
  --cov-report=lcov --cov-report=term-missing
93
90
  """
94
91
 
92
+ [tool.hatch.envs.hatch-static-analysis]
93
+ dependencies = ["ruff==0.7.0"]
94
+
95
95
  [tool.hatch.envs.hatch-static-analysis.scripts]
96
96
  format-check = ["ruff format --config .config/ruff.toml --check --diff {args:.}",]
97
97
  format-fix = ["ruff format --config .config/ruff.toml {args:.}",]
@@ -14,15 +14,15 @@ cfgv==3.4.0
14
14
  # via pre-commit
15
15
  chardet==5.2.0
16
16
  # via frictionless
17
- charset-normalizer==3.3.2
17
+ charset-normalizer==3.4.0
18
18
  # via requests
19
19
  click==8.1.7
20
20
  # via typer
21
- coverage==7.6.1
21
+ coverage==7.6.4
22
22
  # via pytest-cov
23
- distlib==0.3.8
23
+ distlib==0.3.9
24
24
  # via virtualenv
25
- et-xmlfile==1.1.0
25
+ et-xmlfile==2.0.0
26
26
  # via openpyxl
27
27
  filelock==3.16.1
28
28
  # via virtualenv
@@ -40,21 +40,21 @@ ijson==3.3.0
40
40
  # via hdx-python-utilities
41
41
  iniconfig==2.0.0
42
42
  # via pytest
43
- isodate==0.6.1
43
+ isodate==0.7.2
44
44
  # via frictionless
45
45
  jinja2==3.1.4
46
46
  # via frictionless
47
47
  jsonlines==4.0.0
48
48
  # via hdx-python-utilities
49
- jsonpath-ng==1.6.1
49
+ jsonpath-ng==1.7.0
50
50
  # via libhxl
51
51
  jsonschema==4.23.0
52
52
  # via
53
53
  # frictionless
54
54
  # tableschema-to-template
55
- jsonschema-specifications==2023.12.1
55
+ jsonschema-specifications==2024.10.1
56
56
  # via jsonschema
57
- libhxl==5.2.1
57
+ libhxl==5.2.2
58
58
  # via hdx-python-country (pyproject.toml)
59
59
  loguru==0.7.2
60
60
  # via hdx-python-utilities
@@ -62,7 +62,7 @@ markdown-it-py==3.0.0
62
62
  # via rich
63
63
  marko==2.1.2
64
64
  # via frictionless
65
- markupsafe==2.1.5
65
+ markupsafe==3.0.2
66
66
  # via jinja2
67
67
  mdurl==0.1.2
68
68
  # via markdown-it-py
@@ -74,6 +74,8 @@ packaging==24.1
74
74
  # via pytest
75
75
  petl==1.7.15
76
76
  # via frictionless
77
+ pip==24.3.1
78
+ # via simpleeval
77
79
  platformdirs==4.3.6
78
80
  # via virtualenv
79
81
  pluggy==1.5.0
@@ -82,7 +84,7 @@ ply==3.11
82
84
  # via
83
85
  # jsonpath-ng
84
86
  # libhxl
85
- pre-commit==4.0.0
87
+ pre-commit==4.0.1
86
88
  # via hdx-python-country (pyproject.toml)
87
89
  pydantic==2.9.2
88
90
  # via frictionless
@@ -96,7 +98,7 @@ pytest==8.3.3
96
98
  # via
97
99
  # hdx-python-country (pyproject.toml)
98
100
  # pytest-cov
99
- pytest-cov==5.0.0
101
+ pytest-cov==6.0.0
100
102
  # via hdx-python-country (pyproject.toml)
101
103
  python-dateutil==2.9.0.post0
102
104
  # via
@@ -127,7 +129,7 @@ requests-file==2.1.0
127
129
  # via hdx-python-utilities
128
130
  rfc3986==2.0.0
129
131
  # via frictionless
130
- rich==13.9.2
132
+ rich==13.9.3
131
133
  # via typer
132
134
  rpds-py==0.20.0
133
135
  # via
@@ -135,16 +137,14 @@ rpds-py==0.20.0
135
137
  # referencing
136
138
  ruamel-yaml==0.18.6
137
139
  # via hdx-python-utilities
138
- ruamel-yaml-clib==0.2.8
140
+ ruamel-yaml-clib==0.2.12
139
141
  # via ruamel-yaml
140
142
  shellingham==1.5.4
141
143
  # via typer
142
- simpleeval==1.0.0
144
+ simpleeval==1.0.1
143
145
  # via frictionless
144
146
  six==1.16.0
145
- # via
146
- # isodate
147
- # python-dateutil
147
+ # via python-dateutil
148
148
  stringcase==1.2.0
149
149
  # via frictionless
150
150
  structlog==24.4.0
@@ -153,6 +153,8 @@ tableschema-to-template==0.0.13
153
153
  # via hdx-python-utilities
154
154
  tabulate==0.9.0
155
155
  # via frictionless
156
+ tenacity==9.0.0
157
+ # via hdx-python-country (pyproject.toml)
156
158
  text-unidecode==1.3
157
159
  # via python-slugify
158
160
  typer==0.12.5
@@ -173,7 +175,7 @@ urllib3==2.2.3
173
175
  # requests
174
176
  validators==0.34.0
175
177
  # via frictionless
176
- virtualenv==20.26.6
178
+ virtualenv==20.27.1
177
179
  # via pre-commit
178
180
  wheel==0.44.0
179
181
  # via libhxl
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '3.8.1'
16
- __version_tuple__ = version_tuple = (3, 8, 1)
15
+ __version__ = version = '3.8.3'
16
+ __version_tuple__ = version_tuple = (3, 8, 3)
@@ -602,6 +602,38 @@ class AdminLevel:
602
602
  continue
603
603
  return relevant_name_replacements
604
604
 
605
+ def get_admin_fuzzy_dont(
606
+ self, countryiso3: str, parent: Optional[str]
607
+ ) -> List[str]:
608
+ """Get relevant admin names that should not be fuzzy matched from
609
+ admin fuzzy dont which is a list of strings. These can be global
610
+ or they can be restricted by country or parent. Keys take the form
611
+ "DONT_MATCH", "AFG|DONT_MATCH", or "AF01|DONT_MATCH".
612
+
613
+ Args:
614
+ countryiso3 (str): ISO3 country code
615
+ parent (Optional[str]): Parent admin code
616
+
617
+ Returns:
618
+ List[str]: Relevant admin names that should not be fuzzy matched
619
+ """
620
+ relevant_admin_fuzzy_dont = []
621
+ for value in self.admin_fuzzy_dont:
622
+ if "|" not in value:
623
+ if value not in relevant_admin_fuzzy_dont:
624
+ relevant_admin_fuzzy_dont.append(value)
625
+ continue
626
+ prefix, name = value.split("|")
627
+ if parent:
628
+ if prefix == parent:
629
+ if name not in relevant_admin_fuzzy_dont:
630
+ relevant_admin_fuzzy_dont.append(name)
631
+ if prefix == countryiso3:
632
+ if name not in relevant_admin_fuzzy_dont:
633
+ relevant_admin_fuzzy_dont.append(name)
634
+ continue
635
+ return relevant_admin_fuzzy_dont
636
+
605
637
  def fuzzy_pcode(
606
638
  self,
607
639
  countryiso3: str,
@@ -658,7 +690,9 @@ class AdminLevel:
658
690
  pcode = name_to_pcode.get(
659
691
  normalised_name, name_to_pcode.get(alt_normalised_name)
660
692
  )
661
- if not pcode and name.lower() in self.admin_fuzzy_dont:
693
+ if not pcode and name.lower() in self.get_admin_fuzzy_dont(
694
+ countryiso3, parent
695
+ ):
662
696
  if logname:
663
697
  self.ignored.add((logname, countryiso3, name))
664
698
  return None
@@ -0,0 +1,157 @@
1
+ import logging
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ from tenacity import (
5
+ Retrying,
6
+ after_log,
7
+ retry_if_exception_type,
8
+ stop_after_attempt,
9
+ wait_fixed,
10
+ )
11
+
12
+ from hdx.utilities.base_downloader import DownloadError
13
+ from hdx.utilities.downloader import Download
14
+ from hdx.utilities.retriever import Retrieve
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class WFPAPI:
20
+ """Light wrapper around WFP REST API. It needs a token_downloader that has
21
+ been configured with WFP basic authentication credentials and a retriever
22
+ that will configured by this class with the bearer token obtained from the
23
+ token_downloader.
24
+
25
+ Args:
26
+ token_downloader (Download): Download object with WFP basic authentication
27
+ retriever (Retrieve): Retrieve object for interacting with WFP API
28
+ """
29
+
30
+ token_url = "https://api.wfp.org/token"
31
+ base_url = "https://api.wfp.org/vam-data-bridges/5.0.0/"
32
+ scope = "vamdatabridges_commodities-list_get vamdatabridges_commodityunits-list_get vamdatabridges_marketprices-alps_get vamdatabridges_commodities-categories-list_get vamdatabridges_commodityunits-conversion-list_get vamdatabridges_marketprices-priceweekly_get vamdatabridges_markets-geojsonlist_get vamdatabridges_marketprices-pricemonthly_get vamdatabridges_markets-list_get vamdatabridges_currency-list_get vamdatabridges_currency-usdindirectquotation_get"
33
+ default_retry_params = {
34
+ "retry": retry_if_exception_type(DownloadError),
35
+ "after": after_log(logger, logging.INFO),
36
+ }
37
+
38
+ def __init__(
39
+ self,
40
+ token_downloader: Download,
41
+ retriever: Retrieve,
42
+ ):
43
+ self.token_downloader = token_downloader
44
+ self.retriever = retriever
45
+ self.retry_params = {"attempts": 1, "wait": 1}
46
+
47
+ def get_retry_params(self) -> Dict:
48
+ return self.retry_params
49
+
50
+ def update_retry_params(self, attempts: int, wait: int) -> Dict:
51
+ self.retry_params["attempts"] = attempts
52
+ self.retry_params["wait"] = wait
53
+ return self.retry_params
54
+
55
+ def refresh_token(self) -> None:
56
+ self.token_downloader.download(
57
+ self.token_url,
58
+ post=True,
59
+ parameters={
60
+ "grant_type": "client_credentials",
61
+ "scope": self.scope,
62
+ },
63
+ )
64
+ bearer_token = self.token_downloader.get_json()["access_token"]
65
+ self.retriever.downloader.set_bearer_token(bearer_token)
66
+
67
+ def retrieve(
68
+ self,
69
+ url: str,
70
+ filename: str,
71
+ log: str,
72
+ parameters: Optional[Dict] = None,
73
+ ) -> Any:
74
+ """Retrieve JSON from WFP API.
75
+
76
+ Args:
77
+ url (str): URL to download
78
+ filename (Optional[str]): Filename of saved file. Defaults to getting from url.
79
+ log (Optional[str]): Text to use in log string to describe download. Defaults to filename.
80
+ parameters (Dict): Parameters to pass to download_json call
81
+
82
+ Returns:
83
+ Any: The data from the JSON file
84
+ """
85
+ retryer = Retrying(
86
+ retry=self.default_retry_params["retry"],
87
+ after=self.default_retry_params["after"],
88
+ stop=stop_after_attempt(self.retry_params["attempts"]),
89
+ wait=wait_fixed(self.retry_params["wait"]),
90
+ )
91
+ for attempt in retryer:
92
+ with attempt:
93
+ try:
94
+ results = self.retriever.download_json(
95
+ url, filename, log, False, parameters=parameters
96
+ )
97
+ except DownloadError:
98
+ response = self.retriever.downloader.response
99
+ if response and response.status_code not in (
100
+ 104,
101
+ 401,
102
+ 403,
103
+ ):
104
+ raise
105
+ self.refresh_token()
106
+ results = self.retriever.download_json(
107
+ url, filename, log, False, parameters=parameters
108
+ )
109
+ return results
110
+
111
+ def get_items(
112
+ self,
113
+ endpoint: str,
114
+ countryiso3: Optional[str] = None,
115
+ parameters: Optional[Dict] = None,
116
+ ) -> List:
117
+ """Retrieve a list of items from the WFP API.
118
+
119
+ Args:
120
+ endpoint (str): End point to call
121
+ countryiso3 (Optional[str]): Country for which to obtain data. Defaults to all countries.
122
+ parameters (Optional[Dict]): Paramaters to pass to call. Defaults to None.
123
+
124
+ Returns:
125
+ List: List of items from the WFP endpoint
126
+ """
127
+ if not parameters:
128
+ parameters = {}
129
+ all_data = []
130
+ url = f"{self.base_url}{endpoint}"
131
+ url_parts = url.split("/")
132
+ base_filename = f"{url_parts[-2]}_{url_parts[-1]}"
133
+ if countryiso3 == "PSE": # hack as PSE is treated by WFP as 2 areas
134
+ countryiso3s = ["PSW", "PSG"]
135
+ else:
136
+ countryiso3s = [countryiso3]
137
+ for countryiso3 in countryiso3s:
138
+ page = 1
139
+ data = None
140
+ while data is None or len(data) > 0:
141
+ page_parameters = {"page": page}
142
+ page_parameters.update(parameters)
143
+ if countryiso3 is None:
144
+ filename = f"{base_filename}_{page}.json"
145
+ log = f"{base_filename} page {page}"
146
+ else:
147
+ filename = f"{base_filename}_{countryiso3}_{page}.json"
148
+ log = f"{base_filename} for {countryiso3} page {page}"
149
+ page_parameters["CountryCode"] = countryiso3
150
+ try:
151
+ json = self.retrieve(url, filename, log, page_parameters)
152
+ except FileNotFoundError:
153
+ json = {"items": []}
154
+ data = json["items"]
155
+ all_data.extend(data)
156
+ page = page + 1
157
+ return all_data
@@ -0,0 +1,73 @@
1
+ import logging
2
+ from typing import Dict, List
3
+
4
+ from . import get_int_timestamp
5
+ from .wfp_api import WFPAPI
6
+ from hdx.utilities.dateparse import parse_date
7
+ from hdx.utilities.typehint import ListTuple
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class WFPExchangeRates:
13
+ """Obtain WFP official exchange rates. It needs a WFP API object.
14
+
15
+ Args:
16
+ wfp_api (WFPAPI): WFPAPI object
17
+ """
18
+
19
+ def __init__(self, wfp_api: WFPAPI):
20
+ self.wfp_api = wfp_api
21
+
22
+ def get_currencies(self) -> List[str]:
23
+ """Get list of currencies in WFP API
24
+
25
+ Returns:
26
+ List[str]: List of currencies in WFP API
27
+ """
28
+ currencies = []
29
+ for currency in self.wfp_api.get_items("Currency/List"):
30
+ currencies.append(currency["name"])
31
+ return currencies
32
+
33
+ def get_currency_historic_rates(self, currency: str) -> Dict[int, float]:
34
+ """Get historic rates for currency from WFP API
35
+
36
+ Args:
37
+ currency (str): Currency
38
+
39
+ Returns:
40
+ Dict[int, float]: Mapping from timestamp to rate
41
+ """
42
+ quotes = self.wfp_api.get_items(
43
+ "Currency/UsdIndirectQuotation",
44
+ parameters={"currencyName": currency},
45
+ )
46
+ historic_rates = {}
47
+ for quote in quotes:
48
+ if not quote["isOfficial"]:
49
+ continue
50
+ date = parse_date(quote["date"])
51
+ timestamp = get_int_timestamp(date)
52
+ historic_rates[timestamp] = quote["value"]
53
+ return historic_rates
54
+
55
+ def get_historic_rates(
56
+ self, currencies: ListTuple[str]
57
+ ) -> Dict[str, Dict]:
58
+ """Get historic rates for a list of currencies from WFP API
59
+
60
+ Args:
61
+ currencies (List[str]): List of currencies
62
+
63
+ Returns:
64
+ Dict[str, Dict]: Mapping from currency to mapping from timestamp to rate
65
+ """
66
+ historic_rates = {}
67
+ for currency in currencies:
68
+ logger.info(f"Getting WFP historic rates for {currency}")
69
+ currency_historic_rates = self.get_currency_historic_rates(
70
+ currency
71
+ )
72
+ historic_rates[currency.upper()] = currency_historic_rates
73
+ return historic_rates
@@ -516,7 +516,7 @@ admin_name_replacements:
516
516
  " oblast": ""
517
517
 
518
518
  admin_fuzzy_dont:
519
- - "nord"
519
+ - "YEM|nord"
520
520
  - "north"
521
521
  - "sud"
522
522
  - "south"
@@ -0,0 +1 @@
1
+ {"items": [{"createDate": "2021-08-02T18:24:29.657", "extendedName": "United Arab Emirates Dirham", "id": 131, "name": "AED", "updateDate": "2023-10-05T16:05:48.223"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Afghan Afghani", "id": 87, "name": "AFN", "updateDate": "2023-10-05T16:06:06.557"}, {"createDate": "2021-08-02T18:22:53.87", "extendedName": "Albanian Lek", "id": 130, "name": "ALL", "updateDate": "2023-10-05T16:06:11.963"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Armenian Dram", "id": 37, "name": "AMD", "updateDate": "2023-10-05T16:06:16.883"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Angolan Kwanza", "id": 96, "name": "AOA", "updateDate": "2023-10-05T15:07:06.5"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Argentine Peso", "id": 106, "name": "ARS", "updateDate": "2023-10-05T16:06:22.83"}, {"createDate": "2021-08-02T18:28:54.6", "extendedName": "Australian Dollar", "id": 133, "name": "AUD", "updateDate": "2023-10-05T16:06:28.503"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Azerbaijani Manat", "id": 36, "name": "AZN", "updateDate": "2023-10-05T16:06:33.617"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Bangladeshi Taka", "id": 25, "name": "BDT", "updateDate": "2023-10-05T16:06:39.94"}, {"createDate": "2021-08-02T18:27:55.72", "extendedName": "Bulgarian Lev", "id": 132, "name": "BGN", "updateDate": "2023-10-05T16:06:45.027"}, {"createDate": "2021-10-04T18:28:31.65", "extendedName": "Bahraini Dinar", "id": 138, "name": "BHD", "updateDate": "2023-10-05T16:06:52.357"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Burundian Franc", "id": 32, "name": "BIF", "updateDate": "2023-10-05T16:05:30.807"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Boliviano", "id": 46, "name": "BOB", "updateDate": "2023-10-05T16:07:16.897"}, {"createDate": "2024-01-19T10:08:31.157", "extendedName": "Brazilian Real", "id": 159, "name": "BRL", "updateDate": null}, {"createDate": "2021-11-16T13:56:25.917", "extendedName": "Bahamian Dollar", "id": 144, "name": "BSD", "updateDate": "2023-10-05T16:09:05.437"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Bhutanese Ngultrum", "id": 76, "name": "BTN", "updateDate": "2023-10-05T16:07:41.03"}, {"createDate": "2022-09-09T08:56:59.297", "extendedName": "Botswana Pula", "id": 148, "name": "BWP", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Belarusian Ruble", "id": 107, "name": "BYR", "updateDate": "2023-10-05T16:08:22.667"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Congolese Franc", "id": 27, "name": "CDF", "updateDate": "2023-10-05T16:08:43.547"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Chilean Peso", "id": 108, "name": "CLP", "updateDate": "2023-10-05T16:08:58.83"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Renminbi", "id": 109, "name": "CNY", "updateDate": "2023-10-05T16:09:23.17"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Colombian Peso", "id": 67, "name": "COP", "updateDate": "2023-10-05T16:09:51.277"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Costa Rican Colon", "id": 92, "name": "CRC", "updateDate": "2023-10-05T16:10:04.74"}, {"createDate": "2021-08-02T19:18:01.077", "extendedName": "Cuban Convertible Pesos", "id": 134, "name": "CUC", "updateDate": "2023-10-05T16:10:15.51"}, {"createDate": "2021-07-23T10:23:48.907", "extendedName": "Cuban Peso", "id": 127, "name": "CUP", "updateDate": "2021-07-23T10:24:03.74"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Cape Verdean Escudo", "id": 57, "name": "CVE", "updateDate": "2023-10-05T16:10:33.13"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Djiboutian Franc", "id": 59, "name": "DJF", "updateDate": "2023-10-05T16:10:45.763"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Dominican Peso", "id": 85, "name": "DOP", "updateDate": "2023-10-05T16:11:12.62"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Algerian Dinar", "id": 91, "name": "DZD", "updateDate": "2023-10-05T16:11:26.253"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Egyptian Pound", "id": 38, "name": "EGP", "updateDate": "2023-10-05T16:11:39.353"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Eritrean Nakfa", "id": 110, "name": "ERN", "updateDate": "2023-10-05T16:11:53.783"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Ethiopian Birr", "id": 47, "name": "ETB", "updateDate": "2023-10-05T16:12:07.26"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Euro", "id": 111, "name": "EUR", "updateDate": "2023-10-05T16:12:17.437"}, {"createDate": "2021-11-16T13:59:56.407", "extendedName": "Fijian dollar", "id": 146, "name": "FJD", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Georgian Lari", "id": 50, "name": "GEL", "updateDate": "2023-10-05T16:12:32.133"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Ghanaian Cedi", "id": 35, "name": "GHS", "updateDate": "2023-10-05T16:12:51.58"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Gambian Dalasi", "id": 42, "name": "GMD", "updateDate": "2023-10-05T16:13:02.697"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Guinean Franc", "id": 54, "name": "GNF", "updateDate": "2023-10-05T16:13:27.12"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Guatemalan Quetzal", "id": 82, "name": "GTQ", "updateDate": "2023-10-05T16:13:42.487"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Honduran Lempira", "id": 112, "name": "HNL", "updateDate": "2023-10-05T16:14:02.63"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Haitian Gourde", "id": 24, "name": "HTG", "updateDate": "2023-10-05T16:16:54.453"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Indonesian Rupiah", "id": 34, "name": "IDR", "updateDate": "2023-10-05T16:51:09.01"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "New Israeli Shekel", "id": 73, "name": "ILS", "updateDate": "2021-09-20T17:55:14.71"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Indian Rupee", "id": 68, "name": "INR", "updateDate": "2023-10-05T16:51:24.84"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Iraqi Dinar", "id": 84, "name": "IQD", "updateDate": "2023-10-05T16:51:42.25"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Iranian Rial", "id": 89, "name": "IRR", "updateDate": "2023-10-05T16:52:01.813"}, {"createDate": "2021-11-16T13:50:01.28", "extendedName": "Jamaican Dollar", "id": 139, "name": "JMD", "updateDate": "2021-11-16T13:51:47.597"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Jordanian Dinar", "id": 58, "name": "JOD", "updateDate": "2023-10-05T16:52:13.29"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Japanese Yen", "id": 113, "name": "JPY", "updateDate": "2023-10-05T16:52:25.02"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Kenyan Shilling", "id": 30, "name": "KES", "updateDate": "2023-10-05T17:20:23.877"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Kyrgyzstani Som", "id": 61, "name": "KGS", "updateDate": "2023-10-05T17:20:37.52"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Cambodian Riel", "id": 60, "name": "KHR", "updateDate": "2023-10-05T17:20:54.753"}, {"createDate": "2022-09-09T08:58:07.763", "extendedName": "Comorian Franc", "id": 149, "name": "KMF", "updateDate": null}, {"createDate": "2021-11-16T13:53:56.17", "extendedName": "North Korean Won", "id": 141, "name": "KPW", "updateDate": null}, {"createDate": "2021-11-16T13:57:58.577", "extendedName": "Cayman Islands Dollar", "id": 145, "name": "KYD", "updateDate": "2023-10-05T17:21:02.627"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Kazakhstani Tenge", "id": 99, "name": "KZT", "updateDate": "2023-10-05T17:21:22.537"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Lao Kip", "id": 63, "name": "LAK", "updateDate": "2023-10-05T17:21:33.213"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Lebanese Pound", "id": 90, "name": "LBP", "updateDate": "2023-10-05T17:21:44.72"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Sri Lankan Rupee", "id": 55, "name": "LKR", "updateDate": "2023-10-05T17:21:55.583"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Liberian Dollar", "id": 40, "name": "LRD", "updateDate": "2023-10-05T17:22:08.767"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Lesotho Loti", "id": 56, "name": "LSL", "updateDate": "2023-10-05T17:22:20.387"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Libyan Dinar", "id": 97, "name": "LYD", "updateDate": "2023-10-05T17:22:34.527"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Moroccan Dirham", "id": 101, "name": "MAD", "updateDate": "2023-10-05T17:22:45.337"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Moldovan Leu", "id": 100, "name": "MDL", "updateDate": "2023-10-05T17:22:56.143"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Malagasy Ariary", "id": 65, "name": "MGA", "updateDate": "2023-10-05T17:23:11.417"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Myanmar Kyat", "id": 74, "name": "MMK", "updateDate": "2023-10-05T17:23:21.75"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Mongolian T\u00f6gr\u00f6g", "id": 114, "name": "MNT", "updateDate": "2023-10-05T17:23:37.12"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Mauritanian Ouguiya", "id": 64, "name": "MRO", "updateDate": "2023-10-05T17:23:52.63"}, {"createDate": "2022-05-18T14:54:28.977", "extendedName": "Ouguiya", "id": 147, "name": "MRU", "updateDate": "2022-05-20T14:29:42.43"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Malawian Kwacha", "id": 66, "name": "MWK", "updateDate": "2023-10-05T17:24:11.41"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Mexican Peso", "id": 115, "name": "MXN", "updateDate": "2023-10-05T17:24:27.67"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Mozambican Metical", "id": 51, "name": "MZN", "updateDate": "2023-10-06T13:09:29"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Namibian Dollar", "id": 116, "name": "NAD", "updateDate": "2023-10-06T13:09:36.943"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Nigerian Naira", "id": 95, "name": "NGN", "updateDate": "2023-10-06T13:09:47.943"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Nicaraguan C\u00f3rdoba", "id": 86, "name": "NIO", "updateDate": "2023-10-06T13:10:00.62"}, {"createDate": "2023-10-06T13:10:24.21", "extendedName": "Norwegian krone", "id": 152, "name": "NOK", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Nepalese Rupee", "id": 62, "name": "NPR", "updateDate": "2023-10-06T13:10:37.26"}, {"createDate": "2023-10-06T13:11:01.767", "extendedName": "New Zealand Dollar", "id": 153, "name": "NZD", "updateDate": null}, {"createDate": "2023-10-06T13:11:20.807", "extendedName": "Omani Rial", "id": 154, "name": "OMR", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Panamanian Balboa", "id": 117, "name": "PAB", "updateDate": "2023-10-06T13:11:45.267"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Peruvian Sol", "id": 33, "name": "PEN", "updateDate": "2023-10-06T13:11:54.71"}, {"createDate": "2021-11-16T13:51:13.607", "extendedName": "Papua New Guinean Kina", "id": 140, "name": "PGK", "updateDate": "2021-11-16T13:51:20.977"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Philippine Peso", "id": 29, "name": "PHP", "updateDate": "2023-10-06T13:12:31.657"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Pakistani Rupee", "id": 45, "name": "PKR", "updateDate": "2023-10-06T13:12:45.58"}, {"createDate": "2023-10-06T13:12:59.437", "extendedName": "Polish z\u0142oty", "id": 155, "name": "PLN", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Paraguayan Guaran\u00ed", "id": 118, "name": "PYG", "updateDate": "2023-10-06T13:13:08.133"}, {"createDate": "2023-10-06T13:14:01.817", "extendedName": "Romanian Leu", "id": 156, "name": "RON", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Russian Ruble", "id": 102, "name": "RUB", "updateDate": "2023-10-06T13:13:29.22"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Rwandan Franc", "id": 77, "name": "RWF", "updateDate": "2023-10-06T13:14:15.373"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Saudi Riyal", "id": 103, "name": "SAR", "updateDate": "2023-10-06T13:14:24.197"}, {"createDate": "2022-09-09T10:23:48.027", "extendedName": "Solomon Islands Dollar", "id": 150, "name": "SBD", "updateDate": "2023-10-06T13:14:30.883"}, {"createDate": "2023-10-06T13:14:55.84", "extendedName": "Seychelles Rupee", "id": 157, "name": "SCR", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Sudanese Pound", "id": 75, "name": "SDG", "updateDate": "2023-10-06T13:15:03.55"}, {"createDate": "2023-10-06T13:15:21.86", "extendedName": "Swedish Krona ", "id": 158, "name": "SEK", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Sierra Leonean Leone ", "id": 53, "name": "SLL", "updateDate": "2023-10-06T13:15:44.363"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Somaliland Shilling", "id": 81, "name": "SLS", "updateDate": "2020-05-13T19:08:07.153"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Somali Shilling", "id": 79, "name": "SOS", "updateDate": "2023-10-06T13:15:54.223"}, {"createDate": "2021-09-03T16:47:19.25", "extendedName": "Surinamese dollar", "id": 137, "name": "SRD", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "South Sudanese Pound", "id": 83, "name": "SSP", "updateDate": "2023-10-06T13:16:09.307"}, {"createDate": "2021-11-16T13:54:49.843", "extendedName": "S\u00e3o Tom\u00e9 and Pr\u00edncipe Dobra", "id": 142, "name": "STN", "updateDate": "2022-02-04T18:49:22.997"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Syrian Pound", "id": 78, "name": "SYP", "updateDate": "2023-10-06T13:16:20.727"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Swazi Lilangeni", "id": 23, "name": "SZL", "updateDate": "2023-10-06T13:16:32.907"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Thai Baht", "id": 119, "name": "THB", "updateDate": "2023-10-06T13:16:43.66"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Tajikistani Somoni", "id": 49, "name": "TJS", "updateDate": "2023-10-06T13:16:53.313"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Turkmenistan Manat", "id": 105, "name": "TMT", "updateDate": "2023-10-06T13:17:03.19"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Tunisian Dinar", "id": 104, "name": "TND", "updateDate": "2023-10-06T13:17:16.303"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Turkish Lira", "id": 88, "name": "TRY", "updateDate": "2023-10-06T13:17:27.8"}, {"createDate": "2021-11-16T13:55:49.043", "extendedName": "Trinidad and Tobago dollar", "id": 143, "name": "TTD", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Tanzanian Shilling", "id": 22, "name": "TZS", "updateDate": "2023-10-06T13:17:41.38"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Ukrainian Hryvnia", "id": 93, "name": "UAH", "updateDate": "2023-10-06T13:17:49.587"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Ugandan Shilling", "id": 39, "name": "UGX", "updateDate": "2023-10-06T13:18:00.927"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "United States Dollar", "id": 28, "name": "USD", "updateDate": "2023-10-06T13:18:14.463"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Uruguayan Peso", "id": 120, "name": "UYU", "updateDate": "2022-02-04T19:02:54.16"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Uzbekistan Sum", "id": 121, "name": "UZS", "updateDate": "2023-10-06T13:18:39.537"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": null, "id": 98, "name": "VEF", "updateDate": null}, {"createDate": "2021-08-27T15:20:05.343", "extendedName": "Venezuelan Bolivar", "id": 135, "name": "VES", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Vietnamese Dong", "id": 122, "name": "VND", "updateDate": "2023-10-06T13:19:04.453"}, {"createDate": "2022-09-09T10:27:13.38", "extendedName": "Vanuatu Vatu", "id": 151, "name": "VUV", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Samoan Tala", "id": 123, "name": "WST", "updateDate": "2023-10-06T13:19:15.853"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "CFA franc BEAC", "id": 48, "name": "XAF", "updateDate": "2023-10-06T13:19:28.203"}, {"createDate": "2021-08-02T18:17:10.363", "extendedName": "East Caribbean dollar", "id": 129, "name": "XCD", "updateDate": null}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "CFA franc BCEAO", "id": 26, "name": "XOF", "updateDate": "2023-10-06T13:19:46.72"}, {"createDate": "2020-04-22T22:02:26.937", "extendedName": "Yemeni Rial", "id": 31, "name": "YER", "updateDate": "2023-10-06T13:19:55.923"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "South African Rand", "id": 124, "name": "ZAR", "updateDate": "2023-10-06T13:20:04.47"}, {"createDate": "2024-05-10T16:34:21.023", "extendedName": "Zimbabwe Gold", "id": 160, "name": "ZiG", "updateDate": "2024-05-16T20:03:21.057"}, {"createDate": "2020-04-22T22:02:26.94", "extendedName": "Zambian Kwacha", "id": 94, "name": "ZMW", "updateDate": "2022-09-09T10:19:57.007"}, {"createDate": "2020-04-22T22:02:26.943", "extendedName": "Zimbabwean Dollar", "id": 125, "name": "ZWL", "updateDate": "2024-05-10T16:34:31.017"}], "page": 1, "totalItems": 127}
@@ -0,0 +1 @@
1
+ {"items": [], "page": 2, "totalItems": 127}