hdx-python-country 3.8.2__tar.gz → 3.8.4__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.2 → hdx_python_country-3.8.4}/.config/pre-commit-config.yaml +3 -3
  2. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/PKG-INFO +3 -3
  3. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/pyproject.toml +5 -5
  4. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/requirements.txt +16 -14
  5. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/_version.py +2 -2
  6. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/country.py +23 -5
  7. hdx_python_country-3.8.4/src/hdx/location/wfp_api.py +157 -0
  8. hdx_python_country-3.8.4/src/hdx/location/wfp_exchangerates.py +73 -0
  9. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_List_1.json +1 -0
  10. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_List_2.json +1 -0
  11. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_1.json +1 -0
  12. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_10.json +1 -0
  13. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_2.json +1 -0
  14. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_3.json +1 -0
  15. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_4.json +1 -0
  16. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_5.json +1 -0
  17. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_6.json +1 -0
  18. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_7.json +1 -0
  19. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_8.json +1 -0
  20. hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_9.json +1 -0
  21. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/test_country.py +16 -0
  22. hdx_python_country-3.8.4/tests/hdx/location/test_wfp_exchangerates.py +66 -0
  23. hdx_python_country-3.8.2/src/hdx/location/wfp_exchangerates.py +0 -101
  24. hdx_python_country-3.8.2/tests/hdx/location/test_wfp_exchangerates.py +0 -42
  25. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.config/coveragerc +0 -0
  26. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.config/pytest.ini +0 -0
  27. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.config/ruff.toml +0 -0
  28. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.github/workflows/publish.yaml +0 -0
  29. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.github/workflows/run-python-tests.yaml +0 -0
  30. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.gitignore +0 -0
  31. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/CONTRIBUTING.md +0 -0
  32. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/LICENSE +0 -0
  33. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/README.md +0 -0
  34. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/documentation/.readthedocs.yaml +0 -0
  35. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/documentation/main.md +0 -0
  36. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/documentation/pydoc-markdown.yaml +0 -0
  37. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv +0 -0
  38. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/__init__.py +0 -0
  39. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/adminlevel.py +0 -0
  40. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/currency.py +0 -0
  41. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/phonetics.py +0 -0
  42. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/adminlevel.yaml +0 -0
  43. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/adminlevelparent.yaml +0 -0
  44. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/download-global-pcode-lengths.csv +0 -0
  45. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/download-global-pcodes-adm-1-2.csv +0 -0
  46. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/secondary_historic_rates.csv +0 -0
  47. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/secondary_rates.json +0 -0
  48. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
  49. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/__init__.py +0 -0
  50. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/test_adminlevel.py +0 -0
  51. {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/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,11 +1,10 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: hdx-python-country
3
- Version: 3.8.2
3
+ Version: 3.8.4
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
7
7
  License: MIT
8
- License-File: LICENSE
9
8
  Keywords: HDX,country,country code,currencies,currency,exchange rate,foreign exchange,fx,iso 3166,iso2,iso3,location,region
10
9
  Classifier: Development Status :: 5 - Production/Stable
11
10
  Classifier: Intended Audience :: Developers
@@ -26,8 +25,9 @@ Classifier: Programming Language :: Python :: 3.12
26
25
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
26
  Requires-Python: >=3.8
28
27
  Requires-Dist: hdx-python-utilities>=3.7.4
29
- Requires-Dist: libhxl>=5.2.1
28
+ Requires-Dist: libhxl>=5.2.2
30
29
  Requires-Dist: pyphonetics
30
+ Requires-Dist: tenacity
31
31
  Provides-Extra: dev
32
32
  Requires-Dist: pre-commit; extra == 'dev'
33
33
  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:.}",]
@@ -18,11 +18,11 @@ charset-normalizer==3.4.0
18
18
  # via requests
19
19
  click==8.1.7
20
20
  # via typer
21
- coverage==7.6.3
21
+ coverage==7.6.7
22
22
  # via pytest-cov
23
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
@@ -32,7 +32,7 @@ hdx-python-utilities==3.7.4
32
32
  # via hdx-python-country (pyproject.toml)
33
33
  humanize==4.11.0
34
34
  # via frictionless
35
- identify==2.6.1
35
+ identify==2.6.2
36
36
  # via pre-commit
37
37
  idna==3.10
38
38
  # via requests
@@ -54,7 +54,7 @@ jsonschema==4.23.0
54
54
  # tableschema-to-template
55
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==3.0.1
65
+ markupsafe==3.0.2
66
66
  # via jinja2
67
67
  mdurl==0.1.2
68
68
  # via markdown-it-py
@@ -70,7 +70,7 @@ nodeenv==1.9.1
70
70
  # via pre-commit
71
71
  openpyxl==3.1.5
72
72
  # via hdx-python-utilities
73
- packaging==24.1
73
+ packaging==24.2
74
74
  # via pytest
75
75
  petl==1.7.15
76
76
  # via frictionless
