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.
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.config/pre-commit-config.yaml +3 -3
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/PKG-INFO +3 -3
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/pyproject.toml +5 -5
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/requirements.txt +16 -14
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/_version.py +2 -2
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/country.py +23 -5
- hdx_python_country-3.8.4/src/hdx/location/wfp_api.py +157 -0
- hdx_python_country-3.8.4/src/hdx/location/wfp_exchangerates.py +73 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_List_1.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_List_2.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_1.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_10.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_2.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_3.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_4.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_5.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_6.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_7.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_8.json +1 -0
- hdx_python_country-3.8.4/tests/fixtures/wfp/Currency_UsdIndirectQuotation_9.json +1 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/test_country.py +16 -0
- hdx_python_country-3.8.4/tests/hdx/location/test_wfp_exchangerates.py +66 -0
- hdx_python_country-3.8.2/src/hdx/location/wfp_exchangerates.py +0 -101
- hdx_python_country-3.8.2/tests/hdx/location/test_wfp_exchangerates.py +0 -42
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.config/coveragerc +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.config/pytest.ini +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.config/ruff.toml +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.github/workflows/publish.yaml +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/.gitignore +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/CONTRIBUTING.md +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/LICENSE +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/README.md +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/documentation/main.md +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/documentation/pydoc-markdown.yaml +0 -0
- {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
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/adminlevel.py +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/currency.py +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/src/hdx/location/phonetics.py +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/adminlevel.yaml +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/adminlevelparent.yaml +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/download-global-pcode-lengths.csv +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/download-global-pcodes-adm-1-2.csv +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/secondary_historic_rates.csv +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/fixtures/secondary_rates.json +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/__init__.py +0 -0
- {hdx_python_country-3.8.2 → hdx_python_country-3.8.4}/tests/hdx/location/test_adminlevel.py +0 -0
- {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:
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
21
|
+
coverage==7.6.7
|
|
22
22
|
# via pytest-cov
|
|
23
23
|
distlib==0.3.9
|
|
24
24
|
# via virtualenv
|
|
25
|
-
et-xmlfile==
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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==
|
|
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.
|
|
130
|
+
rich==13.9.4
|
|
131
131
|
# via typer
|
|
132
|
-
rpds-py==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.
|
|
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.
|
|
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.
|
|
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.
|
|
176
|
+
virtualenv==20.27.1
|
|
175
177
|
# via pre-commit
|
|
176
|
-
wheel==0.
|
|
178
|
+
wheel==0.45.0
|
|
177
179
|
# via libhxl
|
|
178
180
|
xlrd==2.0.1
|
|
179
181
|
# via hdx-python-utilities
|
|
@@ -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
|
-
|
|
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:
|
|
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}
|