oda-data 2.5.0__tar.gz → 2.7.0__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 (77) hide show
  1. {oda_data-2.5.0 → oda_data-2.7.0}/PKG-INFO +47 -20
  2. {oda_data-2.5.0 → oda_data-2.7.0}/README.md +42 -16
  3. oda_data-2.7.0/pyproject.toml +237 -0
  4. oda_data-2.7.0/src/oda_data/__init__.py +114 -0
  5. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/oecd.py +12 -10
  6. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/representations.py +2 -2
  7. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/sources.py +169 -123
  8. oda_data-2.7.0/src/oda_data/cache/__init__.py +38 -0
  9. oda_data-2.7.0/src/oda_data/cache/_migrate.py +388 -0
  10. oda_data-2.7.0/src/oda_data/cache/api.py +517 -0
  11. oda_data-2.7.0/src/oda_data/cache/config.py +114 -0
  12. oda_data-2.7.0/src/oda_data/cache/types.py +75 -0
  13. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/channels.py +8 -5
  14. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/common.py +3 -3
  15. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/validation.py +19 -8
  16. oda_data-2.7.0/src/oda_data/config.py +36 -0
  17. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/common.py +6 -5
  18. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/crs_functions.py +1 -1
  19. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/oecd.py +25 -7
  20. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/one.py +1 -1
  21. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/common.py +3 -3
  22. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/dac1_indicators.json +87 -51
  23. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/oecd.py +1 -1
  24. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/one.py +1 -1
  25. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/oecd.py +1 -1
  26. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/one.py +1 -1
  27. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/indicator.py +1 -1
  28. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/eu.py +10 -3
  29. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/policy_markers.py +2 -2
  30. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/sector_imputations.py +1 -1
  31. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/oda_data_indicators.csv +19 -17
  32. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/flow_types.json +3 -1
  33. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/provider_groupings.json +2 -2
  34. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/recipient_groupings.json +1 -1
  35. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/cache.py +244 -80
  36. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/compatibility.py +7 -5
  37. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/gni.py +2 -0
  38. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/create_mapping.py +4 -4
  39. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/crs_names.json +4 -5
  40. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/dac1_names.json +1 -1
  41. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/dac2a_names.json +3 -3
  42. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/sector_lists.py +2 -2
  43. oda_data-2.5.0/pyproject.toml +0 -134
  44. oda_data-2.5.0/src/oda_data/__init__.py +0 -59
  45. oda_data-2.5.0/src/oda_data/config.py +0 -17
  46. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/__init__.py +0 -0
  47. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/constants.py +0 -0
  48. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/__init__.py +0 -0
  49. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/crs_channel_mapping.csv +0 -0
  50. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/dtypes.py +0 -0
  51. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/schema.py +0 -0
  52. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/__init__.py +0 -0
  53. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/common.py +0 -0
  54. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/__init__.py +0 -0
  55. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/crs_indicators.json +0 -0
  56. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/__init__.py +0 -0
  57. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/dac1_functions.py +0 -0
  58. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/__init__.py +0 -0
  59. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/common.py +0 -0
  60. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/dac2a_functions.py +0 -0
  61. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/dac2a_indicators.json +0 -0
  62. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/__init__.py +0 -0
  63. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/logger.py +0 -0
  64. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_flow_types.json +0 -0
  65. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_modalities.json +0 -0
  66. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_policy_markers.json +0 -0
  67. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_purpose.json +0 -0
  68. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_type_of_finance.json +0 -0
  69. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/dac1_aid_flow_types.json +0 -0
  70. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/dac2a_aid_type.json +0 -0
  71. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/indicators.json +0 -0
  72. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/key_columns.json +0 -0
  73. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/v1_indicators_mapping.json +0 -0
  74. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/__init__.py +0 -0
  75. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/groupings.py +0 -0
  76. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/__init__.py +0 -0
  77. {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/add.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
- Name: oda-data
3
- Version: 2.5.0
2
+ Name: oda_data
3
+ Version: 2.7.0
4
4
  Summary: A python package to work with Official Development Assistance data from the OECD DAC.
5
5
  Author: Jorge Rivera, Miguel Haro Ruiz
6
6
  Author-email: Jorge Rivera <jorge.rivera@one.org>, Miguel Haro Ruiz <miguel.haroruiz@one.org>
@@ -18,15 +18,16 @@ Classifier: Topic :: Scientific/Engineering
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Requires-Dist: cachetools>=6.2.0
20
20
  Requires-Dist: filelock>=3.20.0
21
- Requires-Dist: oda-reader>=1.4.1
21
+ Requires-Dist: oda-reader>=1.6.0
22
+ Requires-Dist: platformdirs>=4.0.0
22
23
  Requires-Dist: pandas[excel,parquet,performance]>=2.2.0
23
24
  Requires-Dist: pydeflate>=2.3.3
24
25
  Requires-Dist: reader>=3.18
25
26
  Requires-Dist: thefuzz>=0.22.1
26
27
  Requires-Python: >=3.11
27
- Project-URL: Documentation, https://github.com/ONEcampaign/oda_data_package
28
28
  Project-URL: Homepage, https://github.com/ONEcampaign/oda_data_package
29
29
  Project-URL: Repository, https://github.com/ONEcampaign/oda_data_package
30
+ Project-URL: Documentation, https://github.com/ONEcampaign/oda_data_package
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  [![pypi](https://img.shields.io/pypi/v/oda_data.svg)](https://pypi.org/project/oda_data/)
@@ -38,6 +39,7 @@ Description-Content-Type: text/markdown
38
39
  [![Downloads](https://static.pepy.tech/badge/oda-data)](https://pepy.tech/project/oda-data)
39
40
 
40
41
  # The ODA Data Package
42
+
41
43
  This is a Python package designed for accessing, processing, and analyzing Official Development Assistance (ODA) data from OECD DAC. With an intuitive API, it simplifies common tasks like retrieving ODA indicators, converting currencies, filtering data, and handling bulk downloads.
42
44
 
43
45
  **Note: This is the new version of the package (V2). This release includes many breaking changes and previous workflows
@@ -70,6 +72,7 @@ The package is compatible with Python 3.11 and above.
70
72
  Most users can get the data they need by using the `OECDClient` class.
71
73
 
72
74
  An object of this class can handle:
75
+
73
76
  - getting data for specific indicators (one or more)
74
77
  - filtering the data for specific donors, recipients(if relevant), years.
75
78
  - returning the data in a variety of currency/prices combinations.
@@ -159,6 +162,7 @@ OECDClient.export_available_indicators(export_folder="path/to/folder/")
159
162
  ```
160
163
 
161
164
  ### Providers
165
+
162
166
  You can get a dictionary with all available providers, with their code and name, by using the `.available_providers()` method:
163
167
 
164
168
  ```python
@@ -168,6 +172,7 @@ providers = OECDClient.available_providers()
168
172
  ```
169
173
 
170
174
  ### Recipients
175
+
171
176
  You can get a dictionary with all available recipients, with their code and name, by using the `.available_recipients()` method:
172
177
 
173
178
  ```python
@@ -177,6 +182,7 @@ recipients = OECDClient.available_recipients()
177
182
  ```
178
183
 
179
184
  ### Currencies
185
+
180
186
  You can get a dictionary with all available currencies, with their code and name, by using the `.available_currencies()` method:
181
187
 
182
188
  ```python
@@ -190,6 +196,7 @@ currencies = OECDClient.available_currencies()
190
196
  Different measures are available depending on the data source. Here's what each source supports:
191
197
 
192
198
  **DAC1 Measures:**
199
+
193
200
  - `commitment` - Total commitments
194
201
  - `commitment_grant` - Grant commitments only
195
202
  - `commitment_non_grant` - Non-grant commitments
@@ -201,10 +208,12 @@ Different measures are available depending on the data source. Here's what each
201
208
  - `received` - Amounts received
202
209
 
203
210
  **DAC2A Measures:**
211
+
204
212
  - `net_disbursement` - Net disbursements (default)
205
213
  - `gross_disbursement` - Gross disbursements
206
214
 
207
215
  **CRS Measures:**
216
+
208
217
  - `commitment` - Commitment amounts
209
218
  - `grant_equivalent` - Grant equivalent values
210
219
  - `gross_disbursement` - Gross disbursement amounts
@@ -214,16 +223,20 @@ Different measures are available depending on the data source. Here's what each
214
223
  - `export_credit` - Export credits
215
224
 
216
225
  **MultiSystem Measures:**
226
+
217
227
  - `commitment` - Commitments
218
228
  - `gross_disbursement` - Gross disbursements
219
229
 
220
230
  ## Accessing the data
231
+
221
232
  For more advanced users, you can use this package to get and work with different tables and databases from the OECD DAC.
222
233
 
223
234
  ### DAC 1
235
+
224
236
  The `DAC1Data` class can retrieve and return DAC 1 data.
225
237
 
226
238
  You can optionally specify:
239
+
227
240
  - years: to filter the data for specific years
228
241
  - providers: to filter the data for specific providers (based on their code).
229
242
  - indicators: to filter the data for a specific indicator (for DAC1 this means AIDTYPE_CODE)
@@ -231,6 +244,7 @@ You can optionally specify:
231
244
  Not specifying any or all of these parameters will return all the available data.
232
245
 
233
246
  After instantiating the object, you can call:
247
+
234
248
  - `download`: to download the data from the data-explorer API or the bulk download service. This method returns a DataFrame.
235
249
  - `read`: to read data as stored in the specified folder. If the data is not available, it will be downloaded.
236
250
 
@@ -270,11 +284,12 @@ data = dac1.read(
270
284
  )
271
285
  ```
272
286
 
273
-
274
287
  ### DAC 2A
288
+
275
289
  The `DAC2AData` class can retrieve and return DAC2a data.
276
290
 
277
291
  You can optionally specify:
292
+
278
293
  - years: to filter the data for specific years
279
294
  - providers: to filter the data for specific providers (based on their code).
280
295
  - recipients: to filter the data for specific recipients (based on their code).
@@ -283,6 +298,7 @@ You can optionally specify:
283
298
  Not specifying any or all of these parameters will return all the available data.
284
299
 
285
300
  After instantiating the object, you can call:
301
+
286
302
  - `download`: to download the data from the data-explorer API or the bulk download service. This method returns a DataFrame.
287
303
  - `read`: to read data as stored in the specified folder. If the data is not available, it will be downloaded.
288
304
 
@@ -332,9 +348,11 @@ data = dac2a.read(
332
348
  ```
333
349
 
334
350
  ### CRS
351
+
335
352
  The `CRSData` class can retrieve and return CRS data.
336
353
 
337
354
  You can optionally specify:
355
+
338
356
  - years: to filter the data for specific years
339
357
  - providers: to filter the data for specific providers (based on their code).
340
358
  - recipients: to filter the data for specific recipients (based on their code).
@@ -358,11 +376,12 @@ crs = CRSData(years=range(2010, 2024))
358
376
  data = crs.read(using_bulk_download=True)
359
377
  ```
360
378
 
361
-
362
379
  ### MultiSystem
380
+
363
381
  The `MultiSystemData` class can retrieve and return Providers Total Use of the Multilateral System data.
364
382
 
365
383
  You can optionally specify:
384
+
366
385
  - years: to filter the data for specific years
367
386
  - providers: to filter the data for specific providers (based on their code).
368
387
  - recipients: to filter the data for specific recipients (based on their code).
@@ -375,7 +394,6 @@ You can refer to the examples above for DAC1 and DAC2a to understand the usage o
375
394
  **Note**: given the speed and rate-limiting of the dac-explorer APIs, consider using the bulk option
376
395
  unless you're looking for something very specific.
377
396
 
378
-
379
397
  ## Utility Functions
380
398
 
381
399
  The package provides several utility functions to enhance and enrich your ODA data analysis:
@@ -448,21 +466,29 @@ dac_members = providers["dac_members"]
448
466
 
449
467
  ### Cache Management
450
468
 
451
- Control the package's caching behavior:
469
+ `oda_data` stores downloaded data in a per-OS, version-segmented directory
470
+ (`~/Library/Caches/oda-data/<version>/` on macOS, `~/.cache/oda-data/<version>/`
471
+ on Linux, and the equivalent `AppData\Local` path on Windows). The location can be
472
+ overridden with `oda_data.set_cache_root(path)` or the `ODA_DATA_CACHE_DIR`
473
+ environment variable. See [CACHING.md](CACHING.md) for full details on disk
474
+ locations, scopes, multi-process behavior, and migration from older versions.
452
475
 
453
- ```python
454
- from oda_data import clear_cache, disable_cache, enable_cache
476
+ The fastest recovery path for a corrupt or stale cache is:
455
477
 
456
- # Clear all cached data
457
- clear_cache()
478
+ ```python
479
+ from oda_data import cache
458
480
 
459
- # Temporarily disable caching (for development/testing)
460
- disable_cache()
481
+ # Clear only the raw zip archives and let them re-download on next read:
482
+ cache.clear("raw")
461
483
 
462
- # Re-enable caching
463
- enable_cache()
484
+ # Or wipe everything:
485
+ cache.clear("all")
464
486
  ```
465
487
 
488
+ The legacy helpers `clear_cache()`, `disable_cache()`, and `enable_cache()` continue
489
+ to work and are thin wrappers over `cache.clear("all")`, `cache.disable_cache("all")`,
490
+ and `cache.enable_cache("all")` respectively.
491
+
466
492
  ### Compatibility with Version 1.x
467
493
 
468
494
  For users migrating from v1.x, a compatibility layer is available:
@@ -534,11 +560,12 @@ data = aiddata.read()
534
560
  ## Key features
535
561
 
536
562
  - **Speed up analysis** - The package handles downloading, cleaning and loading all the data, so you can focus on the
537
- analysis.
563
+ analysis.
538
564
  - **Get data in the currency and prices you need** - ODA data is only available in US dollars (current or constant
539
- prices) and local currency units (current prices). The package allows you to view the data in US dollars, Euros,
540
- British Pounds and Canadian dollars, in both current and constant prices. We can add any other DAC currency if you
541
- request it via the [issues page](https://github.com/ONEcampaign/oda_data_package/issues)
565
+ prices) and local currency units (current prices). The package allows you to view the data in US dollars, Euros,
566
+ British Pounds and Canadian dollars, in both current and constant prices. We can add any other DAC currency if you
567
+ request it via the [issues page](https://github.com/ONEcampaign/oda_data_package/issues)
542
568
 
543
569
  ## Contributing
570
+
544
571
  Interested in contributing to the package? Please reach out.
@@ -7,6 +7,7 @@
7
7
  [![Downloads](https://static.pepy.tech/badge/oda-data)](https://pepy.tech/project/oda-data)
8
8
 
9
9
  # The ODA Data Package
10
+
10
11
  This is a Python package designed for accessing, processing, and analyzing Official Development Assistance (ODA) data from OECD DAC. With an intuitive API, it simplifies common tasks like retrieving ODA indicators, converting currencies, filtering data, and handling bulk downloads.
11
12
 
12
13
  **Note: This is the new version of the package (V2). This release includes many breaking changes and previous workflows
@@ -39,6 +40,7 @@ The package is compatible with Python 3.11 and above.
39
40
  Most users can get the data they need by using the `OECDClient` class.
40
41
 
41
42
  An object of this class can handle:
43
+
42
44
  - getting data for specific indicators (one or more)
43
45
  - filtering the data for specific donors, recipients(if relevant), years.
44
46
  - returning the data in a variety of currency/prices combinations.
@@ -128,6 +130,7 @@ OECDClient.export_available_indicators(export_folder="path/to/folder/")
128
130
  ```
129
131
 
130
132
  ### Providers
133
+
131
134
  You can get a dictionary with all available providers, with their code and name, by using the `.available_providers()` method:
132
135
 
133
136
  ```python
@@ -137,6 +140,7 @@ providers = OECDClient.available_providers()
137
140
  ```
138
141
 
139
142
  ### Recipients
143
+
140
144
  You can get a dictionary with all available recipients, with their code and name, by using the `.available_recipients()` method:
141
145
 
142
146
  ```python
@@ -146,6 +150,7 @@ recipients = OECDClient.available_recipients()
146
150
  ```
147
151
 
148
152
  ### Currencies
153
+
149
154
  You can get a dictionary with all available currencies, with their code and name, by using the `.available_currencies()` method:
150
155
 
151
156
  ```python
@@ -159,6 +164,7 @@ currencies = OECDClient.available_currencies()
159
164
  Different measures are available depending on the data source. Here's what each source supports:
160
165
 
161
166
  **DAC1 Measures:**
167
+
162
168
  - `commitment` - Total commitments
163
169
  - `commitment_grant` - Grant commitments only
164
170
  - `commitment_non_grant` - Non-grant commitments
@@ -170,10 +176,12 @@ Different measures are available depending on the data source. Here's what each
170
176
  - `received` - Amounts received
171
177
 
172
178
  **DAC2A Measures:**
179
+
173
180
  - `net_disbursement` - Net disbursements (default)
174
181
  - `gross_disbursement` - Gross disbursements
175
182
 
176
183
  **CRS Measures:**
184
+
177
185
  - `commitment` - Commitment amounts
178
186
  - `grant_equivalent` - Grant equivalent values
179
187
  - `gross_disbursement` - Gross disbursement amounts
@@ -183,16 +191,20 @@ Different measures are available depending on the data source. Here's what each
183
191
  - `export_credit` - Export credits
184
192
 
185
193
  **MultiSystem Measures:**
194
+
186
195
  - `commitment` - Commitments
187
196
  - `gross_disbursement` - Gross disbursements
188
197
 
189
198
  ## Accessing the data
199
+
190
200
  For more advanced users, you can use this package to get and work with different tables and databases from the OECD DAC.
191
201
 
192
202
  ### DAC 1
203
+
193
204
  The `DAC1Data` class can retrieve and return DAC 1 data.
194
205
 
195
206
  You can optionally specify:
207
+
196
208
  - years: to filter the data for specific years
197
209
  - providers: to filter the data for specific providers (based on their code).
198
210
  - indicators: to filter the data for a specific indicator (for DAC1 this means AIDTYPE_CODE)
@@ -200,6 +212,7 @@ You can optionally specify:
200
212
  Not specifying any or all of these parameters will return all the available data.
201
213
 
202
214
  After instantiating the object, you can call:
215
+
203
216
  - `download`: to download the data from the data-explorer API or the bulk download service. This method returns a DataFrame.
204
217
  - `read`: to read data as stored in the specified folder. If the data is not available, it will be downloaded.
205
218
 
@@ -239,11 +252,12 @@ data = dac1.read(
239
252
  )
240
253
  ```
241
254
 
242
-
243
255
  ### DAC 2A
256
+
244
257
  The `DAC2AData` class can retrieve and return DAC2a data.
245
258
 
246
259
  You can optionally specify:
260
+
247
261
  - years: to filter the data for specific years
248
262
  - providers: to filter the data for specific providers (based on their code).
249
263
  - recipients: to filter the data for specific recipients (based on their code).
@@ -252,6 +266,7 @@ You can optionally specify:
252
266
  Not specifying any or all of these parameters will return all the available data.
253
267
 
254
268
  After instantiating the object, you can call:
269
+
255
270
  - `download`: to download the data from the data-explorer API or the bulk download service. This method returns a DataFrame.
256
271
  - `read`: to read data as stored in the specified folder. If the data is not available, it will be downloaded.
257
272
 
@@ -301,9 +316,11 @@ data = dac2a.read(
301
316
  ```
302
317
 
303
318
  ### CRS
319
+
304
320
  The `CRSData` class can retrieve and return CRS data.
305
321
 
306
322
  You can optionally specify:
323
+
307
324
  - years: to filter the data for specific years
308
325
  - providers: to filter the data for specific providers (based on their code).
309
326
  - recipients: to filter the data for specific recipients (based on their code).
@@ -327,11 +344,12 @@ crs = CRSData(years=range(2010, 2024))
327
344
  data = crs.read(using_bulk_download=True)
328
345
  ```
329
346
 
330
-
331
347
  ### MultiSystem
348
+
332
349
  The `MultiSystemData` class can retrieve and return Providers Total Use of the Multilateral System data.
333
350
 
334
351
  You can optionally specify:
352
+
335
353
  - years: to filter the data for specific years
336
354
  - providers: to filter the data for specific providers (based on their code).
337
355
  - recipients: to filter the data for specific recipients (based on their code).
@@ -344,7 +362,6 @@ You can refer to the examples above for DAC1 and DAC2a to understand the usage o
344
362
  **Note**: given the speed and rate-limiting of the dac-explorer APIs, consider using the bulk option
345
363
  unless you're looking for something very specific.
346
364
 
347
-
348
365
  ## Utility Functions
349
366
 
350
367
  The package provides several utility functions to enhance and enrich your ODA data analysis:
@@ -417,21 +434,29 @@ dac_members = providers["dac_members"]
417
434
 
418
435
  ### Cache Management
419
436
 
420
- Control the package's caching behavior:
437
+ `oda_data` stores downloaded data in a per-OS, version-segmented directory
438
+ (`~/Library/Caches/oda-data/<version>/` on macOS, `~/.cache/oda-data/<version>/`
439
+ on Linux, and the equivalent `AppData\Local` path on Windows). The location can be
440
+ overridden with `oda_data.set_cache_root(path)` or the `ODA_DATA_CACHE_DIR`
441
+ environment variable. See [CACHING.md](CACHING.md) for full details on disk
442
+ locations, scopes, multi-process behavior, and migration from older versions.
421
443
 
422
- ```python
423
- from oda_data import clear_cache, disable_cache, enable_cache
444
+ The fastest recovery path for a corrupt or stale cache is:
424
445
 
425
- # Clear all cached data
426
- clear_cache()
446
+ ```python
447
+ from oda_data import cache
427
448
 
428
- # Temporarily disable caching (for development/testing)
429
- disable_cache()
449
+ # Clear only the raw zip archives and let them re-download on next read:
450
+ cache.clear("raw")
430
451
 
431
- # Re-enable caching
432
- enable_cache()
452
+ # Or wipe everything:
453
+ cache.clear("all")
433
454
  ```
434
455
 
456
+ The legacy helpers `clear_cache()`, `disable_cache()`, and `enable_cache()` continue
457
+ to work and are thin wrappers over `cache.clear("all")`, `cache.disable_cache("all")`,
458
+ and `cache.enable_cache("all")` respectively.
459
+
435
460
  ### Compatibility with Version 1.x
436
461
 
437
462
  For users migrating from v1.x, a compatibility layer is available:
@@ -503,11 +528,12 @@ data = aiddata.read()
503
528
  ## Key features
504
529
 
505
530
  - **Speed up analysis** - The package handles downloading, cleaning and loading all the data, so you can focus on the
506
- analysis.
531
+ analysis.
507
532
  - **Get data in the currency and prices you need** - ODA data is only available in US dollars (current or constant
508
- prices) and local currency units (current prices). The package allows you to view the data in US dollars, Euros,
509
- British Pounds and Canadian dollars, in both current and constant prices. We can add any other DAC currency if you
510
- request it via the [issues page](https://github.com/ONEcampaign/oda_data_package/issues)
533
+ prices) and local currency units (current prices). The package allows you to view the data in US dollars, Euros,
534
+ British Pounds and Canadian dollars, in both current and constant prices. We can add any other DAC currency if you
535
+ request it via the [issues page](https://github.com/ONEcampaign/oda_data_package/issues)
511
536
 
512
537
  ## Contributing
538
+
513
539
  Interested in contributing to the package? Please reach out.
@@ -0,0 +1,237 @@
1
+ [project]
2
+ name = "oda_data"
3
+ version = "2.7.0"
4
+ description = "A python package to work with Official Development Assistance data from the OECD DAC."
5
+ requires-python = ">=3.11"
6
+
7
+ license = {text = "MIT"}
8
+ readme = "README.md"
9
+ authors = [
10
+ {name = "Jorge Rivera", email = "jorge.rivera@one.org"},
11
+ {name = "Miguel Haro Ruiz", email = "miguel.haroruiz@one.org"}
12
+ ]
13
+
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: Science/Research",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Topic :: Scientific/Engineering",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ ]
27
+
28
+ dependencies = [
29
+ "cachetools>=6.2.0",
30
+ "filelock>=3.20.0",
31
+ "oda-reader>=1.6.0",
32
+ "platformdirs>=4.0.0",
33
+ "pandas[excel,parquet,performance]>=2.2.0",
34
+ "pydeflate>=2.3.3",
35
+ "reader>=3.18",
36
+ "thefuzz>=0.22.1",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/ONEcampaign/oda_data_package"
41
+ Repository = "https://github.com/ONEcampaign/oda_data_package"
42
+ Documentation = "https://github.com/ONEcampaign/oda_data_package"
43
+
44
+ [build-system]
45
+ requires = ["uv_build>=0.11.8,<0.12"]
46
+ build-backend = "uv_build"
47
+
48
+ [dependency-groups]
49
+ dev = [
50
+ "pre-commit>=4.5.0",
51
+ "ruff>=0.14.9",
52
+ "ty>=0.0.33",
53
+ "mkdocs-material>=9.7.0",
54
+ ]
55
+ test = [
56
+ "pytest>=8.0.0",
57
+ "pytest-mock>=3.12.0",
58
+ "pytest-cov>=4.1.0",
59
+ "pytest-xdist>=3.5.0",
60
+ "freezegun>=1.4.0",
61
+ ]
62
+
63
+ [tool.ruff]
64
+ # Set the maximum line length
65
+ line-length = 88
66
+
67
+ # Target Python 3.11+
68
+ target-version = "py311"
69
+
70
+ # Lint/format notebooks too
71
+ extend-include = ["*.ipynb"]
72
+
73
+ # Exclude common directories
74
+ exclude = [
75
+ ".git",
76
+ ".venv",
77
+ "venv",
78
+ "__pycache__",
79
+ "build",
80
+ "dist",
81
+ "*.egg-info",
82
+ ".pytest_cache",
83
+ "htmlcov",
84
+ ]
85
+
86
+ [tool.ruff.lint]
87
+ # Enable recommended rules plus extras
88
+ select = [
89
+ "E", # pycodestyle errors
90
+ "W", # pycodestyle warnings
91
+ "F", # pyflakes
92
+ "I", # isort
93
+ "N", # pep8-naming
94
+ "UP", # pyupgrade
95
+ "B", # flake8-bugbear
96
+ "C4", # flake8-comprehensions
97
+ "SIM", # flake8-simplify
98
+ "PL", # pylint
99
+ "RUF", # ruff-specific rules
100
+ "ERA", # eradicate (commented-out code)
101
+ "PERF", # perflint
102
+ "ANN", # flake8-annotations (require type hints on public APIs)
103
+ ]
104
+
105
+ # Ignore specific rules that might be too strict
106
+ ignore = [
107
+ "E501", # Line too long (handled by formatter)
108
+ "PLR0913", # Too many arguments
109
+ "PLR0912", # Too many branches
110
+ "PLR0914", # Too many locals
111
+ "PLR0915", # Too many statements
112
+ "PLR2004", # Magic value used in comparison
113
+ "PLC0415", # Import outside top-level (used to avoid circular imports)
114
+ "ANN401", # Allow `Any` in typed signatures
115
+ ]
116
+
117
+ # Allow autofix for all enabled rules
118
+ fixable = ["ALL"]
119
+ unfixable = []
120
+
121
+ [tool.ruff.lint.per-file-ignores]
122
+ # Allow test files to have longer lines and more assertions
123
+ "tests/**/*.py" = ["ANN", "E501", "PLR2004", "RUF002", "RUF003", "PLW0603", "ERA001"] # Tests don't need annotations (ANN); allow × in comments/docstrings; PLW0603 for spawn-pool worker globals; ERA001 for intentional commented-out fixtures
124
+ # Allow global variable usage in __init__.py (architectural decision)
125
+ "src/oda_data/__init__.py" = ["PLW0603", "PLW0602", "F811"]
126
+ # Lazy module-level state (override flag, chained-root cache, auto-migrate gate, 5GB warning latch).
127
+ "src/oda_data/cache/config.py" = ["PLW0603"]
128
+ "src/oda_data/cache/api.py" = ["PLW0603"]
129
+ # Allow tmpdir reassignment pattern (Path conversion)
130
+ "src/oda_data/tools/cache.py" = ["PLW2901"]
131
+ # Existing complexity in OECDClient._apply_filters — out of scope for refactor here.
132
+ "src/oda_data/api/oecd.py" = ["PLR0912"]
133
+ # Allow loop variable binding patterns (intentional for lambda closures)
134
+ "src/oda_data/indicators/crs/crs_functions.py" = ["B023"]
135
+ "src/oda_data/indicators/research/sector_imputations.py" = ["B023"]
136
+ # Allow mixedCase variable names matching official sector code names
137
+ "src/oda_data/tools/sector_lists.py" = ["N816"]
138
+
139
+ [tool.ruff.lint.pydocstyle]
140
+ convention = "google"
141
+
142
+ [tool.ruff.format]
143
+ # Use double quotes for strings
144
+ quote-style = "double"
145
+
146
+ # Use spaces for indentation
147
+ indent-style = "space"
148
+
149
+ # Like Black, respect magic trailing commas
150
+ skip-magic-trailing-comma = false
151
+
152
+ # Like Black, automatically detect line endings
153
+ line-ending = "auto"
154
+
155
+ [tool.ty.environment]
156
+ python-version = "3.11"
157
+
158
+ [tool.ty.src]
159
+ include = ["src/oda_data"]
160
+
161
+ # NOTE: The following two sections are borrowed from the bblocks-projects
162
+ # `project` preset (the `package` preset omits them). This is a pandas/numpy-
163
+ # heavy package, so the same false-positive cascade from those libraries'
164
+ # incomplete stubs applies here. Kept as a deliberate divergence.
165
+ [tool.ty.analysis]
166
+ # Replace pandas / numpy type information with `Any` to eliminate the cascade
167
+ # of false positives from those libraries' incomplete or absent stubs without
168
+ # disabling type checking on our own code.
169
+ # https://docs.astral.sh/ty/reference/configuration/
170
+ replace-imports-with-any = [
171
+ "pandas",
172
+ "pandas.**",
173
+ "numpy",
174
+ "numpy.**",
175
+ ]
176
+
177
+ [tool.ty.rules]
178
+ # These warn-by-default rules fire frequently on dynamic dataframe / dict
179
+ # patterns common in this codebase. Demoted to ignore.
180
+ possibly-missing-attribute = "ignore"
181
+ possibly-unresolved-reference = "ignore"
182
+
183
+ [tool.pytest.ini_options]
184
+ # Test discovery patterns
185
+ testpaths = ["tests"]
186
+ python_files = ["test_*.py"]
187
+ python_classes = ["Test*"]
188
+ python_functions = ["test_*"]
189
+
190
+ # Test execution options. Integration/network tests are deselected by default.
191
+ addopts = """
192
+ -v
193
+ --strict-markers
194
+ --tb=short
195
+ --cov=src/oda_data
196
+ --cov-report=term-missing
197
+ --cov-report=html
198
+ --cov-branch
199
+ -m "not integration and not network"
200
+ """
201
+
202
+ # Custom markers for organizing tests
203
+ markers = [
204
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
205
+ "integration: marks tests that call real OECD API (deselected by default)",
206
+ "network: marks tests requiring live network access (opt-in via RUN_NETWORK_TESTS=1; deselected by default)",
207
+ "unit: marks tests as unit tests",
208
+ "cache: marks tests related to caching functionality",
209
+ "validation: marks tests related to input validation",
210
+ "cleaning: marks tests related to data cleaning",
211
+ ]
212
+
213
+ # Directories not searched for tests
214
+ norecursedirs = [".git", ".venv", "venv", "__pycache__", "*.egg-info", ".pytest_cache", "htmlcov"]
215
+
216
+ [tool.coverage.run]
217
+ source = ["src/oda_data"]
218
+ branch = true
219
+ omit = [
220
+ "*/tests/*",
221
+ "*/__init__.py",
222
+ "*/config.py",
223
+ "*/logger.py",
224
+ ]
225
+
226
+ [tool.coverage.report]
227
+ precision = 2
228
+ show_missing = true
229
+ exclude_lines = [
230
+ "pragma: no cover",
231
+ "def __repr__",
232
+ "raise AssertionError",
233
+ "raise NotImplementedError",
234
+ "if __name__ == .__main__.:",
235
+ "if TYPE_CHECKING:",
236
+ "@abstractmethod",
237
+ ]