pydeflate 2.0.2__py3-none-any.whl → 2.1.1__py3-none-any.whl
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.
- pydeflate/__init__.py +7 -2
- pydeflate/core/api.py +8 -1
- pydeflate/core/source.py +10 -1
- pydeflate/exchange/exchangers.py +48 -17
- pydeflate/sources/common.py +1 -1
- pydeflate/sources/world_bank.py +111 -7
- pydeflate/utils.py +69 -9
- {pydeflate-2.0.2.dist-info → pydeflate-2.1.1.dist-info}/METADATA +9 -12
- {pydeflate-2.0.2.dist-info → pydeflate-2.1.1.dist-info}/RECORD +11 -11
- {pydeflate-2.0.2.dist-info → pydeflate-2.1.1.dist-info}/WHEEL +1 -1
- {pydeflate-2.0.2.dist-info → pydeflate-2.1.1.dist-info}/LICENSE +0 -0
pydeflate/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
__author__ = """Jorge Rivera"""
|
|
2
|
-
__version__ = "2.
|
|
2
|
+
__version__ = "2.1.1"
|
|
3
3
|
|
|
4
4
|
from pydeflate.deflate.deflators import (
|
|
5
5
|
oecd_dac_deflate,
|
|
@@ -12,7 +12,12 @@ from pydeflate.deflate.deflators import (
|
|
|
12
12
|
)
|
|
13
13
|
|
|
14
14
|
from pydeflate.deflate.legacy_deflate import deflate
|
|
15
|
-
from pydeflate.exchange.exchangers import
|
|
15
|
+
from pydeflate.exchange.exchangers import (
|
|
16
|
+
oecd_dac_exchange,
|
|
17
|
+
wb_exchange,
|
|
18
|
+
wb_exchange_ppp,
|
|
19
|
+
imf_exchange,
|
|
20
|
+
)
|
|
16
21
|
from pydeflate.pydeflate_config import setup_logger
|
|
17
22
|
|
|
18
23
|
|
pydeflate/core/api.py
CHANGED
|
@@ -77,7 +77,9 @@ def _base_operation(
|
|
|
77
77
|
)
|
|
78
78
|
|
|
79
79
|
# Flag missing data
|
|
80
|
-
flag_missing_pydeflate_data(
|
|
80
|
+
flag_missing_pydeflate_data(
|
|
81
|
+
base_obj._unmatched_data, entity_column=entity_column, year_column=year_column
|
|
82
|
+
)
|
|
81
83
|
x = base_obj._merged_data[value_column]
|
|
82
84
|
y = base_obj._merged_data[
|
|
83
85
|
"pydeflate_EXCHANGE" if exchange else "pydeflate_deflator"
|
|
@@ -174,6 +176,8 @@ class BaseExchange:
|
|
|
174
176
|
pydeflate_data=self.pydeflate_data,
|
|
175
177
|
entity_column=entity_column,
|
|
176
178
|
ix=self._idx,
|
|
179
|
+
source_codes=self._idx[-1] == "pydeflate_entity_code",
|
|
180
|
+
dac=self.exchange_rates.source.name == "DAC",
|
|
177
181
|
)
|
|
178
182
|
|
|
179
183
|
# store unmatched data
|
|
@@ -363,6 +367,9 @@ class BaseDeflate:
|
|
|
363
367
|
pydeflate_data=self.pydeflate_data,
|
|
364
368
|
entity_column=entity_column,
|
|
365
369
|
ix=self._idx,
|
|
370
|
+
source_codes=self.use_source_codes,
|
|
371
|
+
dac=self.exchange_deflator.source.name == "DAC"
|
|
372
|
+
or self.price_deflator.source.name == "DAC",
|
|
366
373
|
)
|
|
367
374
|
|
|
368
375
|
# store unmatched data
|
pydeflate/core/source.py
CHANGED
|
@@ -5,7 +5,7 @@ import pandas as pd
|
|
|
5
5
|
from pydeflate.sources.common import AvailableDeflators
|
|
6
6
|
from pydeflate.sources.dac import read_dac
|
|
7
7
|
from pydeflate.sources.imf import read_weo
|
|
8
|
-
from pydeflate.sources.world_bank import read_wb
|
|
8
|
+
from pydeflate.sources.world_bank import read_wb, read_wb_lcu_ppp, read_wb_usd_ppp
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@dataclass
|
|
@@ -49,6 +49,15 @@ class WorldBank(Source):
|
|
|
49
49
|
super().__init__(name="World Bank", reader=read_wb, update=update)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
class WorldBankPPP(Source):
|
|
53
|
+
def __init__(self, update: bool = False, *, from_lcu: bool = True):
|
|
54
|
+
super().__init__(
|
|
55
|
+
name="World Bank PPP",
|
|
56
|
+
reader=read_wb_lcu_ppp if from_lcu else read_wb_usd_ppp,
|
|
57
|
+
update=update,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
52
61
|
class DAC(Source):
|
|
53
62
|
def __init__(self, update: bool = False):
|
|
54
63
|
super().__init__(name="DAC", reader=read_dac, update=update)
|
pydeflate/exchange/exchangers.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from functools import wraps
|
|
2
2
|
|
|
3
3
|
import pandas as pd
|
|
4
|
+
from frictionless.console.common import source
|
|
4
5
|
|
|
5
6
|
from pydeflate.core.api import BaseExchange
|
|
6
|
-
from pydeflate.core.source import DAC, WorldBank, IMF
|
|
7
|
+
from pydeflate.core.source import DAC, WorldBank, IMF, WorldBankPPP
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def _generate_docstring(source_name: str) -> str:
|
|
@@ -28,26 +29,33 @@ def _generate_docstring(source_name: str) -> str:
|
|
|
28
29
|
)
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
def _exchange(exchange_source_cls):
|
|
32
|
+
def _exchange(exchange_source_cls, **fixed_params):
|
|
32
33
|
"""Decorator to create exchange wrappers with specific source"""
|
|
33
34
|
|
|
34
35
|
def decorator(func):
|
|
35
36
|
@wraps(func)
|
|
36
|
-
def wrapper(
|
|
37
|
-
data: pd.DataFrame,
|
|
38
|
-
*,
|
|
39
|
-
source_currency: str = "USA",
|
|
40
|
-
target_currency: str = "USA",
|
|
41
|
-
id_column: str = "iso_code",
|
|
42
|
-
year_column: str = "year",
|
|
43
|
-
use_source_codes: bool = False,
|
|
44
|
-
value_column: str = "value",
|
|
45
|
-
target_value_column: str = "value",
|
|
46
|
-
reversed_: bool = False,
|
|
47
|
-
year_format: str | None = None,
|
|
48
|
-
update_rates: bool = False,
|
|
49
|
-
):
|
|
37
|
+
def wrapper(data: pd.DataFrame, **kwargs):
|
|
50
38
|
# Validate input parameters
|
|
39
|
+
for param in fixed_params:
|
|
40
|
+
if param in kwargs:
|
|
41
|
+
raise ValueError(
|
|
42
|
+
f"The parameter '{param}' cannot be passed to this function."
|
|
43
|
+
)
|
|
44
|
+
# set fixed parameters
|
|
45
|
+
kwargs.update(fixed_params)
|
|
46
|
+
|
|
47
|
+
# Unpack the parameters
|
|
48
|
+
source_currency = kwargs.get("source_currency", "USA")
|
|
49
|
+
target_currency = kwargs.get("target_currency", "USA")
|
|
50
|
+
id_column = kwargs.get("id_column", "iso_code")
|
|
51
|
+
year_column = kwargs.get("year_column", "year")
|
|
52
|
+
use_source_codes = kwargs.get("use_source_codes", False)
|
|
53
|
+
value_column = kwargs.get("value_column", "value")
|
|
54
|
+
target_value_column = kwargs.get("target_value_column", "value")
|
|
55
|
+
reversed_ = kwargs.get("reversed_", False)
|
|
56
|
+
year_format = kwargs.get("year_format", None)
|
|
57
|
+
update_rates = kwargs.get("update_rates", False)
|
|
58
|
+
|
|
51
59
|
if not isinstance(data, pd.DataFrame):
|
|
52
60
|
raise ValueError("The 'data' parameter must be a pandas DataFrame.")
|
|
53
61
|
|
|
@@ -68,7 +76,14 @@ def _exchange(exchange_source_cls):
|
|
|
68
76
|
to_exchange = data.copy()
|
|
69
77
|
|
|
70
78
|
# Initialize the deflator source
|
|
71
|
-
|
|
79
|
+
if exchange_source_cls.__name__ == "WorldBankPPP":
|
|
80
|
+
source = exchange_source_cls(
|
|
81
|
+
update=update_rates,
|
|
82
|
+
from_lcu=False if source_currency == "USA" else True,
|
|
83
|
+
)
|
|
84
|
+
source_currency = "LCU" if source_currency == "USA" else source_currency
|
|
85
|
+
else:
|
|
86
|
+
source = exchange_source_cls(update=update_rates)
|
|
72
87
|
|
|
73
88
|
# Create a deflator object
|
|
74
89
|
exchange = BaseExchange(
|
|
@@ -130,6 +145,22 @@ def wb_exchange(
|
|
|
130
145
|
) -> pd.DataFrame: ...
|
|
131
146
|
|
|
132
147
|
|
|
148
|
+
@_exchange(WorldBankPPP, target_currency="PPP")
|
|
149
|
+
def wb_exchange_ppp(
|
|
150
|
+
data: pd.DataFrame,
|
|
151
|
+
*,
|
|
152
|
+
source_currency: str = "USA",
|
|
153
|
+
id_column: str = "iso_code",
|
|
154
|
+
year_column: str = "year",
|
|
155
|
+
use_source_codes: bool = False,
|
|
156
|
+
value_column: str = "value",
|
|
157
|
+
target_value_column: str = "value",
|
|
158
|
+
reversed_: bool = False,
|
|
159
|
+
year_format: str | None = None,
|
|
160
|
+
update_rates: bool = False,
|
|
161
|
+
) -> pd.DataFrame: ...
|
|
162
|
+
|
|
163
|
+
|
|
133
164
|
@_exchange(IMF)
|
|
134
165
|
def imf_exchange(
|
|
135
166
|
data: pd.DataFrame,
|
pydeflate/sources/common.py
CHANGED
|
@@ -21,7 +21,7 @@ def check_file_age(file: Path) -> int:
|
|
|
21
21
|
"""
|
|
22
22
|
current_date = datetime.today()
|
|
23
23
|
# Extract date from the filename (format: weo_YYYY-MM-DD.parquet)
|
|
24
|
-
file_date = datetime.strptime(file.stem.split("_")[1], "%Y-%m-%d")
|
|
24
|
+
file_date = datetime.strptime(file.stem.split("_")[-1], "%Y-%m-%d")
|
|
25
25
|
|
|
26
26
|
# Return the difference in days between today and the file's date
|
|
27
27
|
return (current_date - file_date).days
|
pydeflate/sources/world_bank.py
CHANGED
|
@@ -21,6 +21,18 @@ _INDICATORS: dict = {
|
|
|
21
21
|
"PA.NUS.FCRF": "EXCHANGE", # Official Exchange Rate
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
_INDICATORS_LCU_PPP: dict = {
|
|
25
|
+
"NY.GDP.DEFL.ZS": "NGDP_D", # GDP Deflator (Index)
|
|
26
|
+
"NY.GDP.DEFL.ZS.AD": "NGDP_DL", # GDP Deflator linked series
|
|
27
|
+
"PA.NUS.PPP": "EXCHANGE", # PPP conversion factor
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_INDICATORS_USD_PPP: dict = {
|
|
31
|
+
"NY.GDP.DEFL.ZS": "NGDP_D", # GDP Deflator (Index)
|
|
32
|
+
"NY.GDP.DEFL.ZS.AD": "NGDP_DL", # GDP Deflator linked series
|
|
33
|
+
"PA.NUS.PPPC.RF": "EXCHANGE", # PPP conversion factor to market exchange rate
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
|
|
25
37
|
def get_wb_indicator(series: str, value_name: str | None = None) -> pd.DataFrame:
|
|
26
38
|
"""Fetch a World Bank indicator and transform it into a cleaned DataFrame.
|
|
@@ -126,7 +138,28 @@ def _parallel_download_indicators(indicators: dict) -> list[pd.DataFrame]:
|
|
|
126
138
|
return dfs
|
|
127
139
|
|
|
128
140
|
|
|
129
|
-
def
|
|
141
|
+
def _add_ppp_ppp_exchange(df: pd.DataFrame) -> pd.DataFrame:
|
|
142
|
+
"""
|
|
143
|
+
Add the PPP exchange rate to the DataFrame.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
df: pd.DataFrame: The DataFrame containing the World Bank data.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
pd.DataFrame: The DataFrame with the PPP exchange rates
|
|
150
|
+
|
|
151
|
+
"""
|
|
152
|
+
ppp = df.loc[lambda d: d["entity_code"] == "USA"].copy()
|
|
153
|
+
ppp[["entity_code", "entity", "pydeflate_iso3"]] = "PPP"
|
|
154
|
+
|
|
155
|
+
df = pd.concat([df, ppp], ignore_index=True)
|
|
156
|
+
|
|
157
|
+
return df
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _download_wb(
|
|
161
|
+
indicators: dict, prefix: str = "wb", add_ppp_exchange: bool = False
|
|
162
|
+
) -> None:
|
|
130
163
|
"""Download multiple World Bank indicators in parallel and save as a parquet file.
|
|
131
164
|
|
|
132
165
|
This function fetches all indicators defined in _INDICATORS in parallel, concatenates
|
|
@@ -134,7 +167,7 @@ def download_wb() -> None:
|
|
|
134
167
|
"""
|
|
135
168
|
logger.info("Downloading the latest World Bank data...")
|
|
136
169
|
|
|
137
|
-
indicators_data = _parallel_download_indicators(indicators=
|
|
170
|
+
indicators_data = _parallel_download_indicators(indicators=indicators)
|
|
138
171
|
|
|
139
172
|
# Concatenate all DataFrames horizontally (by columns)
|
|
140
173
|
df = pd.concat(indicators_data, axis=1).reset_index()
|
|
@@ -145,7 +178,13 @@ def download_wb() -> None:
|
|
|
145
178
|
.pipe(compute_exchange_deflator, base_year_measure="NGDP_D")
|
|
146
179
|
.assign(pydeflate_iso3=lambda d: d.entity_code)
|
|
147
180
|
.sort_values(by=["year", "entity_code"])
|
|
148
|
-
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
if add_ppp_exchange:
|
|
184
|
+
df = df.pipe(_add_ppp_ppp_exchange)
|
|
185
|
+
|
|
186
|
+
df = (
|
|
187
|
+
df.pipe(prefix_pydeflate_to_columns)
|
|
149
188
|
.pipe(enforce_pyarrow_types)
|
|
150
189
|
.reset_index(drop=True)
|
|
151
190
|
)
|
|
@@ -154,10 +193,29 @@ def download_wb() -> None:
|
|
|
154
193
|
suffix = today()
|
|
155
194
|
|
|
156
195
|
# Save the DataFrame as a parquet file
|
|
157
|
-
output_path = PYDEFLATE_PATHS.data / f"
|
|
196
|
+
output_path = PYDEFLATE_PATHS.data / f"{prefix}_{suffix}.parquet"
|
|
158
197
|
df.to_parquet(output_path)
|
|
159
198
|
|
|
160
|
-
logger.info(f"Saved World Bank data to
|
|
199
|
+
logger.info(f"Saved World Bank data to {prefix}_{suffix}.parquet")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def download_wb() -> None:
|
|
203
|
+
"""Download the latest World Bank data."""
|
|
204
|
+
_download_wb(indicators=_INDICATORS, prefix="wb")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def download_wb_lcu_ppp() -> None:
|
|
208
|
+
"""Download the latest World Bank data (PPP)."""
|
|
209
|
+
_download_wb(
|
|
210
|
+
indicators=_INDICATORS_LCU_PPP, prefix="wb_lcu_ppp", add_ppp_exchange=True
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def download_wb_usd_ppp() -> None:
|
|
215
|
+
"""Download the latest World Bank data (PPP)."""
|
|
216
|
+
_download_wb(
|
|
217
|
+
indicators=_INDICATORS_USD_PPP, prefix="wb_usd_ppp", add_ppp_exchange=True
|
|
218
|
+
)
|
|
161
219
|
|
|
162
220
|
|
|
163
221
|
def _find_wb_files_in_path(path: Path) -> list:
|
|
@@ -169,7 +227,31 @@ def _find_wb_files_in_path(path: Path) -> list:
|
|
|
169
227
|
Returns:
|
|
170
228
|
list: List of WB parquet files found in the directory.
|
|
171
229
|
"""
|
|
172
|
-
return list(path.glob("wb_*.parquet"))
|
|
230
|
+
return list(path.glob(f"wb_*.parquet"))
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _find_wb_lcu_ppp_files_in_path(path: Path) -> list:
|
|
234
|
+
"""Find all WB PPP parquet files in the specified directory.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
path (Path): The directory path to search for WB parquet files.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
list: List of WB parquet files found in the directory.
|
|
241
|
+
"""
|
|
242
|
+
return list(path.glob(f"wb_lcu_ppp_*.parquet"))
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _find_wb_usd_ppp_files_in_path(path: Path) -> list:
|
|
246
|
+
"""Find all WB PPP parquet files in the specified directory.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
path (Path): The directory path to search for WB parquet files.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
list: List of WB parquet files found in the directory.
|
|
253
|
+
"""
|
|
254
|
+
return list(path.glob(f"wb_usd_ppp_*.parquet"))
|
|
173
255
|
|
|
174
256
|
|
|
175
257
|
def read_wb(update: bool = False) -> pd.DataFrame:
|
|
@@ -182,5 +264,27 @@ def read_wb(update: bool = False) -> pd.DataFrame:
|
|
|
182
264
|
)
|
|
183
265
|
|
|
184
266
|
|
|
267
|
+
def read_wb_lcu_ppp(update: bool = False) -> pd.DataFrame:
|
|
268
|
+
"""Read the latest World Bank data from parquet files or download fresh data."""
|
|
269
|
+
return read_data(
|
|
270
|
+
file_finder_func=_find_wb_lcu_ppp_files_in_path,
|
|
271
|
+
download_func=download_wb_lcu_ppp,
|
|
272
|
+
data_name="World Bank",
|
|
273
|
+
update=update,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def read_wb_usd_ppp(update: bool = False) -> pd.DataFrame:
|
|
278
|
+
"""Read the latest World Bank data from parquet files or download fresh data."""
|
|
279
|
+
return read_data(
|
|
280
|
+
file_finder_func=_find_wb_usd_ppp_files_in_path,
|
|
281
|
+
download_func=download_wb_usd_ppp,
|
|
282
|
+
data_name="World Bank",
|
|
283
|
+
update=update,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
|
|
185
287
|
if __name__ == "__main__":
|
|
186
|
-
|
|
288
|
+
df_wb = read_wb(False)
|
|
289
|
+
df_usd = read_wb_usd_ppp(False)
|
|
290
|
+
df_lcu = read_wb_lcu_ppp(False)
|
pydeflate/utils.py
CHANGED
|
@@ -35,6 +35,7 @@ def clean_number(number):
|
|
|
35
35
|
|
|
36
36
|
return float(number)
|
|
37
37
|
|
|
38
|
+
|
|
38
39
|
def create_pydeflate_year(
|
|
39
40
|
data: pd.DataFrame, year_column: str, year_format: str | None = None
|
|
40
41
|
) -> pd.DataFrame:
|
|
@@ -50,21 +51,68 @@ def create_pydeflate_year(
|
|
|
50
51
|
return data
|
|
51
52
|
|
|
52
53
|
|
|
54
|
+
def _use_implied_dac_rates(
|
|
55
|
+
data: pd.DataFrame,
|
|
56
|
+
pydeflate_data: pd.DataFrame,
|
|
57
|
+
ix: list[str],
|
|
58
|
+
entity_column: str,
|
|
59
|
+
source_codes: bool,
|
|
60
|
+
) -> pd.DataFrame:
|
|
61
|
+
"""When rates are missing for entities in DAC data, the correct behaviour is to use
|
|
62
|
+
the DAC overall rates"""
|
|
63
|
+
|
|
64
|
+
# Assign the DAC code to a temporary column
|
|
65
|
+
data.loc[
|
|
66
|
+
lambda d: ~d[f"temp_{entity_column}"].isin(pydeflate_data[ix[-1]].unique()),
|
|
67
|
+
f"temp_{entity_column}",
|
|
68
|
+
] = (
|
|
69
|
+
20001 if source_codes else "DAC"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Log the fact that implied rates are being used
|
|
73
|
+
flag_missing_pydeflate_data(
|
|
74
|
+
unmatched_data=data.loc[
|
|
75
|
+
lambda d: ~d[f"{entity_column}"].isin(pydeflate_data[ix[-1]].unique())
|
|
76
|
+
],
|
|
77
|
+
entity_column=entity_column,
|
|
78
|
+
year_column="pydeflate_year",
|
|
79
|
+
using_implied=True,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return data
|
|
83
|
+
|
|
84
|
+
|
|
53
85
|
def merge_user_and_pydeflate_data(
|
|
54
86
|
data: pd.DataFrame,
|
|
55
87
|
pydeflate_data: pd.DataFrame,
|
|
56
88
|
entity_column: str,
|
|
57
89
|
ix: list[str],
|
|
90
|
+
source_codes: bool = True,
|
|
91
|
+
dac: bool = False,
|
|
58
92
|
) -> pd.DataFrame:
|
|
59
|
-
|
|
93
|
+
|
|
94
|
+
data[f"temp_{entity_column}"] = data[entity_column]
|
|
95
|
+
|
|
96
|
+
if dac:
|
|
97
|
+
data = _use_implied_dac_rates(
|
|
98
|
+
data=data,
|
|
99
|
+
pydeflate_data=pydeflate_data,
|
|
100
|
+
ix=ix,
|
|
101
|
+
entity_column=entity_column,
|
|
102
|
+
source_codes=source_codes,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
df_ = data.merge(
|
|
60
106
|
pydeflate_data,
|
|
61
107
|
how="outer",
|
|
62
|
-
left_on=["pydeflate_year", entity_column],
|
|
108
|
+
left_on=["pydeflate_year", f"temp_{entity_column}"],
|
|
63
109
|
right_on=ix,
|
|
64
110
|
suffixes=("", "_pydeflate"),
|
|
65
111
|
indicator=True,
|
|
66
112
|
).pipe(enforce_pyarrow_types)
|
|
67
113
|
|
|
114
|
+
return df_.drop(columns=[f"temp_{entity_column}"])
|
|
115
|
+
|
|
68
116
|
|
|
69
117
|
def get_unmatched_pydeflate_data(
|
|
70
118
|
merged_data: pd.DataFrame,
|
|
@@ -84,17 +132,29 @@ def get_matched_pydeflate_data(
|
|
|
84
132
|
)
|
|
85
133
|
|
|
86
134
|
|
|
87
|
-
def flag_missing_pydeflate_data(
|
|
135
|
+
def flag_missing_pydeflate_data(
|
|
136
|
+
unmatched_data: pd.DataFrame,
|
|
137
|
+
entity_column: str,
|
|
138
|
+
year_column: str,
|
|
139
|
+
using_implied: bool = False,
|
|
140
|
+
):
|
|
88
141
|
"""Flag data which is present in the input data but missing in pydeflate's data."""
|
|
89
142
|
if unmatched_data.empty:
|
|
90
143
|
return
|
|
91
|
-
|
|
92
144
|
missing = (
|
|
93
|
-
unmatched_data.
|
|
94
|
-
.
|
|
95
|
-
.
|
|
96
|
-
.
|
|
145
|
+
unmatched_data.filter([entity_column, year_column])
|
|
146
|
+
.drop_duplicates()
|
|
147
|
+
.groupby(entity_column)[year_column]
|
|
148
|
+
.apply(lambda x: ", ".join(map(str, sorted(x))))
|
|
149
|
+
.to_dict()
|
|
97
150
|
)
|
|
98
151
|
|
|
152
|
+
missing_str = "\n".join(f"{entity}: {years}" for entity, years in missing.items())
|
|
153
|
+
|
|
99
154
|
# log all missing data
|
|
100
|
-
|
|
155
|
+
message = (
|
|
156
|
+
"Using DAC members' rates (given missing data) for:"
|
|
157
|
+
if using_implied
|
|
158
|
+
else "Missing exchange data for:"
|
|
159
|
+
)
|
|
160
|
+
logger.info(f"{message}\n{missing_str}")
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: pydeflate
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: Package to convert current prices figures to constant prices and vice versa
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Jorge Rivera
|
|
7
7
|
Author-email: jorge.rivera@one.org
|
|
8
|
-
Requires-Python: >=3.10
|
|
9
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
-
Classifier: Intended Audience :: End Users/Desktop
|
|
11
|
-
Classifier: Intended Audience :: Science/Research
|
|
8
|
+
Requires-Python: >=3.10, <4.0
|
|
12
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Classifier: Natural Language :: English
|
|
14
10
|
Classifier: Programming Language :: Python :: 3
|
|
15
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
-
Requires-Dist: hdx-python-country (>=3.8
|
|
20
|
-
Requires-Dist: imf-reader (>=1.
|
|
21
|
-
Requires-Dist: oda-reader (>=1.0.
|
|
22
|
-
Requires-Dist: pandas (>=2,<3)
|
|
23
|
-
Requires-Dist: pyarrow (
|
|
15
|
+
Requires-Dist: hdx-python-country (>=3.8,<4.0.0)
|
|
16
|
+
Requires-Dist: imf-reader (>=1.2.0,<2.0.0)
|
|
17
|
+
Requires-Dist: oda-reader (>=1.0.5,<2.0.0)
|
|
18
|
+
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
|
19
|
+
Requires-Dist: pyarrow (>=14.0)
|
|
20
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
24
21
|
Requires-Dist: wbgapi (>=1.0.12,<2.0.0)
|
|
25
22
|
Description-Content-Type: text/markdown
|
|
26
23
|
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
pydeflate/.pydeflate_data/README.md,sha256=atNtUL9dD8G184YSd6juFib8TgEQBcSLogiz99APPVs,25
|
|
2
|
-
pydeflate/__init__.py,sha256=
|
|
2
|
+
pydeflate/__init__.py,sha256=JJqxQpHXxfqzada3FkaneDTW9BlNM40CBwjJgEZZ4tQ,1013
|
|
3
3
|
pydeflate/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
pydeflate/core/api.py,sha256
|
|
4
|
+
pydeflate/core/api.py,sha256=mD5zhGlAIvlpT6KcmrHW5rmYwtEq5x2Pqo-jQCQMGpo,14687
|
|
5
5
|
pydeflate/core/deflator.py,sha256=Ax3dmOF3tYRZnkIfFvMMo3SOLgAJHkXSmA-OtIUZkp0,5932
|
|
6
6
|
pydeflate/core/exchange.py,sha256=br6RVgTGa7LW09XemUJZ4Koazf65zuXPQKYKGhS6ROM,8535
|
|
7
|
-
pydeflate/core/source.py,sha256=
|
|
7
|
+
pydeflate/core/source.py,sha256=n603ocgGjthXNcBWwgADkefxWmSFuN77Km9Z0T2zpIg,2027
|
|
8
8
|
pydeflate/deflate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
pydeflate/deflate/deflators.py,sha256=hyLFoX46BAn5m8gTLjw-TFv3x3W6CTQmvmUvq5a_cio,7768
|
|
10
10
|
pydeflate/deflate/legacy_deflate.py,sha256=9pfqsi5KeWgP1yhXeI6K7bAjUeFY-fmRxrpDB7Zu0zo,3900
|
|
11
11
|
pydeflate/exchange/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
pydeflate/exchange/exchangers.py,sha256=
|
|
12
|
+
pydeflate/exchange/exchangers.py,sha256=_3QA3gzUQJgtR6o5n7qrVq8WKLL7x01A8V_DtW8ocPI,6768
|
|
13
13
|
pydeflate/pydeflate_config.py,sha256=5s4SLJf5is5XcUgJHDRx4f27pPiaVh0H2BL8w9QjW0k,1097
|
|
14
14
|
pydeflate/settings/emu.json,sha256=BIvbiMUeHUtCESR3sMcBNrS028yp2YraCJdhDJGvAAo,133
|
|
15
15
|
pydeflate/settings/oecd_codes.json,sha256=jAKI1EgQP4rttjoG3Z-44r1tUJrIEzPCZF5V2aboQhE,911
|
|
16
16
|
pydeflate/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
pydeflate/sources/common.py,sha256=
|
|
17
|
+
pydeflate/sources/common.py,sha256=TvoN3jnqn0xXNuxM52vvgSLA5WRGX8PUD-b5YH6S7GE,9882
|
|
18
18
|
pydeflate/sources/dac.py,sha256=ngFiApGZ_tIQg74ogGVTIbGUA0efnF1SYwfUuqGofOQ,3791
|
|
19
19
|
pydeflate/sources/imf.py,sha256=10vc8xhNJvANb7RDD1WFn9oaZ8g53yUV5LxCQCz6ImM,6337
|
|
20
|
-
pydeflate/sources/world_bank.py,sha256=
|
|
21
|
-
pydeflate/utils.py,sha256=
|
|
22
|
-
pydeflate-2.
|
|
23
|
-
pydeflate-2.
|
|
24
|
-
pydeflate-2.
|
|
25
|
-
pydeflate-2.
|
|
20
|
+
pydeflate/sources/world_bank.py,sha256=uMHidFVgEpj1HVUnNhIZV-rV64hsCBV9ZAbYKk6H0Vw,9333
|
|
21
|
+
pydeflate/utils.py,sha256=tJBd271WzZxVhW9ZMiIRHR0fZWr_MagAYLdmXXaUY3M,3983
|
|
22
|
+
pydeflate-2.1.1.dist-info/LICENSE,sha256=q5tm9mQxwSbV5Ivvjxs7MMqBgan6DM8I4r4irPvmqZM,1075
|
|
23
|
+
pydeflate-2.1.1.dist-info/METADATA,sha256=9_x0yAsOsj70V9dESsz9C89UuQuxc_TTQkyamDDXne4,12437
|
|
24
|
+
pydeflate-2.1.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
|
25
|
+
pydeflate-2.1.1.dist-info/RECORD,,
|
|
File without changes
|