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.
Files changed (70) hide show
  1. {oda_data-2.1.0 → oda_data-2.1.2}/PKG-INFO +1 -1
  2. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/__init__.py +3 -0
  3. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/sources.py +23 -5
  4. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/common.py +11 -3
  5. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/config.py +1 -1
  6. {oda_data-2.1.0 → oda_data-2.1.2}/pyproject.toml +1 -1
  7. {oda_data-2.1.0 → oda_data-2.1.2}/LICENSE +0 -0
  8. {oda_data-2.1.0 → oda_data-2.1.2}/README.md +0 -0
  9. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/.raw_data/README.md +0 -0
  10. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/__init__.py +0 -0
  11. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/constants.py +0 -0
  12. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/oecd.py +0 -0
  13. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/api/representations.py +0 -0
  14. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/__init__.py +0 -0
  15. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/channels.py +0 -0
  16. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/crs_channel_mapping.csv +0 -0
  17. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/dtypes.py +0 -0
  18. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/schema.py +0 -0
  19. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/clean_data/validation.py +0 -0
  20. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/__init__.py +0 -0
  21. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/common.py +0 -0
  22. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/__init__.py +0 -0
  23. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/common.py +0 -0
  24. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/crs_functions.py +0 -0
  25. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/crs_indicators.json +0 -0
  26. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/oecd.py +0 -0
  27. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/crs/one.py +0 -0
  28. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/__init__.py +0 -0
  29. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/common.py +0 -0
  30. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/dac1_functions.py +0 -0
  31. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/dac1_indicators.json +0 -0
  32. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/oecd.py +0 -0
  33. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac1/one.py +0 -0
  34. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/__init__.py +0 -0
  35. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/common.py +0 -0
  36. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/dac2a_functions.py +0 -0
  37. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/dac2a_indicators.json +0 -0
  38. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/oecd.py +0 -0
  39. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/dac2a/one.py +0 -0
  40. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/indicator.py +0 -0
  41. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/__init__.py +0 -0
  42. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/eu.py +0 -0
  43. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/policy_markers.py +0 -0
  44. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/indicators/research/sector_imputations.py +0 -0
  45. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/logger.py +0 -0
  46. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_flow_types.json +0 -0
  47. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_modalities.json +0 -0
  48. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_policy_markers.json +0 -0
  49. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_purpose.json +0 -0
  50. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/crs_type_of_finance.json +0 -0
  51. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/dac1_aid_flow_types.json +0 -0
  52. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/dac2a_aid_type.json +0 -0
  53. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/flow_types.json +0 -0
  54. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/indicators.json +0 -0
  55. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/key_columns.json +0 -0
  56. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/provider_groupings.json +0 -0
  57. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/recipient_groupings.json +0 -0
  58. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/settings/v1_indicators_mapping.json +0 -0
  59. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/__init__.py +0 -0
  60. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/cache.py +0 -0
  61. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/compatibility.py +0 -0
  62. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/gni.py +0 -0
  63. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/groupings.py +0 -0
  64. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/__init__.py +0 -0
  65. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/add.py +0 -0
  66. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/create_mapping.py +0 -0
  67. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/crs_names.json +0 -0
  68. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/dac1_names.json +0 -0
  69. {oda_data-2.1.0 → oda_data-2.1.2}/oda_data/tools/names/dac2a_names.json +0 -0
  70. {oda_data-2.1.0 → oda_data-2.1.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.1.0
3
+ Version: 2.1.2
4
4
  Summary: A python package to work with Official Development Assistance data from the OECD DAC.
5
5
  License: MIT
6
6
  Author: Jorge Rivera
@@ -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
- disk_cache = OnDiskCache(ODAPaths.raw_data, ttl_seconds=86400)
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 or (currency == "USD" and base_year is None):
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 = scripts / ".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"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "oda_data"
3
- version = "2.1.0"
3
+ version = "2.1.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 = [
File without changes
File without changes
File without changes
File without changes
File without changes