hdx-python-country 3.6.4__tar.gz → 3.6.6__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.6.4 → hdx_python_country-3.6.6}/.config/pre-commit-config.yaml +9 -10
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/.config/ruff.toml +8 -5
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/.github/workflows/run-python-tests.yaml +3 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/PKG-INFO +7 -7
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/README.md +4 -4
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/documentation/main.md +9 -8
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/pyproject.toml +10 -14
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/requirements.txt +25 -26
- hdx_python_country-3.6.6/src/hdx/location/__init__.py +17 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/src/hdx/location/_version.py +2 -2
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/src/hdx/location/adminlevel.py +4 -4
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/src/hdx/location/country.py +28 -27
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/src/hdx/location/currency.py +14 -21
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/src/hdx/location/names.py +1 -1
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/src/hdx/location/phonetics.py +1 -1
- hdx_python_country-3.6.6/src/hdx/location/wfp_exchangerates.py +102 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/hdx/location/test_adminlevel.py +1 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/hdx/location/test_country.py +1 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/hdx/location/test_currency.py +17 -15
- hdx_python_country-3.6.6/tests/hdx/location/test_wfp_exchangerates.py +42 -0
- hdx_python_country-3.6.4/.config/black.toml +0 -2
- hdx_python_country-3.6.4/src/hdx/location/__init__.py +0 -1
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/.config/coveragerc +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/.config/pytest.ini +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/.github/workflows/publish.yaml +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/.gitignore +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/CONTRIBUTING.md +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/LICENSE +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/documentation/pydoc-markdown.yaml +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/src/hdx/location/Countries & Territories Taxonomy MVP - C&T Taxonomy with HXL Tags.csv +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/adminlevel.yaml +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/global_pcode_lengths.csv +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/global_pcodes_adm_1_2.csv +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/secondary_historic_rates.csv +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/secondary_rates.json +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/hdx/location/Countries_UZB_Deleted.csv +0 -0
- {hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/hdx/location/__init__.py +0 -0
|
@@ -2,23 +2,22 @@ default_language_version:
|
|
|
2
2
|
python: python3.11
|
|
3
3
|
repos:
|
|
4
4
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
-
rev: v4.
|
|
5
|
+
rev: v4.5.0
|
|
6
6
|
hooks:
|
|
7
7
|
- id: trailing-whitespace
|
|
8
8
|
- id: end-of-file-fixer
|
|
9
9
|
- id: check-ast
|
|
10
|
-
- repo: https://github.com/
|
|
11
|
-
rev:
|
|
12
|
-
hooks:
|
|
13
|
-
- id: black
|
|
14
|
-
args: [--config, .config/black.toml]
|
|
15
|
-
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
|
16
|
-
rev: v0.0.267
|
|
10
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
11
|
+
rev: v0.3.0
|
|
17
12
|
hooks:
|
|
13
|
+
# Run the linter.
|
|
18
14
|
- id: ruff
|
|
19
|
-
args: [--config, .config/ruff.toml, --fix
|
|
15
|
+
args: [--config, .config/ruff.toml, --fix]
|
|
16
|
+
# Run the formatter.
|
|
17
|
+
- id: ruff-format
|
|
18
|
+
args: [--config, .config/ruff.toml]
|
|
20
19
|
- repo: https://github.com/jazzband/pip-tools
|
|
21
|
-
rev:
|
|
20
|
+
rev: 7.4.0
|
|
22
21
|
hooks:
|
|
23
22
|
- id: pip-compile
|
|
24
23
|
name: pip-compile requirements.txt
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
line-length = 79
|
|
2
2
|
exclude = ["_version.py"]
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
# List of rules: https://beta.ruff.rs/docs/rules/
|
|
3
|
+
|
|
4
|
+
[lint]
|
|
5
|
+
# List of rules: https://docs.astral.sh/ruff/rules/
|
|
7
6
|
select = [
|
|
8
7
|
"E", # pycodestyle - default
|
|
9
8
|
"F", # pyflakes - default
|
|
10
9
|
"I" # isort
|
|
11
10
|
]
|
|
11
|
+
ignore = [
|
|
12
|
+
"E501" # Line too long
|
|
13
|
+
]
|
|
14
|
+
|
|
12
15
|
|
|
13
|
-
[isort]
|
|
16
|
+
[lint.isort]
|
|
14
17
|
known-local-folder = ["hdx"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hdx-python-country
|
|
3
|
-
Version: 3.6.
|
|
3
|
+
Version: 3.6.6
|
|
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-email: Michael Rans <rans@email.com>
|
|
@@ -25,8 +25,8 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
25
25
|
Classifier: Programming Language :: Python :: 3.12
|
|
26
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
27
|
Requires-Python: >=3.8
|
|
28
|
-
Requires-Dist: hdx-python-utilities>=3.6.
|
|
29
|
-
Requires-Dist: libhxl>=5.
|
|
28
|
+
Requires-Dist: hdx-python-utilities>=3.6.5
|
|
29
|
+
Requires-Dist: libhxl>=5.2
|
|
30
30
|
Requires-Dist: pyphonetics
|
|
31
31
|
Provides-Extra: dev
|
|
32
32
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
@@ -58,10 +58,10 @@ Dem. for Democratic and Rep. for Republic.
|
|
|
58
58
|
Mapping administration level names from a source to a given base set is also handled
|
|
59
59
|
including phonetic fuzzy name matching.
|
|
60
60
|
|
|
61
|
-
It also provides foreign exchange rates and conversion from amounts in local
|
|
62
|
-
USD and vice-versa. The conversion relies on Yahoo Finance, falling
|
|
63
|
-
[currency-api](https://github.com/fawazahmed0/currency-api) for current rates,
|
|
64
|
-
|
|
61
|
+
It also provides foreign exchange rates and conversion from amounts in local
|
|
62
|
+
currency to USD and vice-versa. The conversion relies on Yahoo Finance, falling
|
|
63
|
+
back on [currency-api](https://github.com/fawazahmed0/currency-api) for current rates, and Yahoo Finance falling back
|
|
64
|
+
on IMF data via IATI (with interpolation) for historic daily rates.
|
|
65
65
|
|
|
66
66
|
For more information, please read the [documentation](https://hdx-python-country.readthedocs.io/en/latest/).
|
|
67
67
|
|
|
@@ -21,10 +21,10 @@ Dem. for Democratic and Rep. for Republic.
|
|
|
21
21
|
Mapping administration level names from a source to a given base set is also handled
|
|
22
22
|
including phonetic fuzzy name matching.
|
|
23
23
|
|
|
24
|
-
It also provides foreign exchange rates and conversion from amounts in local
|
|
25
|
-
USD and vice-versa. The conversion relies on Yahoo Finance, falling
|
|
26
|
-
[currency-api](https://github.com/fawazahmed0/currency-api) for current rates,
|
|
27
|
-
|
|
24
|
+
It also provides foreign exchange rates and conversion from amounts in local
|
|
25
|
+
currency to USD and vice-versa. The conversion relies on Yahoo Finance, falling
|
|
26
|
+
back on [currency-api](https://github.com/fawazahmed0/currency-api) for current rates, and Yahoo Finance falling back
|
|
27
|
+
on IMF data via IATI (with interpolation) for historic daily rates.
|
|
28
28
|
|
|
29
29
|
For more information, please read the [documentation](https://hdx-python-country.readthedocs.io/en/latest/).
|
|
30
30
|
|
|
@@ -29,10 +29,10 @@ Dem. for Democratic and Rep. for Republic.
|
|
|
29
29
|
Mapping administration level names from a source to a given base set is also handled
|
|
30
30
|
including phonetic fuzzy name matching.
|
|
31
31
|
|
|
32
|
-
It also provides foreign exchange rates and conversion from amounts in local
|
|
33
|
-
USD and vice-versa. The conversion relies on Yahoo Finance, falling
|
|
34
|
-
[currency-api](https://github.com/fawazahmed0/currency-api) for current rates,
|
|
35
|
-
|
|
32
|
+
It also provides foreign exchange rates and conversion from amounts in local
|
|
33
|
+
currency to USD and vice-versa. The conversion relies on Yahoo Finance, falling
|
|
34
|
+
back on [currency-api](https://github.com/fawazahmed0/currency-api) for current rates, and Yahoo Finance falling back
|
|
35
|
+
on IMF data via IATI (with interpolation) for historic daily rates.
|
|
36
36
|
|
|
37
37
|
This library is part of the [Humanitarian Data Exchange](https://data.humdata.org/)
|
|
38
38
|
(HDX) project. If you have humanitarian related data, please upload your datasets to
|
|
@@ -185,9 +185,10 @@ unsuited for use where rates are expected to update while the program is running
|
|
|
185
185
|
timezone_handling=2), ignore_timeinfo=False)
|
|
186
186
|
# == 0.76910001039505
|
|
187
187
|
|
|
188
|
-
Historic rates can be made to fall back to current rates if desired (this
|
|
189
|
-
default). It is possible to pass in a Retrieve object to
|
|
190
|
-
downloaded files from the secondary sources to be
|
|
191
|
-
to be reused and to allow fallbacks from
|
|
188
|
+
Historic daily rates can be made to fall back to current rates if desired (this
|
|
189
|
+
is not the default). It is possible to pass in a Retrieve object to
|
|
190
|
+
Currency.setup() to allow the downloaded files from the secondary sources to be
|
|
191
|
+
saved or previously downloaded files to be reused and to allow fallbacks from
|
|
192
|
+
current rates to a static file eg.
|
|
192
193
|
|
|
193
194
|
Currency.setup(retriever, ..., fallback_historic_to_current=True, fallback_current_to_static=True)
|
|
@@ -34,8 +34,8 @@ classifiers = [
|
|
|
34
34
|
requires-python = ">=3.8"
|
|
35
35
|
|
|
36
36
|
dependencies = [
|
|
37
|
-
"hdx-python-utilities>=3.6.
|
|
38
|
-
"libhxl>=5.
|
|
37
|
+
"hdx-python-utilities>=3.6.5",
|
|
38
|
+
"libhxl>=5.2",
|
|
39
39
|
"pyphonetics",
|
|
40
40
|
]
|
|
41
41
|
dynamic = ["version"]
|
|
@@ -50,12 +50,16 @@ Homepage = "https://github.com/OCHA-DAP/hdx-python-country"
|
|
|
50
50
|
[project.optional-dependencies]
|
|
51
51
|
test = ["pytest", "pytest-cov"]
|
|
52
52
|
dev = ["pre-commit"]
|
|
53
|
+
#wfp = ["data-bridges-client@git+https://github.com/WFP-VAM/DataBridgesAPI@dev#egg=data-bridges-client"]
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
#########
|
|
56
57
|
# Hatch #
|
|
57
58
|
#########
|
|
58
59
|
|
|
60
|
+
#[tool.hatch.metadata]
|
|
61
|
+
#allow-direct-references = true
|
|
62
|
+
|
|
59
63
|
# Build
|
|
60
64
|
|
|
61
65
|
[tool.hatch.build.targets.wheel]
|
|
@@ -76,7 +80,7 @@ version_scheme = "python-simplified-semver"
|
|
|
76
80
|
# Tests
|
|
77
81
|
|
|
78
82
|
[tool.hatch.envs.test]
|
|
79
|
-
features = ["test"]
|
|
83
|
+
features = ["test"]#, "wfp"]
|
|
80
84
|
|
|
81
85
|
[tool.hatch.envs.test.scripts]
|
|
82
86
|
test = """
|
|
@@ -90,18 +94,10 @@ python = ["3.12"]
|
|
|
90
94
|
|
|
91
95
|
[tool.hatch.envs.lint]
|
|
92
96
|
detached = true
|
|
93
|
-
dependencies = [
|
|
94
|
-
"black",
|
|
95
|
-
"ruff",
|
|
96
|
-
]
|
|
97
|
+
dependencies = ["ruff"]
|
|
97
98
|
|
|
98
99
|
[tool.hatch.envs.lint.scripts]
|
|
99
100
|
style = [
|
|
100
|
-
"ruff --config .config/ruff.toml {args:.}",
|
|
101
|
-
"
|
|
102
|
-
]
|
|
103
|
-
# Not used for anything at the moment
|
|
104
|
-
fmt = [
|
|
105
|
-
"black --config .config/black.toml {args:.}",
|
|
106
|
-
"ruff --config .config/ruff.toml --fix {args:.}",
|
|
101
|
+
"ruff check --config .config/ruff.toml --diff {args:.}",
|
|
102
|
+
"ruff format --config .config/ruff.toml --diff {args:.}",
|
|
107
103
|
]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# This file is autogenerated by pip-compile with Python 3.11
|
|
3
3
|
# by the following command:
|
|
4
4
|
#
|
|
5
|
-
# pip-compile --all-extras --output-file=requirements.txt
|
|
5
|
+
# pip-compile --all-extras --output-file=requirements.txt pyproject.toml
|
|
6
6
|
#
|
|
7
7
|
annotated-types==0.6.0
|
|
8
8
|
# via pydantic
|
|
@@ -11,7 +11,7 @@ attrs==23.2.0
|
|
|
11
11
|
# frictionless
|
|
12
12
|
# jsonlines
|
|
13
13
|
# jsonschema
|
|
14
|
-
certifi==
|
|
14
|
+
certifi==2024.2.2
|
|
15
15
|
# via requests
|
|
16
16
|
cfgv==3.4.0
|
|
17
17
|
# via pre-commit
|
|
@@ -23,7 +23,7 @@ click==8.1.7
|
|
|
23
23
|
# via typer
|
|
24
24
|
colorama==0.4.6
|
|
25
25
|
# via typer
|
|
26
|
-
coverage[toml]==7.4.
|
|
26
|
+
coverage[toml]==7.4.3
|
|
27
27
|
# via pytest-cov
|
|
28
28
|
distlib==0.3.8
|
|
29
29
|
# via virtualenv
|
|
@@ -31,13 +31,13 @@ et-xmlfile==1.1.0
|
|
|
31
31
|
# via openpyxl
|
|
32
32
|
filelock==3.13.1
|
|
33
33
|
# via virtualenv
|
|
34
|
-
frictionless==5.16.
|
|
34
|
+
frictionless==5.16.1
|
|
35
35
|
# via hdx-python-utilities
|
|
36
|
-
hdx-python-utilities==3.6.
|
|
36
|
+
hdx-python-utilities==3.6.5
|
|
37
37
|
# via hdx-python-country (pyproject.toml)
|
|
38
38
|
humanize==4.9.0
|
|
39
39
|
# via frictionless
|
|
40
|
-
identify==2.5.
|
|
40
|
+
identify==2.5.35
|
|
41
41
|
# via pre-commit
|
|
42
42
|
idna==3.6
|
|
43
43
|
# via requests
|
|
@@ -51,21 +51,21 @@ jinja2==3.1.3
|
|
|
51
51
|
# via frictionless
|
|
52
52
|
jsonlines==4.0.0
|
|
53
53
|
# via hdx-python-utilities
|
|
54
|
-
jsonpath-ng==1.6.
|
|
54
|
+
jsonpath-ng==1.6.1
|
|
55
55
|
# via libhxl
|
|
56
56
|
jsonschema==4.17.3
|
|
57
57
|
# via
|
|
58
58
|
# frictionless
|
|
59
59
|
# tableschema-to-template
|
|
60
|
-
libhxl==5.2
|
|
60
|
+
libhxl==5.2.1
|
|
61
61
|
# via hdx-python-country (pyproject.toml)
|
|
62
62
|
loguru==0.7.2
|
|
63
63
|
# via hdx-python-utilities
|
|
64
64
|
markdown-it-py==3.0.0
|
|
65
65
|
# via rich
|
|
66
|
-
marko==2.0.
|
|
66
|
+
marko==2.0.3
|
|
67
67
|
# via frictionless
|
|
68
|
-
markupsafe==2.1.
|
|
68
|
+
markupsafe==2.1.5
|
|
69
69
|
# via jinja2
|
|
70
70
|
mdurl==0.1.2
|
|
71
71
|
# via markdown-it-py
|
|
@@ -77,19 +77,19 @@ packaging==23.2
|
|
|
77
77
|
# via pytest
|
|
78
78
|
petl==1.7.14
|
|
79
79
|
# via frictionless
|
|
80
|
-
platformdirs==4.
|
|
80
|
+
platformdirs==4.2.0
|
|
81
81
|
# via virtualenv
|
|
82
|
-
pluggy==1.
|
|
82
|
+
pluggy==1.4.0
|
|
83
83
|
# via pytest
|
|
84
84
|
ply==3.11
|
|
85
85
|
# via
|
|
86
86
|
# jsonpath-ng
|
|
87
87
|
# libhxl
|
|
88
|
-
pre-commit==3.6.
|
|
88
|
+
pre-commit==3.6.2
|
|
89
89
|
# via hdx-python-country (pyproject.toml)
|
|
90
|
-
pydantic==2.
|
|
90
|
+
pydantic==2.6.3
|
|
91
91
|
# via frictionless
|
|
92
|
-
pydantic-core==2.
|
|
92
|
+
pydantic-core==2.16.3
|
|
93
93
|
# via pydantic
|
|
94
94
|
pygments==2.17.2
|
|
95
95
|
# via rich
|
|
@@ -97,7 +97,7 @@ pyphonetics==0.5.3
|
|
|
97
97
|
# via hdx-python-country (pyproject.toml)
|
|
98
98
|
pyrsistent==0.20.0
|
|
99
99
|
# via jsonschema
|
|
100
|
-
pytest==
|
|
100
|
+
pytest==8.1.0
|
|
101
101
|
# via
|
|
102
102
|
# hdx-python-country (pyproject.toml)
|
|
103
103
|
# pytest-cov
|
|
@@ -110,7 +110,7 @@ python-dateutil==2.8.2
|
|
|
110
110
|
# libhxl
|
|
111
111
|
python-io-wrapper==0.3.1
|
|
112
112
|
# via libhxl
|
|
113
|
-
python-slugify==8.0.
|
|
113
|
+
python-slugify==8.0.4
|
|
114
114
|
# via frictionless
|
|
115
115
|
pyyaml==6.0.1
|
|
116
116
|
# via
|
|
@@ -124,13 +124,13 @@ requests==2.31.0
|
|
|
124
124
|
# frictionless
|
|
125
125
|
# libhxl
|
|
126
126
|
# requests-file
|
|
127
|
-
requests-file==
|
|
127
|
+
requests-file==2.0.0
|
|
128
128
|
# via hdx-python-utilities
|
|
129
129
|
rfc3986==2.0.0
|
|
130
130
|
# via frictionless
|
|
131
|
-
rich==13.7.
|
|
131
|
+
rich==13.7.1
|
|
132
132
|
# via typer
|
|
133
|
-
ruamel-yaml==0.18.
|
|
133
|
+
ruamel-yaml==0.18.6
|
|
134
134
|
# via hdx-python-utilities
|
|
135
135
|
ruamel-yaml-clib==0.2.8
|
|
136
136
|
# via ruamel-yaml
|
|
@@ -142,7 +142,6 @@ six==1.16.0
|
|
|
142
142
|
# via
|
|
143
143
|
# isodate
|
|
144
144
|
# python-dateutil
|
|
145
|
-
# requests-file
|
|
146
145
|
stringcase==1.2.0
|
|
147
146
|
# via frictionless
|
|
148
147
|
structlog==24.1.0
|
|
@@ -155,23 +154,23 @@ text-unidecode==1.3
|
|
|
155
154
|
# via python-slugify
|
|
156
155
|
typer[all]==0.9.0
|
|
157
156
|
# via frictionless
|
|
158
|
-
typing-extensions==4.
|
|
157
|
+
typing-extensions==4.10.0
|
|
159
158
|
# via
|
|
160
159
|
# frictionless
|
|
161
160
|
# pydantic
|
|
162
161
|
# pydantic-core
|
|
163
162
|
# typer
|
|
164
|
-
unidecode==1.3.
|
|
163
|
+
unidecode==1.3.8
|
|
165
164
|
# via
|
|
166
165
|
# libhxl
|
|
167
166
|
# pyphonetics
|
|
168
|
-
urllib3==2.1
|
|
167
|
+
urllib3==2.2.1
|
|
169
168
|
# via
|
|
170
169
|
# libhxl
|
|
171
170
|
# requests
|
|
172
171
|
validators==0.22.0
|
|
173
172
|
# via frictionless
|
|
174
|
-
virtualenv==20.25.
|
|
173
|
+
virtualenv==20.25.1
|
|
175
174
|
# via pre-commit
|
|
176
175
|
wheel==0.42.0
|
|
177
176
|
# via libhxl
|
|
@@ -179,7 +178,7 @@ xlrd==2.0.1
|
|
|
179
178
|
# via hdx-python-utilities
|
|
180
179
|
xlrd3==1.1.0
|
|
181
180
|
# via libhxl
|
|
182
|
-
xlsxwriter==3.
|
|
181
|
+
xlsxwriter==3.2.0
|
|
183
182
|
# via tableschema-to-template
|
|
184
183
|
xlwt==1.3.0
|
|
185
184
|
# via hdx-python-utilities
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from ._version import version as __version__ # noqa: F401
|
|
4
|
+
from hdx.utilities.dateparse import get_timestamp_from_datetime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_int_timestamp(date: datetime) -> int:
|
|
8
|
+
"""
|
|
9
|
+
Get integer timestamp from datetime object
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
date (datetime): datetime object
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
int: Integer timestamp
|
|
16
|
+
"""
|
|
17
|
+
return int(round(get_timestamp_from_datetime(date)))
|
|
@@ -58,7 +58,7 @@ class AdminLevel:
|
|
|
58
58
|
"admin_name_replacements", {}
|
|
59
59
|
)
|
|
60
60
|
self.admin_fuzzy_dont = admin_config.get("admin_fuzzy_dont", list())
|
|
61
|
-
self.pcodes =
|
|
61
|
+
self.pcodes = []
|
|
62
62
|
self.pcode_lengths = {}
|
|
63
63
|
self.name_to_pcode = {}
|
|
64
64
|
self.pcode_to_name = {}
|
|
@@ -634,7 +634,7 @@ class AdminLevel:
|
|
|
634
634
|
Returns:
|
|
635
635
|
List[str]: List of matches
|
|
636
636
|
"""
|
|
637
|
-
output =
|
|
637
|
+
output = []
|
|
638
638
|
for match in sorted(self.matches):
|
|
639
639
|
line = f"{match[0]} - {match[1]}: Matching ({match[4]}) {match[2]} to {match[3]} on map"
|
|
640
640
|
logger.info(line)
|
|
@@ -647,7 +647,7 @@ class AdminLevel:
|
|
|
647
647
|
Returns:
|
|
648
648
|
List[str]: List of ignored
|
|
649
649
|
"""
|
|
650
|
-
output =
|
|
650
|
+
output = []
|
|
651
651
|
for ignored in sorted(self.ignored):
|
|
652
652
|
if len(ignored) == 2:
|
|
653
653
|
line = f"{ignored[0]} - Ignored {ignored[1]}!"
|
|
@@ -663,7 +663,7 @@ class AdminLevel:
|
|
|
663
663
|
Returns:
|
|
664
664
|
List[str]: List of errors
|
|
665
665
|
"""
|
|
666
|
-
output =
|
|
666
|
+
output = []
|
|
667
667
|
for error in sorted(self.errors):
|
|
668
668
|
if len(error) == 2:
|
|
669
669
|
line = f"{error[0]} - Could not find {error[1]} in map names!"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Country location"""
|
|
2
|
+
|
|
2
3
|
import copy
|
|
3
4
|
import logging
|
|
4
5
|
import re
|
|
@@ -69,8 +70,8 @@ class Country:
|
|
|
69
70
|
_countriesdata = None
|
|
70
71
|
_ochaurl_default = "https://docs.google.com/spreadsheets/d/1NjSI2LaS3SqbgYc0HdD8oIb7lofGtiHgoKKATCpwVdY/export?format=csv&gid=1088874596"
|
|
71
72
|
_ochaurl = _ochaurl_default
|
|
72
|
-
_country_name_overrides =
|
|
73
|
-
_country_name_mappings =
|
|
73
|
+
_country_name_overrides = {}
|
|
74
|
+
_country_name_mappings = {}
|
|
74
75
|
|
|
75
76
|
@classmethod
|
|
76
77
|
def _add_countriesdata(cls, iso3: str, hxlcountry: hxl.Row) -> Dict:
|
|
@@ -131,24 +132,24 @@ class Country:
|
|
|
131
132
|
if regionname:
|
|
132
133
|
add_country_to_set("regioncodes2countries", regionid, iso3)
|
|
133
134
|
cls._countriesdata["regioncodes2names"][regionid] = regionname
|
|
134
|
-
cls._countriesdata["regionnames2codes"][
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
cls._countriesdata["regionnames2codes"][regionname.upper()] = (
|
|
136
|
+
regionid
|
|
137
|
+
)
|
|
137
138
|
if sub_regionname:
|
|
138
139
|
add_country_to_set("regioncodes2countries", sub_regionid, iso3)
|
|
139
|
-
cls._countriesdata["regioncodes2names"][
|
|
140
|
+
cls._countriesdata["regioncodes2names"][sub_regionid] = (
|
|
141
|
+
sub_regionname
|
|
142
|
+
)
|
|
143
|
+
cls._countriesdata["regionnames2codes"][sub_regionname.upper()] = (
|
|
140
144
|
sub_regionid
|
|
141
|
-
|
|
142
|
-
cls._countriesdata["regionnames2codes"][
|
|
143
|
-
sub_regionname.upper()
|
|
144
|
-
] = sub_regionid
|
|
145
|
+
)
|
|
145
146
|
if intermediate_regionname:
|
|
146
147
|
add_country_to_set(
|
|
147
148
|
"regioncodes2countries", intermediate_regionid, iso3
|
|
148
149
|
)
|
|
149
|
-
cls._countriesdata["regioncodes2names"][
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
cls._countriesdata["regioncodes2names"][intermediate_regionid] = (
|
|
151
|
+
intermediate_regionname
|
|
152
|
+
)
|
|
152
153
|
cls._countriesdata["regionnames2codes"][
|
|
153
154
|
intermediate_regionname.upper()
|
|
154
155
|
] = intermediate_regionid
|
|
@@ -167,21 +168,21 @@ class Country:
|
|
|
167
168
|
Returns:
|
|
168
169
|
None
|
|
169
170
|
"""
|
|
170
|
-
cls._countriesdata =
|
|
171
|
-
cls._countriesdata["countries"] =
|
|
172
|
-
cls._countriesdata["iso2iso3"] =
|
|
173
|
-
cls._countriesdata["m49iso3"] =
|
|
174
|
-
cls._countriesdata["countrynames2iso3"] =
|
|
175
|
-
cls._countriesdata["regioncodes2countries"] =
|
|
176
|
-
cls._countriesdata["regioncodes2names"] =
|
|
177
|
-
cls._countriesdata["regionnames2codes"] =
|
|
178
|
-
cls._countriesdata["aliases"] =
|
|
179
|
-
cls._countriesdata["currencies"] =
|
|
171
|
+
cls._countriesdata = {}
|
|
172
|
+
cls._countriesdata["countries"] = {}
|
|
173
|
+
cls._countriesdata["iso2iso3"] = {}
|
|
174
|
+
cls._countriesdata["m49iso3"] = {}
|
|
175
|
+
cls._countriesdata["countrynames2iso3"] = {}
|
|
176
|
+
cls._countriesdata["regioncodes2countries"] = {}
|
|
177
|
+
cls._countriesdata["regioncodes2names"] = {}
|
|
178
|
+
cls._countriesdata["regionnames2codes"] = {}
|
|
179
|
+
cls._countriesdata["aliases"] = {}
|
|
180
|
+
cls._countriesdata["currencies"] = {}
|
|
180
181
|
|
|
181
182
|
for key, value in cls._country_name_mappings.items():
|
|
182
|
-
cls._countriesdata["countrynames2iso3"][
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
cls._countriesdata["countrynames2iso3"][key.upper()] = (
|
|
184
|
+
value.upper()
|
|
185
|
+
)
|
|
185
186
|
|
|
186
187
|
for country in countries:
|
|
187
188
|
iso3 = country.get("#country+code+v_iso3")
|
|
@@ -891,4 +892,4 @@ class Country:
|
|
|
891
892
|
|
|
892
893
|
if exception is not None:
|
|
893
894
|
raise exception
|
|
894
|
-
return
|
|
895
|
+
return []
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""Currency conversion"""
|
|
2
|
+
|
|
2
3
|
import logging
|
|
4
|
+
from copy import copy
|
|
3
5
|
from datetime import datetime, timezone
|
|
4
6
|
from typing import Dict, Optional, Union
|
|
5
7
|
|
|
8
|
+
from . import get_int_timestamp
|
|
6
9
|
from hdx.utilities.dateparse import (
|
|
7
|
-
get_timestamp_from_datetime,
|
|
8
10
|
now_utc,
|
|
9
11
|
parse_date,
|
|
10
12
|
)
|
|
@@ -27,7 +29,7 @@ class Currency:
|
|
|
27
29
|
"""
|
|
28
30
|
|
|
29
31
|
_primary_rates_url = "https://query2.finance.yahoo.com/v8/finance/chart/{currency}=X?period1={date}&period2={date}&interval=1d&events=div%2Csplit&formatted=false&lang=en-US®ion=US&corsDomain=finance.yahoo.com"
|
|
30
|
-
_secondary_rates_url = "https://cdn.jsdelivr.net/
|
|
32
|
+
_secondary_rates_url = "https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/usd.min.json"
|
|
31
33
|
_secondary_historic_url = (
|
|
32
34
|
"https://codeforiati.org/imf-exchangerates/imf_exchangerates.csv"
|
|
33
35
|
)
|
|
@@ -44,19 +46,6 @@ class Currency:
|
|
|
44
46
|
_fixed_now = None
|
|
45
47
|
_threshold = 1.3
|
|
46
48
|
|
|
47
|
-
@classmethod
|
|
48
|
-
def _get_int_timestamp(cls, date: datetime) -> int:
|
|
49
|
-
"""
|
|
50
|
-
Get integer timestamp from datetime object
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
date (datetime): datetime object
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
int: Integer timestamp
|
|
57
|
-
"""
|
|
58
|
-
return int(round(get_timestamp_from_datetime(date)))
|
|
59
|
-
|
|
60
49
|
@classmethod
|
|
61
50
|
def setup(
|
|
62
51
|
cls,
|
|
@@ -69,6 +58,8 @@ class Currency:
|
|
|
69
58
|
no_historic: bool = False,
|
|
70
59
|
fixed_now: Optional[datetime] = None,
|
|
71
60
|
log_level: int = logging.DEBUG,
|
|
61
|
+
current_rates_cache: Dict = {"USD": 1},
|
|
62
|
+
historic_rates_cache: Dict = {},
|
|
72
63
|
) -> None:
|
|
73
64
|
"""
|
|
74
65
|
Setup the sources. If you wish to use a static fallback file by setting
|
|
@@ -85,13 +76,15 @@ class Currency:
|
|
|
85
76
|
no_historic (bool): Do not set up historic rates. Defaults to False.
|
|
86
77
|
fixed_now (Optional[datetime]): Use a fixed datetime for now. Defaults to None (use datetime.now()).
|
|
87
78
|
log_level (int): Level at which to log messages. Defaults to logging.DEBUG.
|
|
79
|
+
current_rates_cache (Dict): Pre-populate current rates cache with given values. Defaults to {"USD": 1}.
|
|
80
|
+
historic_rates_cache (Dict): Pre-populate historic rates cache with given values. Defaults to {}.
|
|
88
81
|
|
|
89
82
|
Returns:
|
|
90
83
|
None
|
|
91
84
|
"""
|
|
92
85
|
|
|
93
|
-
cls._cached_current_rates =
|
|
94
|
-
cls._cached_historic_rates =
|
|
86
|
+
cls._cached_current_rates = copy(current_rates_cache)
|
|
87
|
+
cls._cached_historic_rates = copy(historic_rates_cache)
|
|
95
88
|
cls._rates_api = primary_rates_url
|
|
96
89
|
cls._secondary_rates = None
|
|
97
90
|
cls._secondary_historic = None
|
|
@@ -131,10 +124,10 @@ class Currency:
|
|
|
131
124
|
filename="historic_rates.csv",
|
|
132
125
|
logstr="secondary historic exchange rates",
|
|
133
126
|
)
|
|
134
|
-
cls._secondary_historic =
|
|
127
|
+
cls._secondary_historic = {}
|
|
135
128
|
for row in iterator:
|
|
136
129
|
currency = row["Currency"]
|
|
137
|
-
date =
|
|
130
|
+
date = get_int_timestamp(parse_date(row["Date"]))
|
|
138
131
|
rate = float(row["Rate"])
|
|
139
132
|
dict_of_dicts_add(
|
|
140
133
|
cls._secondary_historic, currency, date, rate
|
|
@@ -281,7 +274,7 @@ class Currency:
|
|
|
281
274
|
else:
|
|
282
275
|
now = now_utc()
|
|
283
276
|
get_close = False
|
|
284
|
-
timestamp =
|
|
277
|
+
timestamp = get_int_timestamp(now)
|
|
285
278
|
else:
|
|
286
279
|
get_close = True
|
|
287
280
|
data = cls._get_primary_rates_data(currency, timestamp)
|
|
@@ -479,7 +472,7 @@ class Currency:
|
|
|
479
472
|
)
|
|
480
473
|
else:
|
|
481
474
|
date = date.astimezone(timezone.utc)
|
|
482
|
-
timestamp =
|
|
475
|
+
timestamp = get_int_timestamp(date)
|
|
483
476
|
if currency_data is not None:
|
|
484
477
|
fx_rate = currency_data.get(timestamp)
|
|
485
478
|
if fx_rate is not None:
|
|
@@ -11,7 +11,7 @@ class Phonetics(pyphonetics.RefinedSoundex):
|
|
|
11
11
|
possible_names: ListTuple,
|
|
12
12
|
name: str,
|
|
13
13
|
alternative_name: Optional[str] = None,
|
|
14
|
-
transform_possible_names: ListTuple[Callable] =
|
|
14
|
+
transform_possible_names: ListTuple[Callable] = [],
|
|
15
15
|
threshold: int = 2,
|
|
16
16
|
) -> Optional[int]:
|
|
17
17
|
"""
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from datetime import timezone
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
|
|
5
|
+
from . import get_int_timestamp
|
|
6
|
+
from hdx.utilities.typehint import ListTuple
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from data_bridges_client import ApiClient, Configuration, CurrencyApi
|
|
10
|
+
from data_bridges_client.exceptions import ApiException
|
|
11
|
+
from data_bridges_client.token import WfpApiToken
|
|
12
|
+
except ImportError:
|
|
13
|
+
WfpApiToken = None
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class WFPExchangeRates:
|
|
19
|
+
"""Obtain WFP official exchange rates. Requires WFP credentials amd
|
|
20
|
+
installation of the WFP extra eg. `pip install hdx-python-country[wfp]`
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
key: WFP API key
|
|
24
|
+
secret: WFP API secret
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, key: str, secret: str):
|
|
28
|
+
# Configure OAuth2 access token for authorization: default
|
|
29
|
+
self.token = WfpApiToken(api_key=key, api_secret=secret)
|
|
30
|
+
configuration = Configuration()
|
|
31
|
+
configuration.access_token = self.token.refresh()
|
|
32
|
+
api_client = ApiClient(configuration)
|
|
33
|
+
self.api_instance = CurrencyApi(api_client)
|
|
34
|
+
|
|
35
|
+
def get_currencies(self) -> List[str]:
|
|
36
|
+
"""Get list of currencies in WFP API
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
List[str]: List of currencies in WFP API
|
|
40
|
+
"""
|
|
41
|
+
currencies = []
|
|
42
|
+
for currencydto in self.api_instance.currency_list_get().items:
|
|
43
|
+
currencies.append(currencydto.name)
|
|
44
|
+
return currencies
|
|
45
|
+
|
|
46
|
+
def get_currency_historic_rates(self, currency: str) -> Dict[int, float]:
|
|
47
|
+
"""Get historic rates for currency from WFP API
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
currency (str): Currency
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Dict[int, float]: Mapping from timestamp to rate
|
|
54
|
+
"""
|
|
55
|
+
historic_rates = {}
|
|
56
|
+
page = 1
|
|
57
|
+
while True:
|
|
58
|
+
try:
|
|
59
|
+
usdquotations = (
|
|
60
|
+
self.api_instance.currency_usd_indirect_quotation_get(
|
|
61
|
+
currency_name=currency, page=page
|
|
62
|
+
).items
|
|
63
|
+
)
|
|
64
|
+
except ApiException as ex:
|
|
65
|
+
if ex.status not in (104, 401, 403):
|
|
66
|
+
raise
|
|
67
|
+
self.token.refresh()
|
|
68
|
+
usdquotations = (
|
|
69
|
+
self.api_instance.currency_usd_indirect_quotation_get(
|
|
70
|
+
currency_name=currency, page=page
|
|
71
|
+
).items
|
|
72
|
+
)
|
|
73
|
+
if not usdquotations:
|
|
74
|
+
break
|
|
75
|
+
for usdquotation in usdquotations:
|
|
76
|
+
if not usdquotation.is_official:
|
|
77
|
+
continue
|
|
78
|
+
date = usdquotation.var_date.replace(tzinfo=timezone.utc)
|
|
79
|
+
timestamp = get_int_timestamp(date)
|
|
80
|
+
historic_rates[timestamp] = usdquotation.value
|
|
81
|
+
page = page + 1
|
|
82
|
+
return historic_rates
|
|
83
|
+
|
|
84
|
+
def get_historic_rates(
|
|
85
|
+
self, currencies: ListTuple[str]
|
|
86
|
+
) -> Dict[str, Dict]:
|
|
87
|
+
"""Get historic rates for a list of currencies from WFP API
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
currencies (List[str]): List of currencies
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Dict[str, Dict]: Mapping from currency to mapping from timestamp to rate
|
|
94
|
+
"""
|
|
95
|
+
historic_rates = {}
|
|
96
|
+
for currency in currencies:
|
|
97
|
+
logger.info(f"Getting WFP historic rates for {currency}")
|
|
98
|
+
currency_historic_rates = self.get_currency_historic_rates(
|
|
99
|
+
currency
|
|
100
|
+
)
|
|
101
|
+
historic_rates[currency.upper()] = currency_historic_rates
|
|
102
|
+
return historic_rates
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Currency Tests"""
|
|
2
|
+
|
|
2
3
|
from os.path import join
|
|
3
4
|
|
|
4
5
|
import pytest
|
|
5
6
|
|
|
7
|
+
from hdx.location import get_int_timestamp
|
|
6
8
|
from hdx.location.currency import Currency, CurrencyError
|
|
7
9
|
from hdx.utilities.dateparse import parse_date
|
|
8
10
|
from hdx.utilities.downloader import Download
|
|
@@ -333,7 +335,7 @@ class TestCurrency:
|
|
|
333
335
|
}
|
|
334
336
|
],
|
|
335
337
|
}
|
|
336
|
-
timestamp =
|
|
338
|
+
timestamp = get_int_timestamp(parse_date("2017-02-15"))
|
|
337
339
|
assert Currency._get_adjclose(indicators, "NGN", timestamp) == 314.5
|
|
338
340
|
indicators = {
|
|
339
341
|
"adjclose": [{"adjclose": [33.13999938964844]}],
|
|
@@ -347,7 +349,7 @@ class TestCurrency:
|
|
|
347
349
|
}
|
|
348
350
|
],
|
|
349
351
|
}
|
|
350
|
-
timestamp =
|
|
352
|
+
timestamp = get_int_timestamp(parse_date("2015-12-15"))
|
|
351
353
|
assert Currency._get_adjclose(indicators, "COP", timestamp) is None
|
|
352
354
|
indicators = {
|
|
353
355
|
"adjclose": [{"adjclose": [605.5509643554688]}],
|
|
@@ -361,7 +363,7 @@ class TestCurrency:
|
|
|
361
363
|
}
|
|
362
364
|
],
|
|
363
365
|
}
|
|
364
|
-
timestamp =
|
|
366
|
+
timestamp = get_int_timestamp(parse_date("2022-04-14"))
|
|
365
367
|
assert (
|
|
366
368
|
Currency._get_adjclose(indicators, "XAF", timestamp)
|
|
367
369
|
== 605.5509643554688
|
|
@@ -378,7 +380,7 @@ class TestCurrency:
|
|
|
378
380
|
}
|
|
379
381
|
],
|
|
380
382
|
}
|
|
381
|
-
timestamp =
|
|
383
|
+
timestamp = get_int_timestamp(parse_date("2022-04-15"))
|
|
382
384
|
assert (
|
|
383
385
|
Currency._get_adjclose(indicators, "XAF", timestamp)
|
|
384
386
|
== 601.632568359375
|
|
@@ -395,7 +397,7 @@ class TestCurrency:
|
|
|
395
397
|
}
|
|
396
398
|
],
|
|
397
399
|
}
|
|
398
|
-
timestamp =
|
|
400
|
+
timestamp = get_int_timestamp(parse_date("2017-02-15"))
|
|
399
401
|
assert Currency._get_adjclose(indicators, "XXX", timestamp) == 3.145
|
|
400
402
|
|
|
401
403
|
Currency.setup(secondary_historic_url=secondary_historic_url)
|
|
@@ -411,7 +413,7 @@ class TestCurrency:
|
|
|
411
413
|
}
|
|
412
414
|
],
|
|
413
415
|
}
|
|
414
|
-
timestamp =
|
|
416
|
+
timestamp = get_int_timestamp(parse_date("2017-02-15"))
|
|
415
417
|
assert Currency._get_adjclose(indicators, "NGN", timestamp) == 314.5
|
|
416
418
|
indicators = {
|
|
417
419
|
"adjclose": [{"adjclose": [33.13999938964844]}],
|
|
@@ -425,7 +427,7 @@ class TestCurrency:
|
|
|
425
427
|
}
|
|
426
428
|
],
|
|
427
429
|
}
|
|
428
|
-
timestamp =
|
|
430
|
+
timestamp = get_int_timestamp(parse_date("2015-12-15"))
|
|
429
431
|
assert (
|
|
430
432
|
Currency._get_adjclose(indicators, "COP", timestamp)
|
|
431
433
|
== 3269.199951171875
|
|
@@ -442,7 +444,7 @@ class TestCurrency:
|
|
|
442
444
|
}
|
|
443
445
|
],
|
|
444
446
|
}
|
|
445
|
-
timestamp =
|
|
447
|
+
timestamp = get_int_timestamp(parse_date("2022-04-14"))
|
|
446
448
|
assert (
|
|
447
449
|
Currency._get_adjclose(indicators, "XAF", timestamp)
|
|
448
450
|
== 605.5509643554688
|
|
@@ -459,7 +461,7 @@ class TestCurrency:
|
|
|
459
461
|
}
|
|
460
462
|
],
|
|
461
463
|
}
|
|
462
|
-
timestamp =
|
|
464
|
+
timestamp = get_int_timestamp(parse_date("2022-04-15"))
|
|
463
465
|
assert (
|
|
464
466
|
Currency._get_adjclose(indicators, "XAF", timestamp)
|
|
465
467
|
== 601.632568359375
|
|
@@ -476,7 +478,7 @@ class TestCurrency:
|
|
|
476
478
|
}
|
|
477
479
|
],
|
|
478
480
|
}
|
|
479
|
-
timestamp =
|
|
481
|
+
timestamp = get_int_timestamp(parse_date("2017-02-15"))
|
|
480
482
|
assert Currency._get_adjclose(indicators, "XXX", timestamp) == 3.145
|
|
481
483
|
indicators = {
|
|
482
484
|
"adjclose": [{"adjclose": [33.13999938964844]}],
|
|
@@ -490,7 +492,7 @@ class TestCurrency:
|
|
|
490
492
|
}
|
|
491
493
|
],
|
|
492
494
|
}
|
|
493
|
-
timestamp =
|
|
495
|
+
timestamp = get_int_timestamp(parse_date("2015-12-15"))
|
|
494
496
|
assert Currency._get_adjclose(indicators, "COP", timestamp) == 3320.0
|
|
495
497
|
indicators = {
|
|
496
498
|
"adjclose": [{"adjclose": [33.13999938964844]}],
|
|
@@ -504,7 +506,7 @@ class TestCurrency:
|
|
|
504
506
|
}
|
|
505
507
|
],
|
|
506
508
|
}
|
|
507
|
-
timestamp =
|
|
509
|
+
timestamp = get_int_timestamp(parse_date("2015-12-15"))
|
|
508
510
|
assert (
|
|
509
511
|
Currency._get_adjclose(indicators, "COP", timestamp)
|
|
510
512
|
== 3313.999938964844
|
|
@@ -523,7 +525,7 @@ class TestCurrency:
|
|
|
523
525
|
}
|
|
524
526
|
],
|
|
525
527
|
}
|
|
526
|
-
timestamp =
|
|
528
|
+
timestamp = get_int_timestamp(parse_date("2015-12-15"))
|
|
527
529
|
assert (
|
|
528
530
|
Currency._get_adjclose(indicators, "COP", timestamp)
|
|
529
531
|
== 33.13999938964844
|
|
@@ -542,7 +544,7 @@ class TestCurrency:
|
|
|
542
544
|
}
|
|
543
545
|
],
|
|
544
546
|
}
|
|
545
|
-
timestamp =
|
|
547
|
+
timestamp = get_int_timestamp(parse_date("2015-12-15"))
|
|
546
548
|
assert (
|
|
547
549
|
Currency._get_adjclose(indicators, "COP", timestamp)
|
|
548
550
|
== 3124.504838709677
|
|
@@ -561,7 +563,7 @@ class TestCurrency:
|
|
|
561
563
|
}
|
|
562
564
|
],
|
|
563
565
|
}
|
|
564
|
-
timestamp =
|
|
566
|
+
timestamp = get_int_timestamp(parse_date("2015-12-15"))
|
|
565
567
|
assert Currency._get_adjclose(indicators, "COP", timestamp) == 3270
|
|
566
568
|
|
|
567
569
|
Currency._no_historic = True
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from os import environ
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from hdx.location import get_int_timestamp
|
|
6
|
+
from hdx.location.currency import Currency
|
|
7
|
+
from hdx.location.wfp_exchangerates import WfpApiToken, WFPExchangeRates
|
|
8
|
+
from hdx.utilities.dateparse import parse_date
|
|
9
|
+
|
|
10
|
+
if WfpApiToken is not None:
|
|
11
|
+
|
|
12
|
+
class TestWFPExchangeRates:
|
|
13
|
+
@pytest.fixture(scope="class")
|
|
14
|
+
def wfp_fx(self):
|
|
15
|
+
key = environ.get("WFP_KEY")
|
|
16
|
+
secret = environ.get("WFP_SECRET")
|
|
17
|
+
return WFPExchangeRates(key, secret)
|
|
18
|
+
|
|
19
|
+
@pytest.fixture(scope="class")
|
|
20
|
+
def currency(self):
|
|
21
|
+
return "afn"
|
|
22
|
+
|
|
23
|
+
@pytest.fixture(scope="class")
|
|
24
|
+
def date(self):
|
|
25
|
+
return parse_date("2020-02-20")
|
|
26
|
+
|
|
27
|
+
def test_get_currencies(self, wfp_fx):
|
|
28
|
+
currencies = wfp_fx.get_currencies()
|
|
29
|
+
assert len(currencies) == 126
|
|
30
|
+
|
|
31
|
+
def test_get_historic_rates(self, wfp_fx, currency, date):
|
|
32
|
+
assert (
|
|
33
|
+
Currency.get_historic_rate(currency, date) == 76.80000305175781
|
|
34
|
+
)
|
|
35
|
+
timestamp = get_int_timestamp(date)
|
|
36
|
+
historic_rates = wfp_fx.get_currency_historic_rates(currency)
|
|
37
|
+
assert historic_rates[timestamp] == 77.01
|
|
38
|
+
|
|
39
|
+
def test_get_all_historic_rates(self, wfp_fx, currency, date):
|
|
40
|
+
all_historic_rates = wfp_fx.get_historic_rates([currency])
|
|
41
|
+
Currency.setup(historic_rates_cache=all_historic_rates)
|
|
42
|
+
assert Currency.get_historic_rate(currency, date) == 77.01
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from ._version import version as __version__ # noqa: F401
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/global_pcode_lengths.csv
RENAMED
|
File without changes
|
{hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/global_pcodes_adm_1_2.csv
RENAMED
|
File without changes
|
{hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/fixtures/secondary_historic_rates.csv
RENAMED
|
File without changes
|
|
File without changes
|
{hdx_python_country-3.6.4 → hdx_python_country-3.6.6}/tests/hdx/location/Countries_UZB_Deleted.csv
RENAMED
|
File without changes
|
|
File without changes
|