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.
- {oda_data-2.5.0 → oda_data-2.7.0}/PKG-INFO +47 -20
- {oda_data-2.5.0 → oda_data-2.7.0}/README.md +42 -16
- oda_data-2.7.0/pyproject.toml +237 -0
- oda_data-2.7.0/src/oda_data/__init__.py +114 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/oecd.py +12 -10
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/representations.py +2 -2
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/sources.py +169 -123
- oda_data-2.7.0/src/oda_data/cache/__init__.py +38 -0
- oda_data-2.7.0/src/oda_data/cache/_migrate.py +388 -0
- oda_data-2.7.0/src/oda_data/cache/api.py +517 -0
- oda_data-2.7.0/src/oda_data/cache/config.py +114 -0
- oda_data-2.7.0/src/oda_data/cache/types.py +75 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/channels.py +8 -5
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/common.py +3 -3
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/validation.py +19 -8
- oda_data-2.7.0/src/oda_data/config.py +36 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/common.py +6 -5
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/crs_functions.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/oecd.py +25 -7
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/one.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/common.py +3 -3
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/dac1_indicators.json +87 -51
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/oecd.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/one.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/oecd.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/one.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/indicator.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/eu.py +10 -3
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/policy_markers.py +2 -2
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/sector_imputations.py +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/oda_data_indicators.csv +19 -17
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/flow_types.json +3 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/provider_groupings.json +2 -2
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/recipient_groupings.json +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/cache.py +244 -80
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/compatibility.py +7 -5
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/gni.py +2 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/create_mapping.py +4 -4
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/crs_names.json +4 -5
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/dac1_names.json +1 -1
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/dac2a_names.json +3 -3
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/sector_lists.py +2 -2
- oda_data-2.5.0/pyproject.toml +0 -134
- oda_data-2.5.0/src/oda_data/__init__.py +0 -59
- oda_data-2.5.0/src/oda_data/config.py +0 -17
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/api/constants.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/crs_channel_mapping.csv +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/dtypes.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/clean_data/schema.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/common.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/crs/crs_indicators.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac1/dac1_functions.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/common.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/dac2a_functions.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/dac2a/dac2a_indicators.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/indicators/research/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/logger.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_flow_types.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_modalities.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_policy_markers.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_purpose.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/crs_type_of_finance.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/dac1_aid_flow_types.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/dac2a_aid_type.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/indicators.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/key_columns.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/settings/v1_indicators_mapping.json +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/__init__.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/groupings.py +0 -0
- {oda_data-2.5.0 → oda_data-2.7.0}/src/oda_data/tools/names/__init__.py +0 -0
- {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:
|
|
3
|
-
Version: 2.
|
|
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.
|
|
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
|
[](https://pypi.org/project/oda_data/)
|
|
@@ -38,6 +39,7 @@ Description-Content-Type: text/markdown
|
|
|
38
39
|
[](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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
457
|
-
|
|
478
|
+
```python
|
|
479
|
+
from oda_data import cache
|
|
458
480
|
|
|
459
|
-
#
|
|
460
|
-
|
|
481
|
+
# Clear only the raw zip archives and let them re-download on next read:
|
|
482
|
+
cache.clear("raw")
|
|
461
483
|
|
|
462
|
-
#
|
|
463
|
-
|
|
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
|
[](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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
426
|
-
|
|
446
|
+
```python
|
|
447
|
+
from oda_data import cache
|
|
427
448
|
|
|
428
|
-
#
|
|
429
|
-
|
|
449
|
+
# Clear only the raw zip archives and let them re-download on next read:
|
|
450
|
+
cache.clear("raw")
|
|
430
451
|
|
|
431
|
-
#
|
|
432
|
-
|
|
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
|
+
]
|