oda-data 2.1.0__tar.gz → 2.1.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.1.0 → oda_data-2.1.2}/PKG-INFO +1 -1
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/__init__.py +3 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/sources.py +23 -5
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/common.py +11 -3
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/config.py +1 -1
- {oda_data-2.1.0 → oda_data-2.1.2}/pyproject.toml +1 -1
- {oda_data-2.1.0 → oda_data-2.1.2}/LICENSE +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/README.md +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/.raw_data/README.md +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/constants.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/oecd.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/representations.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/channels.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/crs_channel_mapping.csv +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/dtypes.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/schema.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/validation.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/common.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/common.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/crs_functions.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/crs_indicators.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/oecd.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/one.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/common.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/dac1_functions.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/dac1_indicators.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/oecd.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/one.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/common.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/dac2a_functions.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/dac2a_indicators.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/oecd.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/one.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/indicator.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/eu.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/policy_markers.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/sector_imputations.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/logger.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_flow_types.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_modalities.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_policy_markers.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_purpose.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_type_of_finance.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/dac1_aid_flow_types.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/dac2a_aid_type.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/flow_types.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/indicators.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/key_columns.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/provider_groupings.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/recipient_groupings.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/v1_indicators_mapping.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/cache.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/compatibility.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/gni.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/groupings.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/__init__.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/add.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/create_mapping.py +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/crs_names.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/dac1_names.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/dac2a_names.json +0 -0
- {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/sector_lists.py +0 -0
|
@@ -29,6 +29,9 @@ def set_data_path(path):
|
|
|
29
29
|
global ODAPaths
|
|
30
30
|
|
|
31
31
|
ODAPaths.raw_data = Path(path).resolve()
|
|
32
|
+
# Create on explicit user request; avoids import-time side effects
|
|
33
|
+
ODAPaths.raw_data.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
ODAPaths.pydeflate = ODAPaths.raw_data / ".pydeflate"
|
|
32
35
|
set_pydeflate_path(ODAPaths.raw_data)
|
|
33
36
|
set_cache_dir(ODAPaths.raw_data)
|
|
34
37
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import Optional
|
|
4
|
+
import threading
|
|
4
5
|
|
|
5
6
|
import pandas as pd
|
|
6
7
|
from cachetools import TTLCache
|
|
@@ -15,7 +16,6 @@ from oda_reader import (
|
|
|
15
16
|
)
|
|
16
17
|
from oda_reader._cache import memory
|
|
17
18
|
|
|
18
|
-
from oda_data import config
|
|
19
19
|
from oda_data.clean_data.common import (
|
|
20
20
|
clean_raw_df,
|
|
21
21
|
convert_dot_stat_to_data_explorer_codes,
|
|
@@ -52,7 +52,10 @@ class Source:
|
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
54
|
memory_cache = TTLCache(maxsize=20, ttl=6000)
|
|
55
|
-
|
|
55
|
+
|
|
56
|
+
# Shared, process-wide disk cache and lock
|
|
57
|
+
_shared_disk_cache: Optional[OnDiskCache] = None
|
|
58
|
+
_shared_disk_cache_lock = threading.Lock()
|
|
56
59
|
|
|
57
60
|
def __init__(self):
|
|
58
61
|
self.de_providers = None
|
|
@@ -63,6 +66,24 @@ class Source:
|
|
|
63
66
|
self.schema = None
|
|
64
67
|
self._param_hash = None
|
|
65
68
|
|
|
69
|
+
@property
|
|
70
|
+
def disk_cache(self) -> OnDiskCache:
|
|
71
|
+
# Snapshot path to avoid inconsistency if it changes mid-check
|
|
72
|
+
current_raw = ODAPaths.raw_data
|
|
73
|
+
# Fast-path without lock (shared, process-wide cache)
|
|
74
|
+
dc = Source._shared_disk_cache
|
|
75
|
+
if dc is not None and dc.base_dir == current_raw:
|
|
76
|
+
return dc
|
|
77
|
+
|
|
78
|
+
# Slow-path with lock to ensure single initialization across threads
|
|
79
|
+
with Source._shared_disk_cache_lock:
|
|
80
|
+
dc = Source._shared_disk_cache
|
|
81
|
+
if dc is None or dc.base_dir != current_raw:
|
|
82
|
+
Source._shared_disk_cache = OnDiskCache(
|
|
83
|
+
current_raw, ttl_seconds=86400
|
|
84
|
+
)
|
|
85
|
+
return Source._shared_disk_cache
|
|
86
|
+
|
|
66
87
|
def _add_filter(self, column: str, predicate: str, value: str | int | list) -> None:
|
|
67
88
|
"""Adds a filter to the dataset, ensuring no duplicate columns.
|
|
68
89
|
|
|
@@ -122,7 +143,6 @@ class DACSource(Source):
|
|
|
122
143
|
"""
|
|
123
144
|
|
|
124
145
|
memory_cache = TTLCache(maxsize=20, ttl=6000)
|
|
125
|
-
disk_cache = OnDiskCache(ODAPaths.raw_data, ttl_seconds=86400)
|
|
126
146
|
|
|
127
147
|
def __init__(self):
|
|
128
148
|
super().__init__()
|
|
@@ -522,7 +542,6 @@ class AidDataSource(Source):
|
|
|
522
542
|
"""
|
|
523
543
|
|
|
524
544
|
memory_cache = TTLCache(maxsize=20, ttl=6000)
|
|
525
|
-
disk_cache = OnDiskCache(ODAPaths.raw_data, ttl_seconds=86400)
|
|
526
545
|
|
|
527
546
|
def __init__(self):
|
|
528
547
|
super().__init__()
|
|
@@ -565,7 +584,6 @@ class AidDataData(AidDataSource):
|
|
|
565
584
|
"""Class to handle the AidData data."""
|
|
566
585
|
|
|
567
586
|
memory_cache = TTLCache(maxsize=20, ttl=6000)
|
|
568
|
-
disk_cache = OnDiskCache(config.ODAPaths.raw_data, ttl_seconds=86400)
|
|
569
587
|
|
|
570
588
|
def __init__(
|
|
571
589
|
self,
|
|
@@ -12,8 +12,6 @@ from oda_data.clean_data.validation import validate_currency
|
|
|
12
12
|
from oda_data.config import ODAPaths
|
|
13
13
|
from oda_data.logger import logger
|
|
14
14
|
|
|
15
|
-
set_pydeflate_path(ODAPaths.raw_data)
|
|
16
|
-
|
|
17
15
|
|
|
18
16
|
def clean_column_name(column_name: str) -> str:
|
|
19
17
|
"""Clean a column name by removing spaces, special characters, and lowercasing.
|
|
@@ -140,10 +138,20 @@ def convert_units(
|
|
|
140
138
|
currency: str = "USD",
|
|
141
139
|
base_year: Optional[int] = None,
|
|
142
140
|
):
|
|
141
|
+
# Ensure pydeflate has the current data path and directory exists (lazy init)
|
|
142
|
+
try:
|
|
143
|
+
ODAPaths.raw_data.mkdir(parents=True, exist_ok=True)
|
|
144
|
+
except Exception:
|
|
145
|
+
# In read-only environments, let downstream functions surface meaningful errors
|
|
146
|
+
pass
|
|
147
|
+
set_pydeflate_path(ODAPaths.raw_data)
|
|
148
|
+
|
|
143
149
|
if indicator is None:
|
|
144
150
|
indicator = ""
|
|
145
151
|
|
|
146
|
-
if ".40." in indicator
|
|
152
|
+
if ((".40." in indicator) and ("DAC1.40.1" != indicator)) or (
|
|
153
|
+
currency == "USD" and base_year is None
|
|
154
|
+
):
|
|
147
155
|
return data.assign(currency=currency, prices="current")
|
|
148
156
|
|
|
149
157
|
elif base_year is None:
|
|
@@ -6,7 +6,7 @@ class ODAPaths:
|
|
|
6
6
|
|
|
7
7
|
project = Path(__file__).resolve().parent.parent
|
|
8
8
|
scripts = project / "oda_data"
|
|
9
|
-
raw_data =
|
|
9
|
+
raw_data = (Path.cwd() / ".raw_data").resolve()
|
|
10
10
|
pydeflate = raw_data / ".pydeflate"
|
|
11
11
|
indicators = scripts / "indicators"
|
|
12
12
|
names = scripts / "tools" / "names"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|