oda-data 2.1.2__tar.gz → 2.2.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 (71) hide show
  1. {oda_data-2.1.2 → oda_data-2.2.2}/PKG-INFO +11 -18
  2. oda_data-2.2.2/pyproject.toml +35 -0
  3. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/__init__.py +9 -9
  4. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/api/oecd.py +4 -4
  5. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/api/sources.py +29 -14
  6. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/clean_data/common.py +1 -1
  7. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/clean_data/schema.py +158 -1
  8. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/config.py +1 -1
  9. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/crs/common.py +1 -1
  10. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/crs/crs_functions.py +1 -1
  11. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/crs/oecd.py +3 -4
  12. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac1/dac1_functions.py +1 -2
  13. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac1/oecd.py +2 -2
  14. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac2a/oecd.py +1 -1
  15. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/indicator.py +1 -1
  16. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/research/eu.py +1 -1
  17. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/research/policy_markers.py +30 -11
  18. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/compatibility.py +1 -1
  19. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/gni.py +2 -1
  20. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/names/add.py +1 -0
  21. oda_data-2.1.2/LICENSE +0 -21
  22. oda_data-2.1.2/pyproject.toml +0 -35
  23. {oda_data-2.1.2 → oda_data-2.2.2}/README.md +0 -0
  24. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/.raw_data/README.md +0 -0
  25. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/api/__init__.py +0 -0
  26. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/api/constants.py +0 -0
  27. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/api/representations.py +0 -0
  28. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/clean_data/__init__.py +0 -0
  29. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/clean_data/channels.py +0 -0
  30. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/clean_data/crs_channel_mapping.csv +0 -0
  31. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/clean_data/dtypes.py +0 -0
  32. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/clean_data/validation.py +0 -0
  33. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/__init__.py +0 -0
  34. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/common.py +0 -0
  35. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/crs/__init__.py +0 -0
  36. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/crs/crs_indicators.json +0 -0
  37. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/crs/one.py +0 -0
  38. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac1/__init__.py +0 -0
  39. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac1/common.py +0 -0
  40. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac1/dac1_indicators.json +0 -0
  41. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac1/one.py +0 -0
  42. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac2a/__init__.py +0 -0
  43. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac2a/common.py +0 -0
  44. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac2a/dac2a_functions.py +0 -0
  45. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac2a/dac2a_indicators.json +0 -0
  46. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/dac2a/one.py +0 -0
  47. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/research/__init__.py +0 -0
  48. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/indicators/research/sector_imputations.py +2 -2
  49. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/logger.py +0 -0
  50. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/crs_flow_types.json +0 -0
  51. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/crs_modalities.json +0 -0
  52. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/crs_policy_markers.json +0 -0
  53. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/crs_purpose.json +0 -0
  54. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/crs_type_of_finance.json +0 -0
  55. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/dac1_aid_flow_types.json +0 -0
  56. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/dac2a_aid_type.json +0 -0
  57. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/flow_types.json +0 -0
  58. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/indicators.json +0 -0
  59. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/key_columns.json +0 -0
  60. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/provider_groupings.json +0 -0
  61. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/recipient_groupings.json +0 -0
  62. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/settings/v1_indicators_mapping.json +0 -0
  63. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/__init__.py +0 -0
  64. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/cache.py +0 -0
  65. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/groupings.py +0 -0
  66. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/names/__init__.py +0 -0
  67. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/names/create_mapping.py +1 -1
  68. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/names/crs_names.json +0 -0
  69. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/names/dac1_names.json +0 -0
  70. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/names/dac2a_names.json +0 -0
  71. {oda_data-2.1.2 → oda_data-2.2.2/src}/oda_data/tools/sector_lists.py +0 -0
@@ -1,23 +1,17 @@
1
1
  Metadata-Version: 2.3
2
- Name: oda_data
3
- Version: 2.1.2
2
+ Name: oda-data
3
+ Version: 2.2.2
4
4
  Summary: A python package to work with Official Development Assistance data from the OECD DAC.
5
+ Author: Jorge Rivera, Miguel Haro Ruiz
6
+ Author-email: Jorge Rivera <jorge.rivera@one.org>, Miguel Haro Ruiz <miguel.haroruiz@one.org>
5
7
  License: MIT
6
- Author: Jorge Rivera
7
- Author-email: jorge.rivera@one.org
8
- Requires-Python: >=3.10,<4.0
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Requires-Dist: cachetools (>=5.5.1,<7.0.0)
16
- Requires-Dist: oda-reader (>=1.2,<2.0)
17
- Requires-Dist: pandas (>=2)
18
- Requires-Dist: pyarrow (>=14,<22)
19
- Requires-Dist: pydeflate (>=2.0.1)
20
- Requires-Dist: thefuzz (>=0.22.1)
8
+ Requires-Dist: cachetools>=6.2.0
9
+ Requires-Dist: oda-reader>=1.2.2
10
+ Requires-Dist: pandas[excel,parquet,performance]>=2.3.2
11
+ Requires-Dist: pydeflate>=2.1.3
12
+ Requires-Dist: reader>=3.18
13
+ Requires-Dist: thefuzz>=0.22.1
14
+ Requires-Python: >=3.11
21
15
  Project-URL: Documentation, https://github.com/ONEcampaign/oda_data_package
