oda-data 2.0.0__tar.gz → 2.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {oda_data-2.0.0 → oda_data-2.0.2}/PKG-INFO +3 -3
- {oda_data-2.0.0 → oda_data-2.0.2}/README.md +2 -2
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/__init__.py +5 -2
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/api/oecd.py +5 -5
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/api/representations.py +2 -2
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/api/sources.py +69 -27
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac1/dac1_functions.py +31 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/research/eu.py +9 -9
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/cache.py +3 -3
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/gni.py +4 -4
- {oda_data-2.0.0 → oda_data-2.0.2}/pyproject.toml +1 -1
- {oda_data-2.0.0 → oda_data-2.0.2}/LICENSE +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/.raw_data/README.md +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/api/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/api/constants.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/clean_data/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/clean_data/channels.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/clean_data/common.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/clean_data/crs_channel_mapping.csv +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/clean_data/dtypes.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/clean_data/schema.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/clean_data/validation.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/config.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/common.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/crs/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/crs/common.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/crs/crs_functions.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/crs/crs_indicators.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/crs/oecd.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/crs/one.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac1/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac1/common.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac1/dac1_indicators.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac1/oecd.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac1/one.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac2a/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac2a/common.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac2a/dac2a_functions.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac2a/dac2a_indicators.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac2a/oecd.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/dac2a/one.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/indicator.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/research/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/research/policy_markers.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/indicators/research/sector_imputations.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/logger.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/crs_flow_types.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/crs_modalities.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/crs_policy_markers.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/crs_purpose.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/crs_type_of_finance.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/dac1_aid_flow_types.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/dac2a_aid_type.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/flow_types.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/indicators.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/key_columns.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/provider_groupings.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/recipient_groupings.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/settings/v1_indicators_mapping.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/compatibility.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/groupings.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/names/__init__.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/names/add.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/names/create_mapping.py +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/names/crs_names.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/names/dac1_names.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/names/dac2a_names.json +0 -0
- {oda_data-2.0.0 → oda_data-2.0.2}/oda_data/tools/sector_lists.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: oda_data
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: A python package to work with Official Development Assistance data from the OECD DAC.
|
|
5
5
|
Author: Jorge Rivera
|
|
6
6
|
Author-email: jorge.rivera@one.org
|
|
@@ -49,10 +49,10 @@ the [issues page](https://github.com/ONEcampaign/oda_data_package/issues).
|
|
|
49
49
|
|
|
50
50
|
### Installation
|
|
51
51
|
|
|
52
|
-
The
|
|
52
|
+
The latest version of the package can be installed using pip:
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
pip install
|
|
55
|
+
pip install oda-data --upgrade
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
The package is compatible with Python 3.10 and above.
|
|
@@ -22,10 +22,10 @@ the [issues page](https://github.com/ONEcampaign/oda_data_package/issues).
|
|
|
22
22
|
|
|
23
23
|
### Installation
|
|
24
24
|
|
|
25
|
-
The
|
|
25
|
+
The latest version of the package can be installed using pip:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
pip install
|
|
28
|
+
pip install oda-data --upgrade
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
The package is compatible with Python 3.10 and above.
|
|
@@ -3,7 +3,7 @@ from importlib.metadata import version
|
|
|
3
3
|
__version__ = version("oda_data")
|
|
4
4
|
|
|
5
5
|
from oda_data import tools
|
|
6
|
-
from oda_reader import set_cache_dir
|
|
6
|
+
from oda_reader import set_cache_dir, disable_cache, enable_cache, clear_cache
|
|
7
7
|
from oda_data.api.oecd import OECDClient
|
|
8
8
|
from oda_data.api.sources import DAC1Data, DAC2AData, MultiSystemData, CRSData
|
|
9
9
|
from oda_data.indicators.research.policy_markers import bilateral_policy_marker
|
|
@@ -20,7 +20,7 @@ def set_data_path(path):
|
|
|
20
20
|
from pydeflate import set_pydeflate_path
|
|
21
21
|
|
|
22
22
|
"""Set the path to the data folder."""
|
|
23
|
-
global
|
|
23
|
+
global ODAPaths
|
|
24
24
|
|
|
25
25
|
ODAPaths.raw_data = Path(path).resolve()
|
|
26
26
|
set_pydeflate_path(ODAPaths.raw_data)
|
|
@@ -43,4 +43,7 @@ __all__ = [
|
|
|
43
43
|
"add_names_columns",
|
|
44
44
|
"add_gni_share_column",
|
|
45
45
|
"set_cache_dir",
|
|
46
|
+
"disable_cache",
|
|
47
|
+
"enable_cache",
|
|
48
|
+
"clear_cache",
|
|
46
49
|
]
|
|
@@ -13,7 +13,7 @@ from oda_data.api.constants import (
|
|
|
13
13
|
PRICES,
|
|
14
14
|
_EXCLUDE,
|
|
15
15
|
)
|
|
16
|
-
from oda_data.api.representations import
|
|
16
|
+
from oda_data.api.representations import _ODADict, _ODAList
|
|
17
17
|
from oda_data.api.sources import DAC1Data, DAC2AData, CRSData, MultiSystemData
|
|
18
18
|
from oda_data.clean_data import common as clean
|
|
19
19
|
from oda_data.clean_data.validation import validate_currency, validate_measure
|
|
@@ -228,18 +228,18 @@ class OECDClient:
|
|
|
228
228
|
def available_providers(cls) -> dict:
|
|
229
229
|
"""Returns a dictionary of available donor codes and their names"""
|
|
230
230
|
logger.info("Note that not all providers may be available for all indicators")
|
|
231
|
-
return
|
|
231
|
+
return _ODADict(provider_groupings()["all_official"])
|
|
232
232
|
|
|
233
233
|
@classmethod
|
|
234
234
|
def available_recipients(cls) -> dict:
|
|
235
235
|
"""Returns a dictionary of available recipient codes"""
|
|
236
236
|
logger.info("Note that not all recipients may be available for all indicators")
|
|
237
|
-
return
|
|
237
|
+
return _ODADict(recipient_groupings()["all_developing_countries_regions"])
|
|
238
238
|
|
|
239
239
|
@classmethod
|
|
240
240
|
def available_currencies(cls) -> list:
|
|
241
241
|
"""Returns a dictionary of available currencies"""
|
|
242
|
-
return
|
|
242
|
+
return _ODAList(CURRENCIES)
|
|
243
243
|
|
|
244
244
|
@classmethod
|
|
245
245
|
def available_indicators(cls) -> dict:
|
|
@@ -250,7 +250,7 @@ class OECDClient:
|
|
|
250
250
|
n: v for n, v in i.items() if n in ["name", "description", "sources"]
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
return
|
|
253
|
+
return _ODADict(indicators)
|
|
254
254
|
|
|
255
255
|
@classmethod
|
|
256
256
|
def export_available_indicators(cls, export_folder: str | Path) -> None:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
class
|
|
1
|
+
class _ODAList(list):
|
|
2
2
|
def __repr__(self):
|
|
3
3
|
# Return the elements with a line break between them
|
|
4
4
|
return "[\n" + ",\n".join(str(x) for x in self) + "\n]"
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class _ODADict(dict):
|
|
8
8
|
def __repr__(self):
|
|
9
9
|
# Return the elements with a line break between them
|
|
10
10
|
return "{\n" + ",\n".join(f"{k}: {v}" for k, v in self.items()) + "\n}"
|
|
@@ -2,6 +2,7 @@ from abc import abstractmethod
|
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
4
|
import pandas as pd
|
|
5
|
+
from cachetools import TTLCache
|
|
5
6
|
from oda_reader import (
|
|
6
7
|
download_crs,
|
|
7
8
|
bulk_download_crs,
|
|
@@ -10,6 +11,7 @@ from oda_reader import (
|
|
|
10
11
|
bulk_download_multisystem,
|
|
11
12
|
download_multisystem,
|
|
12
13
|
)
|
|
14
|
+
from oda_reader._cache import memory
|
|
13
15
|
|
|
14
16
|
from oda_data import config
|
|
15
17
|
from oda_data.clean_data.common import (
|
|
@@ -23,6 +25,7 @@ from oda_data.clean_data.validation import (
|
|
|
23
25
|
check_strings,
|
|
24
26
|
)
|
|
25
27
|
from oda_data.logger import logger
|
|
28
|
+
from oda_data.tools.cache import OnDiskCache, generate_param_hash
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
def _filters_to_query(filters: list[tuple[str, str, list]]) -> str:
|
|
@@ -45,13 +48,15 @@ class DACSource:
|
|
|
45
48
|
of data in the form of a pandas DataFrame.
|
|
46
49
|
"""
|
|
47
50
|
|
|
51
|
+
memory_cache = TTLCache(maxsize=20, ttl=6000)
|
|
52
|
+
disk_cache = OnDiskCache(config.ODAPaths.raw_data, ttl_seconds=86400)
|
|
53
|
+
|
|
48
54
|
def __init__(self):
|
|
49
55
|
self.de_providers = None
|
|
50
56
|
self.de_recipients = None
|
|
51
57
|
self.de_indicators = None
|
|
52
58
|
self.filters = None
|
|
53
59
|
self.de_sectors = None
|
|
54
|
-
self.refresh_data = False
|
|
55
60
|
|
|
56
61
|
def _init_filters(
|
|
57
62
|
self,
|
|
@@ -168,25 +173,48 @@ class DACSource:
|
|
|
168
173
|
f"Missing values in {column}: {', '.join(map(str, missing_values))}"
|
|
169
174
|
)
|
|
170
175
|
|
|
171
|
-
def
|
|
172
|
-
self,
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
def _get_read_filters(
|
|
177
|
+
self, additional_filters: Optional[list[tuple]] = None
|
|
178
|
+
) -> list[tuple[str, str, list]] | None:
|
|
179
|
+
filters = (
|
|
180
|
+
self.filters + additional_filters if additional_filters else self.filters
|
|
181
|
+
)
|
|
182
|
+
return filters or None
|
|
178
183
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
"""
|
|
184
|
+
def _get_cached_dataset(
|
|
185
|
+
self, param_hash: str, filters: list[tuple], columns: list[str]
|
|
186
|
+
) -> pd.DataFrame | None:
|
|
183
187
|
|
|
184
|
-
|
|
188
|
+
cached_df = self.memory_cache.get(param_hash)
|
|
185
189
|
|
|
186
|
-
if
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
if cached_df is None:
|
|
191
|
+
cached_df = self.disk_cache.load(
|
|
192
|
+
self.__class__.__name__, param_hash, filters, columns
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return cached_df
|
|
196
|
+
|
|
197
|
+
def _cache_dataset(self, param_hash: str, df: pd.DataFrame) -> None:
|
|
198
|
+
"""Caches the dataset in memory and on disk."""
|
|
199
|
+
self.memory_cache[param_hash] = df.copy(deep=True)
|
|
200
|
+
self.disk_cache.save(self.__class__.__name__, param_hash, df)
|
|
201
|
+
|
|
202
|
+
def _apply_query_and_cache(
|
|
203
|
+
self, df: pd.DataFrame, query: str | None, param_hash: str, bulk: bool
|
|
204
|
+
):
|
|
205
|
+
if bulk:
|
|
206
|
+
self._cache_dataset(param_hash=param_hash, df=df)
|
|
207
|
+
|
|
208
|
+
if query:
|
|
209
|
+
df = df.query(query)
|
|
210
|
+
|
|
211
|
+
if not bulk:
|
|
212
|
+
self._cache_dataset(param_hash=param_hash, df=df)
|
|
213
|
+
|
|
214
|
+
return df
|
|
215
|
+
|
|
216
|
+
def _bulk_hash(self) -> str:
|
|
217
|
+
return generate_param_hash(filters=[("bulk", "==", self.__class__.__name__)])
|
|
190
218
|
|
|
191
219
|
def read(
|
|
192
220
|
self,
|
|
@@ -205,21 +233,35 @@ class DACSource:
|
|
|
205
233
|
pd.DataFrame: The loaded dataset.
|
|
206
234
|
"""
|
|
207
235
|
# Create filters
|
|
208
|
-
filters = (
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
236
|
+
filters = self._get_read_filters(additional_filters=additional_filters)
|
|
237
|
+
|
|
238
|
+
# Generate a query string from the filters
|
|
239
|
+
query = _filters_to_query(filters) if filters else None
|
|
240
|
+
|
|
241
|
+
# Generate a hash string with the filters and the type of file
|
|
242
|
+
param_hash = (
|
|
243
|
+
self._bulk_hash()
|
|
244
|
+
if using_bulk_download
|
|
245
|
+
else generate_param_hash(filters=filters)
|
|
212
246
|
)
|
|
213
247
|
|
|
214
|
-
|
|
215
|
-
|
|
248
|
+
# If caching is not active, clear the cache
|
|
249
|
+
if not memory().store_backend:
|
|
250
|
+
self.disk_cache.cleanup(hash_str=param_hash, force=True)
|
|
251
|
+
self.memory_cache.clear()
|
|
216
252
|
|
|
217
|
-
|
|
253
|
+
# Check if the data is already cached in memory or on disk
|
|
254
|
+
df = self._get_cached_dataset(
|
|
255
|
+
param_hash=param_hash, filters=filters, columns=columns
|
|
256
|
+
)
|
|
218
257
|
|
|
219
|
-
|
|
258
|
+
# If not cached, download the data
|
|
259
|
+
if df is None:
|
|
260
|
+
df = self.download(bulk=using_bulk_download).pipe(clean_raw_df)
|
|
261
|
+
df = self._apply_query_and_cache(
|
|
262
|
+
df=df, query=query, param_hash=param_hash, bulk=using_bulk_download
|
|
263
|
+
)
|
|
220
264
|
|
|
221
|
-
if query:
|
|
222
|
-
df = df.query(query)
|
|
223
265
|
if columns:
|
|
224
266
|
df = df.filter(columns)
|
|
225
267
|
|
|
@@ -23,6 +23,37 @@ def official_oda(data: pd.DataFrame) -> pd.DataFrame:
|
|
|
23
23
|
return data.query(oda_query)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def official_oda_gni(data: pd.DataFrame) -> pd.DataFrame:
|
|
27
|
+
"""Filters the dataset to include only Official Development Assistance (ODA)
|
|
28
|
+
and computes the ratio of ODA to Gross National Income (GNI).
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
data: A pandas DataFrame containing aid data.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
A filtered pandas DataFrame with only official ODA rows.
|
|
35
|
+
"""
|
|
36
|
+
oda = official_oda(data)
|
|
37
|
+
|
|
38
|
+
gni = (
|
|
39
|
+
data.query("aidtype_code == 1")
|
|
40
|
+
.rename(columns={ODASchema.VALUE: "gni_value"})
|
|
41
|
+
.filter([ODASchema.YEAR, ODASchema.PROVIDER_CODE, "gni_value"])
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
df = oda.merge(gni, on=[ODASchema.YEAR, ODASchema.PROVIDER_CODE], how="left")
|
|
45
|
+
df[ODASchema.VALUE] = round(df[ODASchema.VALUE] / df["gni_value"], 6)
|
|
46
|
+
|
|
47
|
+
df = df.drop(columns=["gni_value"])
|
|
48
|
+
|
|
49
|
+
df[ODASchema.AIDTYPE_CODE] = 1010110101
|
|
50
|
+
df[ODASchema.AIDTYPE_NAME] = (
|
|
51
|
+
"Official Development Assistance, as a share of GNI (official definition)"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return df
|
|
55
|
+
|
|
56
|
+
|
|
26
57
|
def one_core_oda(data: pd.DataFrame) -> pd.DataFrame:
|
|
27
58
|
"""Computes ONE's Core ODA metric: ODA excluding in-donor spending
|
|
28
59
|
but including administrative costs.
|
|
@@ -115,28 +115,28 @@ def get_eui_oda_weights(
|
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
def get_eui_plus_bilateral_providers_indicator(
|
|
118
|
-
|
|
118
|
+
client_obj: OECDClient, indicator: str | list[str]
|
|
119
119
|
) -> pd.DataFrame:
|
|
120
120
|
"""Fetches indicator values with adjusted EU institution contributions.
|
|
121
121
|
|
|
122
122
|
Args:
|
|
123
|
-
|
|
123
|
+
client_obj: An `OECDClient` instance to fetch indicator data.
|
|
124
124
|
indicator: Indicator code or list of codes.
|
|
125
125
|
|
|
126
126
|
Returns:
|
|
127
127
|
A DataFrame containing indicator values with adjusted EU contributions.
|
|
128
128
|
"""
|
|
129
129
|
eui_weights = get_eui_oda_weights(
|
|
130
|
-
years=
|
|
131
|
-
providers=
|
|
132
|
-
measure=
|
|
133
|
-
use_bulk_download=
|
|
130
|
+
years=client_obj.years,
|
|
131
|
+
providers=client_obj.providers,
|
|
132
|
+
measure=client_obj.measure[0],
|
|
133
|
+
use_bulk_download=client_obj.use_bulk_download,
|
|
134
134
|
)
|
|
135
135
|
|
|
136
|
-
if 918 not in
|
|
137
|
-
|
|
136
|
+
if 918 not in client_obj.providers:
|
|
137
|
+
client_obj.providers.append(918)
|
|
138
138
|
|
|
139
|
-
data =
|
|
139
|
+
data = client_obj.get_indicators(indicator)
|
|
140
140
|
eui_mask = data[ODASchema.PROVIDER_CODE] == 918
|
|
141
141
|
|
|
142
142
|
data.loc[eui_mask, ODASchema.VALUE] = data.loc[
|
|
@@ -37,7 +37,7 @@ class OnDiskCache:
|
|
|
37
37
|
|
|
38
38
|
def get_file_path(self, dataset_name: str, param_hash: str) -> Path:
|
|
39
39
|
"""Returns the on-disk path for the given dataset and parameter hash."""
|
|
40
|
-
return self.base_dir / f"
|
|
40
|
+
return self.base_dir / f"{dataset_name}-{param_hash}.parquet"
|
|
41
41
|
|
|
42
42
|
def load(
|
|
43
43
|
self,
|
|
@@ -65,9 +65,9 @@ class OnDiskCache:
|
|
|
65
65
|
|
|
66
66
|
def cleanup(self, hash_str: Optional[str] = None, force: bool = False):
|
|
67
67
|
"""Removes expired cache files."""
|
|
68
|
-
pattern = f"
|
|
68
|
+
pattern = f"*{hash_str}*.parquet"
|
|
69
69
|
|
|
70
70
|
for file in self.base_dir.glob(pattern):
|
|
71
71
|
if self._is_expired(file) or force:
|
|
72
72
|
file.unlink(missing_ok=True)
|
|
73
|
-
logger.info(f"Deleted
|
|
73
|
+
logger.info(f"Deleted cache file: {file}")
|
|
@@ -36,22 +36,22 @@ def _get_eu27_gni_as_eu_institutions(gni_obj: OECDClient) -> pd.DataFrame:
|
|
|
36
36
|
)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def _get_gni_data(
|
|
39
|
+
def _get_gni_data(client_obj: OECDClient) -> pd.DataFrame:
|
|
40
40
|
"""Fetch GNI data and optionally include EU Institutions' aggregate.
|
|
41
41
|
|
|
42
42
|
Args:
|
|
43
|
-
|
|
43
|
+
client_obj: An OECDClient object for the main data context.
|
|
44
44
|
|
|
45
45
|
Returns:
|
|
46
46
|
A DataFrame with GNI values per provider and year.
|
|
47
47
|
"""
|
|
48
48
|
# Create a copy of the indicators object and set the measure to "net_disbursement"
|
|
49
|
-
gni_obj = copy(
|
|
49
|
+
gni_obj = copy(client_obj)
|
|
50
50
|
gni_obj.measure = ["net_disbursement"]
|
|
51
51
|
|
|
52
52
|
# Fetch GNI data for the specified indicators
|
|
53
53
|
gni_df = gni_obj.get_indicators("DAC1.40.1")
|
|
54
|
-
providers =
|
|
54
|
+
providers = client_obj.providers or []
|
|
55
55
|
|
|
56
56
|
# Check if EU Institutions (provider code 918) is in the list of providers
|
|
57
57
|
# If it is, aggregate GNI for EU27 countries and assign it to provider 918
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "oda_data"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.2"
|
|
4
4
|
description = "A python package to work with Official Development Assistance data from the OECD DAC."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Jorge Rivera", email = "jorge.rivera@one.org" }, { name = "Miguel Haro Ruiz", email = "miguel.haroruiz@one.org" }]
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|