@@ -96,7 +96,7 @@ pytest==8.3.3
96
96
  # via
97
97
  # hdx-python-country (pyproject.toml)
98
98
  # pytest-cov
99
- pytest-cov==5.0.0
99
+ pytest-cov==6.0.0
100
100
  # via hdx-python-country (pyproject.toml)
101
101
  python-dateutil==2.9.0.post0
102
102
  # via
@@ -127,19 +127,19 @@ requests-file==2.1.0
127
127
  # via hdx-python-utilities
128
128
  rfc3986==2.0.0
129
129
  # via frictionless
130
- rich==13.9.2
130
+ rich==13.9.4
131
131
  # via typer
132
- rpds-py==0.20.0
132
+ rpds-py==0.21.0
133
133
  # via
134
134
  # jsonschema
135
135
  # referencing
136
136
  ruamel-yaml==0.18.6
137
137
  # via hdx-python-utilities
138
- ruamel-yaml-clib==0.2.8
138
+ ruamel-yaml-clib==0.2.12
139
139
  # via ruamel-yaml
140
140
  shellingham==1.5.4
141
141
  # via typer
142
- simpleeval==1.0.0
142
+ simpleeval==1.0.3
143
143
  # via frictionless
144
144
  six==1.16.0
145
145
  # via python-dateutil
@@ -151,9 +151,11 @@ tableschema-to-template==0.0.13
151
151
  # via hdx-python-utilities
152
152
  tabulate==0.9.0
153
153
  # via frictionless
154
+ tenacity==9.0.0
155
+ # via hdx-python-country (pyproject.toml)
154
156
  text-unidecode==1.3
155
157
  # via python-slugify
156
- typer==0.12.5
158
+ typer==0.13.0
157
159
  # via frictionless
158
160
  typing-extensions==4.12.2
159
161
  # via
@@ -171,9 +173,9 @@ urllib3==2.2.3
171
173
  # requests
172
174
  validators==0.34.0
173
175
  # via frictionless
174
- virtualenv==20.26.6
176
+ virtualenv==20.27.1
175
177
  # via pre-commit
176
- wheel==0.44.0
178
+ wheel==0.45.0
177
179
  # via libhxl
178
180
  xlrd==2.0.1
179
181
  # via hdx-python-utilities
@@ -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.2'
16
- __version_tuple__ = version_tuple = (3, 8, 2)
15
+ __version__ = version = '3.8.4'
16
+ __version_tuple__ = version_tuple = (3, 8, 4)
@@ -2,6 +2,7 @@
2
2
 
3
3
  import copy
4
4
  import logging
5
+ import os.path
5
6
  import re
6
7
  from string import punctuation
7
8
  from typing import Dict, List, Optional, Tuple, Union
@@ -73,6 +74,11 @@ class Country:
73
74
  _countriesdata = None
74
75
  _ochaurl_default = "https://docs.google.com/spreadsheets/d/1NjSI2LaS3SqbgYc0HdD8oIb7lofGtiHgoKKATCpwVdY/export?format=csv&gid=1088874596"
75
76
  _ochaurl = _ochaurl_default
77
+ _ochapath_default = script_dir_plus_file(
78
+ "Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv",
79
+ CountryError,
80
+ )
81
+ _ochapath = _ochapath_default
76
82
  _country_name_overrides = {}
77
83
  _country_name_mappings = {}
78
84
 
@@ -238,10 +244,7 @@ class Country:
238
244
  )
239
245
  if countries is None:
240
246
  countries = hxl.data(
241
- script_dir_plus_file(
242
- "Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv",
243
- Country,
244
- ),
247
+ cls._ochapath,
245
248
  InputOptions(allow_local=True, encoding="utf-8"),
246
249
  )
247
250
  cls.set_countriesdata(countries)
@@ -264,7 +267,7 @@ class Country:
264
267
  cls._use_live = use_live
265
268
 
266
269
  @classmethod
267
- def set_ocha_url(cls, url: Optional[str] = None) -> None:
270
+ def set_ocha_url(cls, url: str = None) -> None:
268
271
  """
269
272
  Set OCHA url from which to retrieve countries data
270
273
 
@@ -278,6 +281,21 @@ class Country:
278
281
  url = cls._ochaurl_default
279
282
  cls._ochaurl = url
280
283
 
284
+ @classmethod
285
+ def set_ocha_path(cls, path: Optional[str] = None) -> None:
286
+ """
287
+ Set local path from which to retrieve OCHA countries data
288
+
289
+ Args:
290
+ path (Optional[str]): Local path from which to retrieve countries data. Defaults to None.
291
+
292
+ Returns:
293
+ None
294
+ """
295
+ if not path or (path and not os.path.exists(path)):
296
+ path = cls._ochapath_default
297
+ cls._ochapath = path
298
+
281
299
  @classmethod
282
300
  def set_country_name_overrides(cls, country_name_overrides: Dict) -> None:
283
301
  """
@@ -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
@@ -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}