22
16
  Project-URL: Homepage, https://github.com/ONEcampaign/oda_data_package
23
17
  Project-URL: Repository, https://github.com/ONEcampaign/oda_data_package
@@ -345,4 +339,3 @@ request it via the [issues page](https://github.com/ONEcampaign/oda_data_package
345
339
 
346
340
  ## Contributing
347
341
  Interested in contributing to the package? Please reach out.
348
-
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "oda_data"
3
+ version = "2.2.2"
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
+ dependencies = [
15
+ "cachetools>=6.2.0",
16
+ "oda-reader>=1.2.2",
17
+ "pandas[excel,parquet,performance]>=2.3.2",
18
+ "pydeflate>=2.1.3",
19
+ "reader>=3.18",
20
+ "thefuzz>=0.22.1",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/ONEcampaign/oda_data_package"
25
+ Repository = "https://github.com/ONEcampaign/oda_data_package"
26
+ Documentation = "https://github.com/ONEcampaign/oda_data_package"
27
+
28
+ [build-system]
29
+ requires = ["uv_build>=0.8.22,<0.9.0"]
30
+ build-backend = "uv_build"
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "uv-build>=0.8.22",
35
+ ]
@@ -1,30 +1,29 @@
1
- from importlib.metadata import version
1
+ from oda_reader import clear_cache, disable_cache, enable_cache, set_cache_dir
2
2
 
3
- __version__ = version("oda_data")
4
-
5
- from oda_data import tools
6
- from oda_reader import set_cache_dir, disable_cache, enable_cache, clear_cache
7
3
  from oda_data.api.oecd import OECDClient
8
4
  from oda_data.api.sources import (
5
+ AidDataData,
6
+ CRSData,
9
7
  DAC1Data,
10
8
  DAC2AData,
11
9
  MultiSystemData,
12
- CRSData,
13
- AidDataData,
14
10
  )
15
11
  from oda_data.indicators.research.policy_markers import bilateral_policy_marker
16
12
  from oda_data.tools.compatibility import ODAData
17
13
  from oda_data.tools.gni import add_gni_share_column
18
14
  from oda_data.tools.groupings import provider_groupings, recipient_groupings
19
15
  from oda_data.tools.names.add import add_names_columns
20
- from oda_data.tools.sector_lists import add_sectors, add_broad_sectors
16
+ from oda_data.tools.sector_lists import add_broad_sectors, add_sectors
17
+ from oda_data.indicators.research import sector_imputations
21
18
 
22
19
 
23
20
  def set_data_path(path):
24
21
  from pathlib import Path
25
- from oda_data.config import ODAPaths
22
+
26
23
  from pydeflate import set_pydeflate_path
27
24
 
25
+ from oda_data.config import ODAPaths
26
+
28
27
  """Set the path to the data folder."""
29
28
  global ODAPaths
30
29
 
@@ -56,4 +55,5 @@ __all__ = [
56
55
  "disable_cache",
57
56
  "enable_cache",
58
57
  "clear_cache",
58
+ "sector_imputations",
59
59
  ]
@@ -7,14 +7,14 @@ import pandas as pd
7
7
 
8
8
  from oda_data import config
9
9
  from oda_data.api.constants import (
10
- MEASURES,
11
- Measure,
10
+ _EXCLUDE,
12
11
  CURRENCIES,
12
+ MEASURES,
13
13
  PRICES,
14
- _EXCLUDE,
14
+ Measure,
15
15
  )
16
16
  from oda_data.api.representations import _ODADict, _ODAList
17
- from oda_data.api.sources import DAC1Data, DAC2AData, CRSData, MultiSystemData
17
+ from oda_data.api.sources import CRSData, DAC1Data, DAC2AData, MultiSystemData
18
18
  from oda_data.clean_data import common as clean
19
19
  from oda_data.clean_data.validation import validate_currency, validate_measure
20
20
  from oda_data.indicators.crs import crs_functions
@@ -1,18 +1,18 @@
1
+ import threading
1
2
  from abc import abstractmethod
2
3
  from pathlib import Path
3
4
  from typing import Optional
4
- import threading
5
5
 
6
6
  import pandas as pd
7
7
  from cachetools import TTLCache
8
8
  from oda_reader import (
9
- download_crs,
10
9
  bulk_download_crs,
10
+ bulk_download_multisystem,
11
+ download_aiddata,
12
+ download_crs,
11
13
  download_dac1,
12
14
  download_dac2a,
13
- bulk_download_multisystem,
14
15
  download_multisystem,
15
- download_aiddata,
16
16
  )
17
17
  from oda_reader._cache import memory
18
18
 
@@ -20,17 +20,33 @@ from oda_data.clean_data.common import (
20
20
  clean_raw_df,
21
21
  convert_dot_stat_to_data_explorer_codes,
22
22
  )
23
- from oda_data.clean_data.schema import ODASchema, AidDataSchema
23
+ from oda_data.clean_data.schema import (
24
+ CORE_CRS_MAPPING,
25
+ AidDataSchema,
26
+ ODASchema,
27
+ )
24
28
  from oda_data.clean_data.validation import (
25
- validate_years_providers_recipients,
26
29
  check_integers,
27
30
  check_strings,
31
+ validate_years_providers_recipients,
28
32
  )
29
33
  from oda_data.config import ODAPaths
30
34
  from oda_data.logger import logger
31
35
  from oda_data.tools.cache import OnDiskCache, generate_param_hash
32
36
 
33
37
 
38
+ def translate_cols_and_filters_to_raw(columns, filters) -> tuple[list, list]:
39
+ crs_mapping = {v: k for k, v in CORE_CRS_MAPPING.items()}
40
+ cols = [crs_mapping.get(col, col) for col in columns] if columns else columns
41
+ filters = (
42
+ [(crs_mapping.get(col, col), op, val) for col, op, val in filters]
43
+ if filters
44
+ else None
45
+ )
46
+
47
+ return cols, filters
48
+
49
+
34
50
  def _filters_to_query(filters: list[tuple[str, str, list]]) -> str:
35
51
  """Transform a list of filters into a query string."""
36
52
  query = ""
@@ -79,9 +95,7 @@ class Source:
79
95
  with Source._shared_disk_cache_lock:
80
96
  dc = Source._shared_disk_cache
81
97
  if dc is None or dc.base_dir != current_raw:
82
- Source._shared_disk_cache = OnDiskCache(
83
- current_raw, ttl_seconds=86400
84
- )
98
+ Source._shared_disk_cache = OnDiskCache(current_raw, ttl_seconds=86400)
85
99
  return Source._shared_disk_cache
86
100
 
87
101
  def _add_filter(self, column: str, predicate: str, value: str | int | list) -> None:
@@ -124,7 +138,6 @@ class Source:
124
138
  def _get_cached_dataset(
125
139
  self, param_hash: str, filters: list[tuple], columns: list[str]
126
140
  ) -> pd.DataFrame | None:
127
-
128
141
  cached_df = self.memory_cache.get(param_hash)
129
142
 
130
143
  if cached_df is None:
@@ -156,7 +169,6 @@ class DACSource(Source):
156
169
  recipients: Optional[list[int] | int] = None,
157
170
  sectors: Optional[list[int] | int] = None,
158
171
  ):
159
-
160
172
  self.years, self.providers, self.recipients = (
161
173
  validate_years_providers_recipients(
162
174
  years=years, providers=providers, recipients=recipients
@@ -317,10 +329,13 @@ class DACSource(Source):
317
329
  df=df, query=query, param_hash=param_hash, bulk=using_bulk_download
318
330
  )
319
331
 
320
- df = df.pipe(clean_raw_df)
321
-
322
332
  if columns:
323
- df = df.filter(columns)
333
+ try:
334
+ df = df[columns]
335
+ except Exception as e:
336
+ df = df.pipe(clean_raw_df)[columns]
337
+
338
+ df = df.pipe(clean_raw_df)
324
339
 
325
340
  return df
326
341
 
@@ -4,7 +4,7 @@ from functools import partial
4
4
  from typing import Optional
5
5
 
6
6
  import pandas as pd
7
- from pydeflate import set_pydeflate_path, oecd_dac_deflate, oecd_dac_exchange
7
+ from pydeflate import oecd_dac_deflate, oecd_dac_exchange, set_pydeflate_path
8
8
 
9
9
  from oda_data.clean_data.dtypes import set_default_types
10
10
  from oda_data.clean_data.schema import CRS_MAPPING, ODASchema
@@ -134,9 +134,154 @@ class ODASchema:
134
134
  AID_TO_THRU: str = "aid_to_or_thru"
135
135
  AMOUNT_TYPE_CODE: str = "amounttype_code"
136
136
  MEASURE: str = "measure"
137
+ INITIAL_REPORT: str = "initial_report"
138
+ DE_INCOMEGROUPCODE: str = "de_incomegroupcode"
139
+ CHANNEL_REPORTED_NAME: str = "channel_reported_name"
140
+ GEOGRAPHY: str = "geography"
141
+ KEYWORDS: str = "keywords"
142
+ BUDGET_IDENTIFIER: str = "budget_ident"
143
+ PSI_GRANT_EQ_USD: str = "usd_psi_gr_eq_memo"
137
144
 
138
145
 
139
- CRS_MAPPING: dict[str, str] = {
146
+ CORE_CRS_MAPPING: dict[str, str] = {
147
+ "year": ODASchema.YEAR,
148
+ "donor_code": ODASchema.PROVIDER_CODE,
149
+ "donor_name": ODASchema.PROVIDER_NAME,
150
+ "agency_code": ODASchema.AGENCY_CODE,
151
+ "agency_name": ODASchema.AGENCY_NAME,
152
+ "crs_id": ODASchema.CRS_ID,
153
+ "initial_report": ODASchema.INITIAL_REPORT,
154
+ "project_number": ODASchema.PROJECT_ID,
155
+ "recipient_code": ODASchema.RECIPIENT_CODE,
156
+ "recipient_name": ODASchema.RECIPIENT_NAME,
157
+ "region_name": ODASchema.RECIPIENT_REGION,
158
+ "region_code": ODASchema.RECIPIENT_REGION_CODE,
159
+ "incomegoup_name": ODASchema.RECIPIENT_INCOME,
160
+ "incomegroup_code": ODASchema.RECIPIENT_INCOME_CODE,
161
+ "de_incomegroupcode": ODASchema.DE_INCOMEGROUPCODE,
162
+ "recipient_income_group_oecd_classification": ODASchema.RECIPIENT_INCOME,
163
+ "aid_t": ODASchema.FLOW_MODALITY,
164
+ "financial_instrument": ODASchema.FINANCIAL_INSTRUMENT,
165
+ "type_of_finance": ODASchema.FINANCE_TYPE,
166
+ "finance_t": ODASchema.FINANCE_TYPE,
167
+ "channel_of_delivery": ODASchema.CHANNEL_NAME_DELIVERY,
168
+ "channel_of_delivery_code": ODASchema.CHANNEL_CODE_DELIVERY,
169
+ "channel_code": ODASchema.CHANNEL_CODE,
170
+ "channel_name": ODASchema.CHANNEL_NAME,
171
+ "purpose_code": ODASchema.PURPOSE_CODE,
172
+ "sector_code": ODASchema.SECTOR_CODE,
173
+ "purpose_name": ODASchema.PURPOSE_NAME,
174
+ "sector_name": ODASchema.SECTOR_NAME,
175
+ "project_title": ODASchema.PROJECT_TITLE,
176
+ "long_description": ODASchema.PROJECT_DESCRIPTION,
177
+ "short_description": ODASchema.PROJECT_DESCRIPTION_SHORT,
178
+ "flow_code": ODASchema.FLOW_CODE,
179
+ "flow_name": ODASchema.FLOW_NAME,
180
+ "bi_multi": ODASchema.BI_MULTI,
181
+ "gender": ODASchema.GENDER,
182
+ "category": ODASchema.CATEGORY,
183
+ "usd_commitment": ODASchema.USD_COMMITMENT,
184
+ "usd_disbursement": ODASchema.USD_DISBURSEMENT,
185
+ "usd_received": ODASchema.USD_RECEIVED,
186
+ "usd_grant_equiv": ODASchema.USD_GRANT_EQUIV,
187
+ "usd_net_disbursement": ODASchema.USD_NET_DISBURSEMENT,
188
+ "usd_commitment_defl": ODASchema.USD_COMMITMENT_DEFL,
189
+ "usd_disbursement_defl": ODASchema.USD_DISBURSEMENT_DEFL,
190
+ "usd_received_defl": ODASchema.USD_RECEIVED_DEFL,
191
+ "usd_adjustment": ODASchema.USD_ADJUSTMENT,
192
+ "usd_adjustment_defl": ODASchema.USD_ADJUSTMENT_DEFL,
193
+ "usd_amount_untied": ODASchema.USD_AMOUNT_UNTIED,
194
+ "usd_amount_untied_defl": ODASchema.USD_AMOUNT_UNTIED_DEFL,
195
+ "usd_amount_tied": ODASchema.USD_AMOUNT_TIED,
196
+ "usd_amount_tied_defl": ODASchema.USD_AMOUNT_TIED_DEFL,
197
+ "usd_amount_partial_tied": ODASchema.USD_AMOUNT_PARTIAL_TIED,
198
+ "usd_amount_partial_tied_defl": ODASchema.USD_AMOUNT_PARTIAL_TIED_DEFL,
199
+ "usd_irtc_code": ODASchema.USD_IRTC_CODE,
200
+ "usd_expert_commitment": ODASchema.USD_EXPERT_COMMITMENT,
201
+ "usd_expert_extended": ODASchema.USD_EXPERT_EXTENDED,
202
+ "usd_export_credit": ODASchema.USD_EXPORT_CREDIT,
203
+ "commitment_national": ODASchema.COMMITMENT_NATIONAL,
204
+ "disbursement_national": ODASchema.DISBURSEMENT_NATIONAL,
205
+ "grant_equiv": ODASchema.GRANT_EQUIV_NATIONAL,
206
+ "parent_channel_code": ODASchema.PARENT_CHANNEL_CODE,
207
+ "ld_cflag": ODASchema.LDC_FLAG_CODE,
208
+ "ldcflag": ODASchema.LDC_FLAG_CODE,
209
+ "ld_cflag_name": ODASchema.LDC_FLAG,
210
+ "ldcflag_name": ODASchema.LDC_FLAG,
211
+ "sdg_focus": ODASchema.SDG_FOCUS,
212
+ "sdgfocus": ODASchema.SDG_FOCUS,
213
+ "sd_gfocus": ODASchema.SDG_FOCUS,
214
+ "expected_start_date": ODASchema.EXPECTED_START_DATE,
215
+ "completion_date": ODASchema.COMPLETION_DATE,
216
+ "environment": ODASchema.ENVIRONMENT,
217
+ "dig_code": ODASchema.DIG_CODE,
218
+ "dig": ODASchema.DIG_CODE,
219
+ "trade": ODASchema.TRADE,
220
+ "rmnch": ODASchema.RMNCH_CODE,
221
+ "drr": ODASchema.DRR_CODE,
222
+ "rmnch_code": ODASchema.RMNCH_CODE,
223
+ "drr_code": ODASchema.DRR_CODE,
224
+ "nutrition": ODASchema.NUTRITION,
225
+ "disability": ODASchema.DISABILITY,
226
+ "ftc": ODASchema.FTC_CODE,
227
+ "ftc_code": ODASchema.FTC_CODE,
228
+ "pba": ODASchema.PBA_CODE,
229
+ "pba_code": ODASchema.PBA_CODE,
230
+ "investment_project": ODASchema.INVESTMENT_PROJECT,
231
+ "assoc_finance": ODASchema.ASSOC_FINANCE,
232
+ "biodiversity": ODASchema.BIODIVERSITY,
233
+ "desertification": ODASchema.DESERTIFICATION,
234
+ "commitment_date": ODASchema.COMMITMENT_DATE,
235
+ "type_repayment": ODASchema.TYPE_REPAYMENT,
236
+ "number_repayment": ODASchema.NUMBER_REPAYMENT,
237
+ "interest1": ODASchema.INTEREST1,
238
+ "interest2": ODASchema.INTEREST2,
239
+ "repaydate1": ODASchema.REPAYDATE1,
240
+ "repaydate2": ODASchema.REPAYDATE2,
241
+ "usd_interest": ODASchema.USD_INTEREST,
242
+ "usd_outstanding": ODASchema.USD_OUTSTANDING,
243
+ "usd_arrears_principal": ODASchema.USD_ARREARS_PRINCIPAL,
244
+ "usd_arrears_interest": ODASchema.USD_ARREARS_INTEREST,
245
+ "capital_expend": ODASchema.CAPITAL_EXPEND,
246
+ "ps_iflag": ODASchema.PSI_FLAG,
247
+ "psiflag": ODASchema.PSI_FLAG,
248
+ "psi_flag": ODASchema.PSI_FLAG,
249
+ "ps_iadd_type": ODASchema.PSI_ADD_TYPE,
250
+ "psiadd_type": ODASchema.PSI_ADD_TYPE,
251
+ "psi_add_type": ODASchema.PSI_ADD_TYPE,
252
+ "ps_iadd_assess": ODASchema.PSI_ADD_ASSESS,
253
+ "psiadd_assess": ODASchema.PSI_ADD_ASSESS,
254
+ "psi_add_assess": ODASchema.PSI_ADD_ASSESS,
255
+ "ps_iadd_dev_obj": ODASchema.PSI_ADD_DEV_OBJECTIVE,
256
+ "psiadd_dev_obj": ODASchema.PSI_ADD_DEV_OBJECTIVE,
257
+ "psi_add_dev_obj": ODASchema.PSI_ADD_DEV_OBJECTIVE,
258
+ "oecd_climate_total": ODASchema.CLIMATE_UNSPECIFIED,
259
+ "reporting_type": ODASchema.REPORTING_METHOD,
260
+ "type": ODASchema.MULTILATERAL_TYPE,
261
+ "converged_reporting": ODASchema.CONVERGED_REPORTING,
262
+ "coal_related_financing": ODASchema.COAL_FINANCING,
263
+ "flow_type": ODASchema.FLOW_TYPE,
264
+ "type_of_flow": ODASchema.FLOW_TYPE,
265
+ "aidtype_code": ODASchema.AIDTYPE_CODE,
266
+ "aid_type": ODASchema.AIDTYPE_NAME,
267
+ "flows_code": ODASchema.FLOWS_CODE,
268
+ "fund_flows": ODASchema.FUND_FLOWS,
269
+ "amounttype_code": ODASchema.AMOUNT_TYPE_CODE,
270
+ "de_donorcode": ODASchema.PROVIDER_CODE_DE,
271
+ "de_recipientcode": ODASchema.RECIPIENT_CODE_DE,
272
+ "de_regioncode": ODASchema.RECIPIENT_REGION_CODE_DE,
273
+ "incomegroup_name": ODASchema.RECIPIENT_INCOME,
274
+ "channel_reported_name": ODASchema.CHANNEL_REPORTED_NAME,
275
+ "geography": ODASchema.GEOGRAPHY,
276
+ "keywords": ODASchema.KEYWORDS,
277
+ "climate_adaptation": ODASchema.ADAPTATION,
278
+ "climate_mitigation": ODASchema.MITIGATION,
279
+ "budget_ident": ODASchema.BUDGET_IDENTIFIER,
280
+ "usd_psi_gr_eq_memo": ODASchema.PSI_GRANT_EQ_USD,
281
+ }
282
+
283
+ CRS_MAPPING: dict[str, str] = CORE_CRS_MAPPING | {
284
+ "year": ODASchema.YEAR,
140
285
  "donor_code": ODASchema.PROVIDER_CODE,
141
286
  "donor_name": ODASchema.PROVIDER_NAME,
142
287
  "provider": ODASchema.PROVIDER_NAME,
@@ -146,7 +291,9 @@ CRS_MAPPING: dict[str, str] = {
146
291
  "agency_code": ODASchema.AGENCY_CODE,
147
292
  "agency_name": ODASchema.AGENCY_NAME,
148
293
  "extending_agency": ODASchema.AGENCY_NAME,
294
+ "crs_id": ODASchema.CRS_ID,
149
295
  "crs_identification_n": ODASchema.CRS_ID,
296
+ "initial_report": ODASchema.INITIAL_REPORT,
150
297
  "donor_project_n": ODASchema.PROJECT_ID,
151
298
  "project_number": ODASchema.PROJECT_ID,
152
299
  "recipient_code": ODASchema.RECIPIENT_CODE,
@@ -155,6 +302,7 @@ CRS_MAPPING: dict[str, str] = {
155
302
  "region_code": ODASchema.RECIPIENT_REGION_CODE,
156
303
  "incomegoup_name": ODASchema.RECIPIENT_INCOME,
157
304
  "incomegroup_code": ODASchema.RECIPIENT_INCOME_CODE,
305
+ "de_incomegroupcode": ODASchema.DE_INCOMEGROUPCODE,
158
306
  "recipient_income_group_oecd_classification": ODASchema.RECIPIENT_INCOME,
159
307
  "development_cooperation_modality": ODASchema.FLOW_MODALITY,
160
308
  "aid_t": ODASchema.FLOW_MODALITY,
@@ -177,6 +325,8 @@ CRS_MAPPING: dict[str, str] = {
177
325
  "sub_sector": ODASchema.PURPOSE_NAME,
178
326
  "purpose_code": ODASchema.PURPOSE_CODE,
179
327
  "sector_code": ODASchema.SECTOR_CODE,
328
+ "purpose_name": ODASchema.PURPOSE_NAME,
329
+ "sector_name": ODASchema.SECTOR_NAME,
180
330
  "project_title": ODASchema.PROJECT_TITLE,
181
331
  "long_description": ODASchema.PROJECT_DESCRIPTION,
182
332
  "short_description": ODASchema.PROJECT_DESCRIPTION_SHORT,
@@ -276,6 +426,13 @@ CRS_MAPPING: dict[str, str] = {
276
426
  "de_recipientcode": ODASchema.RECIPIENT_CODE_DE,
277
427
  "de_regioncode": ODASchema.RECIPIENT_REGION_CODE_DE,
278
428
  "incomegroup_name": ODASchema.RECIPIENT_INCOME,
429
+ "channel_reported_name": ODASchema.CHANNEL_REPORTED_NAME,
430
+ "geography": ODASchema.GEOGRAPHY,
431
+ "keywords": ODASchema.KEYWORDS,
432
+ "climate_adaptation": ODASchema.ADAPTATION,
433
+ "climate_mitigation": ODASchema.MITIGATION,
434
+ "budget_ident": ODASchema.BUDGET_IDENTIFIER,
435
+ "usd_psi_gr_eq_memo": ODASchema.PSI_GRANT_EQ_USD,
279
436
  }
280
437
 
281
438
 
@@ -4,7 +4,7 @@ from pathlib import Path
4
4
  class ODAPaths:
5
5
  """Class to store the paths to the data and output folders."""
6
6
 
7
- project = Path(__file__).resolve().parent.parent
7
+ project = Path(__file__).resolve().parent.parent.parent
8
8
  scripts = project / "oda_data"
9
9
  raw_data = (Path.cwd() / ".raw_data").resolve()
10
10
  pydeflate = raw_data / ".pydeflate"
@@ -1,5 +1,5 @@
1
1
  import json
2
- from typing import Callable, Dict, Any
2
+ from typing import Any, Callable, Dict
3
3
 
4
4
  import pandas as pd
5
5
 
@@ -1,6 +1,6 @@
1
1
  import pandas as pd
2
2
 
3
- from oda_data.clean_data.channels import add_multi_channel_codes, add_channel_names
3
+ from oda_data.clean_data.channels import add_channel_names, add_multi_channel_codes
4
4
  from oda_data.clean_data.schema import ODASchema
5
5
  from oda_data.indicators.crs.common import crs_value_cols
6
6
 
@@ -11,12 +11,12 @@ from oda_data import CRSData
11
11
  from oda_data.config import ODAPaths
12
12
  from oda_data.indicators.common import update_mapping_file
13
13
  from oda_data.indicators.crs.common import (
14
- read_crs_type_of_flow,
15
- read_crs_type_of_finance_mapping,
16
14
  read_crs_modality_mapping,
17
15
  read_crs_purpose_mapping,
16
+ read_crs_type_of_finance_mapping,
17
+ read_crs_type_of_flow,
18
18
  )
19
- from oda_data.indicators.indicator import Indicator, SEPARATOR
19
+ from oda_data.indicators.indicator import SEPARATOR, Indicator
20
20
 
21
21
 
22
22
  def generate_totals(crs_indicators: pd.DataFrame) -> pd.DataFrame:
@@ -34,7 +34,6 @@ def generate_totals(crs_indicators: pd.DataFrame) -> pd.DataFrame:
34
34
 
35
35
  # Iteratively group and aggregate data to generate totals
36
36
  for idx, column in enumerate(crs_indicators.columns):
37
-
38
37
  # Create a grouping Total
39
38
  if idx >= 2:
40
39
  columns_g.append(column)
@@ -17,8 +17,7 @@ def official_oda(data: pd.DataFrame) -> pd.DataFrame:
17
17
  A filtered pandas DataFrame with only official ODA rows.
18
18
  """
19
19
  oda_query = (
20
- "(year < 2018 & aidtype_code == 1010) | "
21
- "(year >= 2018 & aidtype_code == 11010)"
20
+ "(year < 2018 & aidtype_code == 1010) | (year >= 2018 & aidtype_code == 11010)"
22
21
  )
23
22
  return data.query(oda_query)
24
23
 
@@ -1,11 +1,11 @@
1
1
  from oda_data.config import ODAPaths
2
+ from oda_data.indicators.common import update_mapping_file
2
3
  from oda_data.indicators.dac1.common import (
3
4
  dac1_aid_flow_type_mapping,
4
5
  dac1_aid_name_mapping,
5
6
  flow_types,
6
7
  )
7
- from oda_data.indicators.common import update_mapping_file
8
- from oda_data.indicators.indicator import Indicator, SEPARATOR
8
+ from oda_data.indicators.indicator import SEPARATOR, Indicator
9
9
 
10
10
 
11
11
  def dac1_oecd_indicators():
@@ -1,7 +1,7 @@
1
1
  from oda_data.config import ODAPaths
2
2
  from oda_data.indicators.common import update_mapping_file
3
3
  from oda_data.indicators.dac2a.common import aid_type
4
- from oda_data.indicators.indicator import Indicator, SEPARATOR
4
+ from oda_data.indicators.indicator import SEPARATOR, Indicator
5
5
 
6
6
 
7
7
  def dac2a_oecd_indicators():
@@ -1,4 +1,4 @@
1
- from dataclasses import dataclass, field, asdict
1
+ from dataclasses import asdict, dataclass, field
2
2
  from typing import Literal, Optional
3
3
 
4
4
  SEPARATOR = "."
@@ -3,7 +3,7 @@
3
3
  import pandas as pd
4
4
 
5
5
  from oda_data.api.constants import Measure
6
- from oda_data.api.oecd import get_measure_filter, OECDClient
6
+ from oda_data.api.oecd import OECDClient, get_measure_filter
7
7
  from oda_data.api.sources import DAC1Data
8
8
  from oda_data.clean_data.schema import ODASchema
9
9
 
@@ -1,13 +1,15 @@
1
1
  import pandas as pd
2
+ from pyarrow import ArrowInvalid
2
3
 
3
4
  from oda_data.api.constants import (
4
- Measure,
5
- PolicyMarker,
6
- MEASURES,
7
5
  EXTENDED_PROVIDER_PURPOSE_GROUPER,
6
+ MEASURES,
8
7
  MarkerScore,
8
+ Measure,
9
+ PolicyMarker,
9
10
  )
10
- from oda_data.clean_data.common import convert_units
11
+ from oda_data.api.sources import translate_cols_and_filters_to_raw
12
+ from oda_data.clean_data.common import clean_raw_df, convert_units
11
13
  from oda_data.clean_data.schema import ODASchema
12
14
 
13
15
 
@@ -23,7 +25,7 @@ def _marker_score_map(marker: PolicyMarker | str) -> list:
23
25
  def _marker_modality_filter() -> list:
24
26
  return [
25
27
  (
26
- "modality",
28
+ ODASchema.FLOW_MODALITY,
27
29
  "in",
28
30
  [
29
31
  "A02",
@@ -94,17 +96,34 @@ def bilateral_policy_marker(
94
96
  filters.append((marker, "in", marker_filter))
95
97
 
96
98
  if oda_only:
97
- filters.append(("category", "in", [10, 60]))
99
+ filters.append(
100
+ (
101
+ ODASchema.FLOW_CODE,
102
+ "in",
103
+ [11, 13, 19, 60],
104
+ )
105
+ )
98
106
 
99
107
  # Set up the CRS data object
100
108
  crs = CRSData(providers=providers, years=years, recipients=recipients)
101
109
 
102
110
  # Read the data and group by provider and purpose
103
- data = crs.read(
104
- columns=grouper + [measure],
105
- additional_filters=filters,
106
- using_bulk_download=True,
107
- )
111
+
112
+ cols = grouper + [measure]
113
+
114
+ try:
115
+ data = crs.read(
116
+ columns=cols,
117
+ additional_filters=filters,
118
+ using_bulk_download=True,
119
+ )
120
+ except ArrowInvalid as e:
121
+ c, f = translate_cols_and_filters_to_raw(cols, filters)
122
+ data = crs.read(
123
+ columns=c,
124
+ additional_filters=f,
125
+ using_bulk_download=True,
126
+ )
108
127
 
109
128
  # if marker is not_screened, we need to filter out the screened data
110
129
  if marker == "not_screened":
@@ -4,7 +4,7 @@ from dataclasses import dataclass, field
4
4
 
5
5
  import pandas as pd
6
6
 
7
- from oda_data import config, OECDClient
7
+ from oda_data import OECDClient, config
8
8
 
9
9
 
10
10
  @dataclass
@@ -1,11 +1,12 @@
1
1
  """Compute GNI share indicators, including EU Institutions if applicable."""
2
2
 
3
3
  from copy import copy
4
+
4
5
  import pandas as pd
5
6
 
6
7
  from oda_data import OECDClient
7
- from oda_data.tools.groupings import provider_groupings
8
8
  from oda_data.clean_data.schema import ODASchema
9
+ from oda_data.tools.groupings import provider_groupings
9
10
 
10
11
 
11
12
  def _get_eu27_gni_as_eu_institutions(gni_obj: OECDClient) -> pd.DataFrame:
@@ -1,6 +1,7 @@
1
1
  """Adds human-readable name columns to a DataFrame based on code columns."""
2
2
 
3
3
  import pandas as pd
4
+
4
5
  from oda_data.tools.names.create_mapping import get_merged_names_mapping
5
6
 
6
7
 
oda_data-2.1.2/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2022 ONE Campaign
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,35 +0,0 @@
1
- [tool.poetry]
2
- name = "oda_data"
3
- version = "2.1.2"
4
- description = "A python package to work with Official Development Assistance data from the OECD DAC."
5
- readme = "README.md"
6
- authors = [
7
- "Jorge Rivera <jorge.rivera@one.org>",
8
- "Miguel Haro Ruiz <miguel.haroruiz@one.org>"
9
- ]
10
- license = "MIT"
11
- homepage = "https://github.com/ONEcampaign/oda_data_package"
12
- repository = "https://github.com/ONEcampaign/oda_data_package"
13
- documentation = "https://github.com/ONEcampaign/oda_data_package"
14
-
15
- [tool.poetry.dependencies]
16
- python = ">=3.10,<4.0"
17
- pandas = ">=2"
18
- thefuzz = ">=0.22.1"
19
- pyarrow = ">=14,<22"
20
- pydeflate = ">=2.0.1"
21
- cachetools = ">=5.5.1,<7.0.0"
22
- oda-reader = "^1.2"
23
-
24
- [tool.poetry.group.dev.dependencies]
25
- black = ">=25"
26
- pytest = ">=8"
27
-
28
-
29
- [tool.poetry-dynamic-versioning]
30
- enable = true
31
- style = "pep440"
32
-
33
- [build-system]
34
- requires = ["poetry-core>=2.0.0,<3.0.0"]
35
- build-backend = "poetry.core.masonry.api"
File without changes
@@ -2,10 +2,10 @@ import pandas as pd
2
2
 
3
3
  from oda_data import provider_groupings
4
4
  from oda_data.api.constants import (
5
- Measure,
5
+ CHANNEL_PURPOSE_SHARE_GROUPER,
6
6
  MEASURES,
7
7
  PROVIDER_PURPOSE_GROUPER,
8
- CHANNEL_PURPOSE_SHARE_GROUPER,
8
+ Measure,
9
9
  )
10
10
  from oda_data.clean_data.channels import add_multi_channel_codes
11
11
  from oda_data.clean_data.common import convert_units
@@ -39,6 +39,7 @@ def snake_to_pascal(name: str, *, keep_single_letter: bool = False) -> str:
39
39
  out.append(part.capitalize())
40
40
  return "".join(out)
41
41
 
42
+
42
43
  def _code_name(df: pd.DataFrame, code_col: str, name_col: str) -> dict:
43
44
  """Return a dictionary mapping code to name."""
44
45
  return (
@@ -187,7 +188,6 @@ def crs_codes_names():
187
188
 
188
189
 
189
190
  def get_merged_names_mapping():
190
-
191
191
  files = ["dac1_names.json", "dac2a_names.json", "crs_names.json"]
192
192
 
193
193
  merged_mapping = {}