[BugFix] Clean Up Nominal GDP & Add EconDB As Provider (#6581)

* clean up nominal gdp and add econdb as provider

* small fix

* test params

* test cassette

* now the other test cassette
This commit is contained in:
Danglewood
2024-07-13 01:09:55 -07:00
committed by GitHub
parent 5f8b06744e
commit 017ce1c82e
15 changed files with 1186 additions and 194 deletions

View File

@@ -1,9 +1,9 @@
"""Nominal GDP Standard Model."""
from datetime import date as dateType
from typing import Literal, Optional
from typing import Optional, Union
from pydantic import Field, field_validator
from pydantic import Field
from openbb_core.provider.abstract.data import Data
from openbb_core.provider.abstract.query_params import QueryParams
@@ -16,11 +16,6 @@ from openbb_core.provider.utils.descriptions import (
class GdpNominalQueryParams(QueryParams):
"""Nominal GDP Query."""
units: Literal["usd", "usd_cap"] = Field(
default="usd",
description=QUERY_DESCRIPTIONS.get("units", "")
+ " Units to get nominal GDP in. Either usd or usd_cap indicating per capita.",
)
start_date: Optional[dateType] = Field(
default=None, description=QUERY_DESCRIPTIONS.get("start_date")
)
@@ -28,19 +23,14 @@ class GdpNominalQueryParams(QueryParams):
default=None, description=QUERY_DESCRIPTIONS.get("end_date")
)
@field_validator("units", mode="before", check_fields=False)
@classmethod
def to_lower(cls, v: Optional[str]) -> Optional[str]:
"""Convert field to lowercase."""
return v.lower() if v else v
class GdpNominalData(Data):
"""Nominal GDP Data."""
date: Optional[dateType] = Field(
default=None, description=DATA_DESCRIPTIONS.get("date")
date: dateType = Field(description=DATA_DESCRIPTIONS.get("date"))
country: str = Field(
default=None, description="The country represented by the GDP value."
)
value: Optional[float] = Field(
default=None, description="Nominal GDP value on the date."
value: Union[int, float] = Field(
description="GDP value for the country and date.",
)

View File

@@ -173,17 +173,20 @@ def test_economy_gdp_forecast(params, headers):
[
(
{
"units": "usd",
"country": "united_states",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"provider": "oecd",
"provider": "econdb",
"use_cache": False,
}
),
(
{
"country": "united_states",
"provider": "oecd",
"units": "usd",
"units": "level",
"frequency": "quarter",
"price_base": "volume",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
}

View File

@@ -160,13 +160,23 @@ def test_economy_gdp_forecast(params, obb):
@parametrize(
"params",
[
({"units": "usd", "start_date": "2021-01-01", "end_date": "2023-06-06"}),
(
{
"country": "united_states",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"provider": "econdb",
"use_cache": False,
}
),
(
{
"country": "united_states",
"provider": "oecd",
"units": "usd",
"start_date": "2021-01-01",
"units": "level",
"price_base": "volume",
"frequency": "quarter",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
}
),

View File

@@ -2637,17 +2637,9 @@
"message": null
},
"description": "Get Nominal GDP Data.",
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.gdp.nominal(provider='oecd')\nobb.economy.gdp.nominal(units='usd', provider='oecd')\n```\n\n",
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.gdp.nominal(provider='oecd')\nobb.economy.gdp.nominal(units=usd, provider='oecd')\n```\n\n",
"parameters": {
"standard": [
{
"name": "units",
"type": "Literal['usd', 'usd_cap']",
"description": "The unit of measurement for the data. Units to get nominal GDP in. Either usd or usd_cap indicating per capita.",
"default": "usd",
"optional": true,
"choices": null
},
{
"name": "start_date",
"type": "Union[date, str]",
@@ -2666,20 +2658,190 @@
},
{
"name": "provider",
"type": "Literal['oecd']",
"description": "The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd.",
"type": "Literal['econdb', 'oecd']",
"description": "The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: econdb, oecd.",
"default": null,
"optional": true
}
],
"econdb": [
{
"name": "country",
"type": "Union[str, List[str]]",
"description": "The country to get data.Use 'all' to get data for all available countries. Multiple items allowed for provider(s): econdb, oecd.",
"default": "united_states",
"optional": true,
"choices": [
"oecd",
"oecd_26",
"oecd_europe",
"g7",
"g20",
"euro_area",
"european_union_27",
"european_union_15",
"nafta",
"argentina",
"australia",
"austria",
"belgium",
"bulgaria",
"brazil",
"canada",
"chile",
"colombia",
"costa_rica",
"croatia",
"czech_republic",
"denmark",
"estonia",
"finland",
"france",
"germany",
"greece",
"hungary",
"iceland",
"india",
"indonesia",
"ireland",
"israel",
"italy",
"japan",
"korea",
"latvia",
"lithuania",
"luxembourg",
"mexico",
"netherlands",
"new_zealand",
"norway",
"poland",
"portugal",
"romania",
"russia",
"saudi_arabia",
"slovak_republic",
"slovenia",
"south_africa",
"spain",
"sweden",
"switzerland",
"turkey",
"united_kingdom",
"united_states",
"all"
]
},
{
"name": "use_cache",
"type": "bool",
"description": "If True, the request will be cached for one day. Using cache is recommended to avoid needlessly requesting the same data.",
"default": true,
"optional": true,
"choices": null
}
],
"oecd": [
{
"name": "country",
"type": "Literal['australia', 'austria', 'belgium', 'brazil', 'canada', 'chile', 'colombia', 'costa_rica', 'czech_republic', 'denmark', 'estonia', 'euro_area', 'european_union', 'finland', 'france', 'germany', 'greece', 'hungary', 'iceland', 'indonesia', 'ireland', 'israel', 'italy', 'japan', 'korea', 'latvia', 'lithuania', 'luxembourg', 'mexico', 'netherlands', 'new_zealand', 'norway', 'poland', 'portugal', 'russia', 'slovak_republic', 'slovenia', 'south_africa', 'spain', 'sweden', 'switzerland', 'turkey', 'united_kingdom', 'united_states', 'all']",
"description": "Country to get GDP for.",
"type": "Union[str, List[str]]",
"description": "The country to get data. Use 'all' to get data for all available countries. Multiple items allowed for provider(s): oecd.",
"default": "united_states",
"optional": true,
"choices": null
"choices": [
"oecd",
"oecd_26",
"oecd_europe",
"g7",
"g20",
"euro_area",
"european_union_27",
"european_union_15",
"nafta",
"argentina",
"australia",
"austria",
"belgium",
"bulgaria",
"brazil",
"canada",
"chile",
"colombia",
"costa_rica",
"croatia",
"czech_republic",
"denmark",
"estonia",
"finland",
"france",
"germany",
"greece",
"hungary",
"iceland",
"india",
"indonesia",
"ireland",
"israel",
"italy",
"japan",
"korea",
"latvia",
"lithuania",
"luxembourg",
"mexico",
"netherlands",
"new_zealand",
"norway",
"poland",
"portugal",
"romania",
"russia",
"saudi_arabia",
"slovak_republic",
"slovenia",
"south_africa",
"spain",
"sweden",
"switzerland",
"turkey",
"united_kingdom",
"united_states",
"all"
]
},
{
"name": "frequency",
"type": "Literal['quarter', 'annual']",
"description": "Frequency of the data.",
"default": "quarter",
"optional": true,
"choices": [
"quarter",
"annual"
]
},
{
"name": "units",
"type": "Literal['level', 'index', 'capita']",
"description": "The unit of measurement for the data.Both 'level' and 'capita' (per) are measured in USD.",
"default": "level",
"optional": true,
"choices": [
"level",
"index",
"capita"
]
},
{
"name": "price_base",
"type": "Literal['current_prices', 'volume']",
"description": "Price base for the data, volume is chain linked volume.",
"default": "current_prices",
"optional": true,
"choices": [
"current_prices",
"volume"
]
}
]
},
@@ -2692,7 +2854,7 @@
},
{
"name": "provider",
"type": "Optional[Literal['oecd']]",
"type": "Optional[Literal['econdb', 'oecd']]",
"description": "Provider name."
},
{
@@ -2718,16 +2880,50 @@
"name": "date",
"type": "date",
"description": "The date of the data.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "country",
"type": "str",
"description": "The country represented by the GDP value.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "value",
"type": "Union[int, float]",
"description": "GDP value for the country and date.",
"default": "",
"optional": false,
"choices": null
}
],
"econdb": [
{
"name": "value",
"type": "Union[int, float]",
"description": "GDP value for the country and date.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "real_growth_qoq",
"type": "float",
"description": "Nominal GDP value on the date.",
"default": null,
"optional": true,
"description": "Real GDP growth rate quarter over quarter.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "real_growth_yoy",
"type": "float",
"description": "Real GDP growth rate year over year.",
"default": "",
"optional": false,
"choices": null
}
],

View File

@@ -122,12 +122,6 @@ class ROUTER_economy_gdp(Container):
@validate
def nominal(
self,
units: Annotated[
Literal["usd", "usd_cap"],
OpenBBField(
description="The unit of measurement for the data. Units to get nominal GDP in. Either usd or usd_cap indicating per capita."
),
] = "usd",
start_date: Annotated[
Union[datetime.date, None, str],
OpenBBField(description="Start date of the data, in YYYY-MM-DD format."),
@@ -137,9 +131,9 @@ class ROUTER_economy_gdp(Container):
OpenBBField(description="End date of the data, in YYYY-MM-DD format."),
] = None,
provider: Annotated[
Optional[Literal["oecd"]],
Optional[Literal["econdb", "oecd"]],
OpenBBField(
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd."
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: econdb, oecd."
),
] = None,
**kwargs
@@ -148,23 +142,29 @@ class ROUTER_economy_gdp(Container):
Parameters
----------
units : Literal['usd', 'usd_cap']
The unit of measurement for the data. Units to get nominal GDP in. Either usd or usd_cap indicating per capita.
start_date : Union[datetime.date, None, str]
Start date of the data, in YYYY-MM-DD format.
end_date : Union[datetime.date, None, str]
End date of the data, in YYYY-MM-DD format.
provider : Optional[Literal['oecd']]
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd.
country : Literal['australia', 'austria', 'belgium', 'brazil', 'canada', 'chile', 'colombia', 'costa_rica', 'czech_republic', 'denmark', 'estonia', 'euro_area', 'european_union', 'finland', 'france', 'germany', 'greece', 'hungary', 'iceland', 'indonesia', 'ireland', 'israel', 'italy', 'japan', 'korea', 'latvia', 'lithuania', 'luxembourg', 'mexico', 'netherlands', 'new_zealand', 'norway', 'poland', 'portugal', 'russia', 'slovak_republic', 'slovenia', 'south_africa', 'spain', 'sweden', 'switzerland', 'turkey', 'united_kingdom', 'united_states', 'all']
Country to get GDP for. (provider: oecd)
provider : Optional[Literal['econdb', 'oecd']]
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: econdb, oecd.
country : str
The country to get data.Use 'all' to get data for all available countries. Multiple comma separated items allowed. (provider: econdb, oecd)
use_cache : bool
If True, the request will be cached for one day. Using cache is recommended to avoid needlessly requesting the same data. (provider: econdb)
frequency : Literal['quarter', 'annual']
Frequency of the data. (provider: oecd)
units : Literal['level', 'index', 'capita']
The unit of measurement for the data.Both 'level' and 'capita' (per) are measured in USD. (provider: oecd)
price_base : Literal['current_prices', 'volume']
Price base for the data, volume is chain linked volume. (provider: oecd)
Returns
-------
OBBject
results : List[GdpNominal]
Serializable results.
provider : Optional[Literal['oecd']]
provider : Optional[Literal['econdb', 'oecd']]
Provider name.
warnings : Optional[List[Warning_]]
List of warnings.
@@ -175,10 +175,16 @@ class ROUTER_economy_gdp(Container):
GdpNominal
----------
date : Optional[date]
date : date
The date of the data.
value : Optional[float]
Nominal GDP value on the date.
country : Optional[str]
The country represented by the GDP value.
value : Union[int, float]
GDP value for the country and date.
real_growth_qoq : Optional[float]
Real GDP growth rate quarter over quarter. (provider: econdb)
real_growth_yoy : Optional[float]
Real GDP growth rate year over year. (provider: econdb)
Examples
--------
@@ -194,15 +200,20 @@ class ROUTER_economy_gdp(Container):
"provider": self._get_provider(
provider,
"economy.gdp.nominal",
("oecd",),
("econdb", "oecd"),
)
},
standard_params={
"units": units,
"start_date": start_date,
"end_date": end_date,
},
extra_params=kwargs,
info={
"country": {
"econdb": {"multiple_items_allowed": True},
"oecd": ["multiple_items_allowed"],
}
},
)
)

View File

@@ -4,6 +4,7 @@ from openbb_core.provider.abstract.provider import Provider
from openbb_econdb.models.available_indicators import EconDbAvailableIndicatorsFetcher
from openbb_econdb.models.country_profile import EconDbCountryProfileFetcher
from openbb_econdb.models.economic_indicators import EconDbEconomicIndicatorsFetcher
from openbb_econdb.models.gdp_nominal import EconDbGdpNominalFetcher
from openbb_econdb.models.yield_curve import EconDbYieldCurveFetcher
econdb_provider = Provider(
@@ -22,6 +23,7 @@ aggregate statistics.""",
"AvailableIndicators": EconDbAvailableIndicatorsFetcher,
"CountryProfile": EconDbCountryProfileFetcher,
"EconomicIndicators": EconDbEconomicIndicatorsFetcher,
"GdpNominal": EconDbGdpNominalFetcher,
"YieldCurve": EconDbYieldCurveFetcher,
},
repr_name="EconDB",

View File

@@ -0,0 +1,209 @@
"""EconDB GDP Nominal Model."""
# pylint: disable=unused-argument
from typing import Any, Dict, List, Optional, Union
from warnings import warn
from openbb_core.app.model.abstract.error import OpenBBError
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.standard_models.gdp_nominal import (
GdpNominalData,
GdpNominalQueryParams,
)
from openbb_core.provider.utils.descriptions import (
QUERY_DESCRIPTIONS,
)
from openbb_core.provider.utils.errors import EmptyDataError
from pydantic import Field, field_validator
class EconDbGdpNominalQueryParams(GdpNominalQueryParams):
"""EconDB GDP Nominal Query."""
__json_schema_extra__ = {
"country": {"multiple_items_allowed": True},
}
country: str = Field(
description=QUERY_DESCRIPTIONS.get("country", "")
+ "Use 'all' to get data for all available countries.",
default="united_states",
)
use_cache: bool = Field(
default=True,
description="If True, the request will be cached for one day."
+ " Using cache is recommended to avoid needlessly requesting the same data.",
)
@field_validator("country", mode="before", check_fields=False)
@classmethod
def validate_country(cls, v):
"""Validate the country."""
# pylint: disable=import-outside-toplevel
from openbb_econdb.utils.helpers import (
COUNTRY_GROUPS,
COUNTRY_MAP,
INDICATOR_COUNTRIES,
THREE_LETTER_ISO_MAP,
)
country = v if isinstance(v, list) else v.split(",")
if "all" in country:
return ",".join(INDICATOR_COUNTRIES.get("GDP"))
for c in country.copy():
if (
len(c) == 2
and c.upper() not in list(COUNTRY_MAP.values())
and c.lower() != "g7"
) or (
len(c) > 3 and c.lower() not in list(COUNTRY_MAP) + list(COUNTRY_GROUPS)
):
country.remove(c)
elif len(c) == 3 and c.lower() != "g20":
_c = THREE_LETTER_ISO_MAP.get(c.upper(), "")
if _c: # pylint: disable=R0801
country[country.index(c)] = _c
else:
warn(f"Error: {c} is not a valid country code.")
country.remove(c)
elif len(c) > 3 and c.lower() in COUNTRY_MAP:
country[country.index(c)] = COUNTRY_MAP[c.lower()].upper()
elif len(c) > 2 and c.lower() in COUNTRY_GROUPS:
country[country.index(c)] = ",".join(COUNTRY_GROUPS[c.lower()])
if len(country) == 0:
raise OpenBBError("No valid countries were supplied.")
return ",".join(country)
class EconDbGdpNominalData(GdpNominalData):
"""EconDB GDP Nominal Data."""
real_growth_qoq: float = Field(
description="Real GDP growth rate quarter over quarter.",
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
)
real_growth_yoy: float = Field(
description="Real GDP growth rate year over year.",
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
)
value: Union[int, float] = Field(
description="GDP value for the country and date.",
json_schema_extra={"x-unit_measurement": "currency"},
)
class EconDbGdpNominalFetcher(
Fetcher[
EconDbGdpNominalQueryParams,
List[EconDbGdpNominalData],
]
):
"""EconDB GDP Nominal Fetcher."""
require_credentials = False
@staticmethod
def transform_query(params: Dict[str, Any]) -> EconDbGdpNominalQueryParams:
"""Transform the query parameters."""
return EconDbGdpNominalQueryParams(**params)
@staticmethod
async def aextract_data(
query: EconDbGdpNominalQueryParams,
credentials: Optional[Dict[str, str]],
**kwargs,
) -> List[Dict]:
"""Extract the data."""
# pylint: disable=import-outside-toplevel
import asyncio # noqa
from pandas import DataFrame, concat
from openbb_econdb.utils.helpers import get_context, parse_context
country = query.country.split(",")
results: List = []
async def get_one_country(_country):
"""Get the GDP data for one country."""
_country = _country.upper()
final_df = DataFrame()
gdp_response, gdp_qoq_response, gdp_yoy_response = await asyncio.gather(
get_context("GDP", _country, "TUSD", query.use_cache),
get_context("RGDP", _country, "TPOP", query.use_cache),
get_context("RGDP", _country, "TOYA", query.use_cache),
)
gdp = parse_context(gdp_response, latest=False).rename(columns={"GDP": "value"}) # type: ignore
gdp_qoq = parse_context(gdp_qoq_response, latest=False).rename(columns={"RGDP": "real_growth_qoq"}) # type: ignore
gdp_yoy = parse_context(gdp_yoy_response, latest=False).rename(columns={"RGDP": "real_growth_yoy"}) # type: ignore
gdp = (
gdp.set_index("Country", append=True)
if "Country" in gdp.columns
else gdp
)
gdp_qoq = (
gdp_qoq.set_index("Country", append=True)
if "Country" in gdp_qoq.columns
else gdp_qoq
)
gdp_yoy = (
gdp_yoy.set_index("Country", append=True)
if "Country" in gdp_yoy.columns
else gdp_yoy
)
final_df = concat(
[gdp, gdp_qoq, gdp_yoy],
axis=1,
)
if final_df.empty:
warn(f"Error: No data returned for {_country}.")
if not final_df.empty:
results.extend(
final_df.reset_index()
.rename(columns={"Country": "country"})
.to_dict(orient="records")
)
chunks = [country[i : i + 5] for i in range(0, len(country), 5)]
for chunk in chunks:
await asyncio.gather(*[get_one_country(c) for c in chunk])
if not results:
raise EmptyDataError("The request returned empty.")
return results
@staticmethod
def transform_data(
query: EconDbGdpNominalQueryParams,
data: List[Dict],
**kwargs,
) -> List[EconDbGdpNominalData]:
"""Transform the data."""
# pylint: disable=import-outside-toplevel
from pandas import DataFrame, to_datetime
df = DataFrame(data)
if query.start_date:
df = df[to_datetime(df["date"]) >= to_datetime(query.start_date)]
if query.end_date:
df = df[to_datetime(df["date"]) <= to_datetime(query.end_date)]
if df.empty: # type: ignore
raise EmptyDataError(
"No data was found for the supplied date range and countries."
)
df = df.set_index(["date", "country"]) # type: ignore
df = df.dropna()
df["value"] = (df["value"] * 1_000_000_000).astype("int64")
df["real_growth_qoq"] = df["real_growth_qoq"] / 100
df["real_growth_yoy"] = df["real_growth_yoy"] / 100
df = df.reset_index()
df = df.sort_values(by=["date", "value"], ascending=[True, False])
return [
EconDbGdpNominalData.model_validate(d) for d in df.to_dict(orient="records")
]

View File

@@ -0,0 +1,231 @@
interactions:
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://www.econdb.com/series/context/?tickers=%5BRGDPIN~TOYA%5D
response:
body:
string: !!binary |
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
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 8a225a33fe3f842f-YVR
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Fri, 12 Jul 2024 16:18:59 GMT
NEL:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Referrer-Policy:
- same-origin
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=FgSHgHZwEWdso2Hd6X6mEB%2BPLPkFwMZ4yHBe6eYsoF91I%2FwbyyZ2CdLpTzRSEWXe%2F8R%2BRqtNKRl%2BVmp1Lcn7sOgoiKUDy%2FBOjapNhQ3GM6crx1vgvL3FjvH2RhcL4%2F2CZE0iN02atES88o%2Bp"}],"group":"cf-nel","max_age":604800}'
Server:
- cloudflare
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
- Origin
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://www.econdb.com/series/context/?tickers=%5BRGDPIN~TPOP%5D
response:
body:
string: !!binary |
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
yYdDcX2+/Q8GHBSHsCAAAA==
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 8a225a33fd612d7e-YVR
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Fri, 12 Jul 2024 16:18:59 GMT
NEL:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Referrer-Policy:
- same-origin
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=W9hythUsRfvZJiIQQYqKt%2FgwbrbjHGy%2B9064ijxKoBgIYSkXcL%2Bwwi0AZz7PF71byD7%2F6wxxtRJxqgi046EXORTYKfznTA7syZqqCN2iSQ%2Bb%2BIjSug5aMEtSclW9akNMBtxAzU2fSocVy8st"}],"group":"cf-nel","max_age":604800}'
Server:
- cloudflare
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
- Origin
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://www.econdb.com/series/context/?tickers=%5BGDPIN~TUSD%5D
response:
body:
string: !!binary |
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
0tAfAAA=
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 8a225a340d6d840e-YVR
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Fri, 12 Jul 2024 16:18:59 GMT
NEL:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Referrer-Policy:
- same-origin
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=tBsVKCJZUiJS4RST46xBmYWRwJVwZ3BbTKG1aF8dpG4XO6RQeWQmmB%2F7WeJwOgfdAyzzqyFRuKMP45vAfr6kBW65i1bjUE1l0q3Wq9BLnvmyaOr3oM3GGtnYCaCftygqHUDCgawYAfOqwNrb"}],"group":"cf-nel","max_age":604800}'
Server:
- cloudflare
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
- Origin
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,231 @@
interactions:
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://www.econdb.com/series/context/?tickers=%5BRGDPIN~TOYA%5D
response:
body:
string: !!binary |
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
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 8a2256fb5ccb7102-YVR
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Fri, 12 Jul 2024 16:16:47 GMT
NEL:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Referrer-Policy:
- same-origin
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=7j4Cxvi9e74lBtVN4gim19N8VkGbGuVGr%2Bt8ZjYzjuuPbK4UytYg1k7pvPbTwPJdLlw3cMBpvViG%2FelgVEYiMPD6D5aU%2BL54oMirDSKBCViSy2l2WO5t1gO96mckFxX3Dr68O2LOQh20Ihfd"}],"group":"cf-nel","max_age":604800}'
Server:
- cloudflare
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
- Origin
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://www.econdb.com/series/context/?tickers=%5BRGDPIN~TPOP%5D
response:
body:
string: !!binary |
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
yYdDcX2+/Q8GHBSHsCAAAA==
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 8a2256fb5ea98429-YVR
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Fri, 12 Jul 2024 16:16:47 GMT
NEL:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Referrer-Policy:
- same-origin
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=3NWiaaXaDCjPrdGmvzB0pnYC5CZtjwbydIuNzkA9Ih6JpaYC0%2FAzd%2FLOgXw60bcYzCgb%2FtBx%2FcOA2RsUG1JAx72LWZtHpeec60bUZmDKd317qvCvpc3pyuCy%2B9aZhgQt5td1cZ2aO0fEXyuA"}],"group":"cf-nel","max_age":604800}'
Server:
- cloudflare
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
- Origin
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://www.econdb.com/series/context/?tickers=%5BGDPIN~TUSD%5D
response:
body:
string: !!binary |
H4sIAAAAAAAAA61Z227jNhD9FUFA3yKGd0p+K7rtYh/21vW+NA0MrUUnBGTJ1SUXLNJv75CyE8cm
2y2owDEsipwzM2dmNKSuvqdVOZRl15WP6SK5cpcafqUUU55hAp/0Iknfvvn07sPfy69f3sC9glOu
YLAfymHs7eTfTFPWdl6na132elUNMNyMdQ1jpul1N+hq1TYvgmWGxZLiBcMLmiPC8j/Sp4vkFTzL
CPbC41wVkfA0o8WSqAXBC66QEtIHj5UPPheK8xh4sItkDC+JdPASFVJ54bkfPhckDh4XIPhgfRje
y30uZc4i4WVGqeWeigUTiFJyDk8D3OdMCBkJz16sFxRJzn3wAe4JFlHcg10gm+7hCUYMe60PcM9x
gePgj7nHBVJ54YUPcK9IVOJRl/cHeEIQIeIcngS5lyzS+ZZ7foDniOWeskMC3CtRFFFVj7zinhbA
PfbCe7lXoH8U98SWHayWhEHYLzCDyPdb7+UeAkXmcfA4z6hcuoq7YBwVygOPA9wrToqosuPcSlzR
ZfmCMSSIp+bjAPcSQi+q6GLLPQHriwWG0JOICA/3OMC9IDSu6Dq3Ur6kbMHZgggkpNf5Ae4JZlGh
h13ZkYfEE6gozq0nRYh7SmhUzceu7LCXvFe5Fz7AfUGj4Znj/lDzsfTD+/OeUBYDb91Kj6xniEnq
hfdyL3NCYiJ/cus+8umCc6j55+0GyQPcS6Wiys4pPEO8OH/kAHyAe8kKMSM8RXnBvPBe7sH5Yl54
6ku8PJj3EL0zwhMkqQdeBbknbE54jApx3usBfIB7rma1Hno94Qk9FeIe+uKYonsCz6DXY+e9noX3
5z2RbMbQA3jsy3sZ4B72WHNyz3JE/fB+7oWMa7RP4RUS3MO9DD3vOctjWs1TeNjjMb/1Xu4FV1Eb
7HN45tnfExHinio2p/UCIt8LH+CeSDovPOGeqieCvR4RczqfI0H91vu5Z1TGtJqn8AwVxAPPQ9wT
Jue0Hrodz/ECwAe4x0zFbDFP4SlSfuv93PMcavSs8Ljww3u554WM2t+fwhPEPZssEjrX4ypuj3cK
j5FSnqoXOtfjDP5mhSfK02iHzvW4yIsZG21aIKG8zg/kPWZiRutpDvt7T9ULnetBrzVn5AM8E55u
J3Sux2kuZtxmUHuk7Am90Lkep4rPab2CR44f3p/3OSMzPvGoRNy3ww2d63FOog7WTuEFyn19fuhc
jwP5M/Z6AE8D8IG8V3TOxONIuqOlazu5snOO4GDsTnffWhA6mKF2ur1rKlMmWfK2a/s+qdqt7gez
TnZdW43rwS7Z6qFcVbpfd2Y3mAn4v1fd6PamK3e39r3S9/S27Fdwc2Mc6NCNGqY05fZFBbvG9K27
/mDdlw6VW7rp9F+jbtZWUPp5LMH8rn600/t1Odmw1E2ftJtka+oaFOztzbExQz9J+91e12U/jLvX
r7dExhwje+NWddvc7F1mh8uqMs2mXVVmPThVrKLrcmi7o0lfDzgEJ+8n/AQgL5JySNZj1+lmALeY
tXZa/QJq9GZjpew9CWKSb4+JfthpkD6MnXbGW3VXd2U9aof8A6/lUpXkNE+IwOlxPNnAsQK7srmx
Iq5cNH526600+GVjxRK0aTu9Bly7bFPWveNIPwyrfSS+KODeImC8cB+nr32N2OvJTX07dutJ712n
N+bBLnz/8Ut6xPl705h+6B4tbV9AV2Pjp0/Kpko+dTZytsm77a7WW/Cf89VF8hwmfT06mrZ7GVm7
yfpnGRnIyHaTjMy8kpEZJ+LpSEbjbpR1Vq7X7dgM/X4OTFm3ld5rvtqTfZIFH/aLk5/3i4+UBHm6
71djV9uZt8OwW1xe3t/fo23b7wy6ae+QaS6t26bIX/XV9uHI8S4AdmYKyMnrkOckoQQeb3bJYLZ6
1ZvGeTol+Z8jxiW+Bd+DGlxOl+CicZhC798S4Nbc3NbwP/G3LU2THWIvLVDhqoAdtEllx35KHi8f
n0d3ujNtdZAKAfVkPbyrWzCgBBZ6J/V/VJznAIoLk2B5sOqVw9CZb845kBRXqfMpcaa+pPmUYzZB
rlJlr7h8yfmLH8l5t5S4lCTEUwEuvBXArXr760d7u7CaTeXffl9fT+GyT7jVndH3+5L6dP0P4cpC
0tAfAAA=
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 8a2256fb59708441-YVR
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Fri, 12 Jul 2024 16:16:47 GMT
NEL:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Referrer-Policy:
- same-origin
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=qRKNCe0DFXM6O7cCwJnQDnszbLxt3e9bFkijhN27zQEpiKHkZbwlyTxWtiFgoJIYKxc7wNenDn9g9S9WnPeNp1S6TBpHnh7p6wSf5lzcQKqC79XZn0ZPD9ynBakyuot27Aq5BZqD2a833Mz6"}],"group":"cf-nel","max_age":604800}'
Server:
- cloudflare
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
- Origin
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
status:
code: 200
message: OK
version: 1

View File

@@ -7,6 +7,7 @@ from openbb_core.app.service.user_service import UserService
from openbb_econdb.models.available_indicators import EconDbAvailableIndicatorsFetcher
from openbb_econdb.models.country_profile import EconDbCountryProfileFetcher
from openbb_econdb.models.economic_indicators import EconDbEconomicIndicatorsFetcher
from openbb_econdb.models.gdp_nominal import EconDbGdpNominalFetcher
from openbb_econdb.models.yield_curve import EconDbYieldCurveFetcher
test_credentials = UserService().default_user_settings.credentials.model_dump(
@@ -91,3 +92,16 @@ def test_econdb_economic_indicators_main_fetcher(credentials=test_credentials):
fetcher = EconDbEconomicIndicatorsFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_econdb_gdp_nominal_fetcher(credentials=test_credentials):
"""Test EconDB GDP Nominal Fetcher."""
params = {
"country": "IN",
"use_cache": False,
}
fetcher = EconDbGdpNominalFetcher()
result = fetcher.test(params, credentials)
assert result is None

View File

@@ -1,101 +1,200 @@
"""OECD Nominal GDP Model."""
from datetime import date
from typing import Any, Dict, List, Literal, Optional, Union
# pylint: disable=unused-argument
from datetime import date
from typing import Any, Dict, List, Literal, Optional
from warnings import warn
from openbb_core.app.model.abstract.error import OpenBBError
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.standard_models.gdp_nominal import (
GdpNominalData,
GdpNominalQueryParams,
)
from openbb_oecd.utils import constants
from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS
from openbb_core.provider.utils.errors import EmptyDataError
from openbb_oecd.utils.constants import CODE_TO_COUNTRY_GDP, COUNTRY_TO_CODE_GDP
from pydantic import Field, field_validator
gdp_countries = tuple(constants.COUNTRY_TO_CODE_GDP.keys()) + ("all",)
GDPCountriesLiteral = Literal[gdp_countries] # type: ignore
# pylint: disable=unused-argument
COUNTRIES = list(COUNTRY_TO_CODE_GDP) + ["all"]
class OECDGdpNominalQueryParams(GdpNominalQueryParams):
"""OECD Nominal GDP Query."""
"""OECD Nominal GDP Query.
country: GDPCountriesLiteral = Field(
description="Country to get GDP for.", default="united_states"
Source: https://www.oecd.org/en/data/datasets/gdp-and-non-financial-accounts.html
This table presents Gross Domestic Product (GDP) and its main components according to the expenditure approach.
Data is presented in US dollars. In the expenditure approach, the components of GDP are:
final consumption expenditure of households and non-profit institutions serving households (NPISH)
plus final consumption expenditure of General Government plus gross fixed capital formation (or investment)
plus net trade (exports minus imports).
"""
__json_schema_extra__ = {"country": ["multiple_items_allowed"]}
country: str = Field(
description=QUERY_DESCRIPTIONS.get("country", "")
+ " Use 'all' to get data for all available countries.",
default="united_states",
json_schema_extra={"choices": COUNTRIES}, # type: ignore
)
frequency: Literal["quarter", "annual"] = Field(
description="Frequency of the data.",
default="quarter",
json_schema_extra={"choices": ["quarter", "annual"]},
)
units: Literal["level", "index", "capita"] = Field(
default="level",
description=QUERY_DESCRIPTIONS.get("units", "")
+ "Both 'level' and 'capita' (per) are measured in USD.",
json_schema_extra={"choices": ["level", "index", "capita"]},
)
price_base: Literal["current_prices", "volume"] = Field(
default="current_prices",
description="Price base for the data, volume is chain linked volume.",
json_schema_extra={"choices": ["current_prices", "volume"]},
)
@field_validator("country", mode="before", check_fields=False)
@classmethod
def validate_country(cls, c):
"""Validate country."""
# pylint: disable=import-outside-toplevel
from openbb_core.provider.utils.helpers import check_item
result: List = []
values = c.replace(" ", "_").split(",")
for v in values:
if v.upper() in CODE_TO_COUNTRY_GDP:
result.append(CODE_TO_COUNTRY_GDP.get(v.upper()))
continue
try:
check_item(v.lower(), COUNTRIES)
except Exception as e:
if len(values) == 1:
raise e from e
warn(f"Invalid country: {v}. Skipping...")
continue
result.append(v.lower())
if result:
return ",".join(result)
raise OpenBBError(f"No valid country found. -> {values}")
class OECDGdpNominalData(GdpNominalData):
"""OECD Nominal GDP Data."""
@field_validator("date", mode="before")
@classmethod
def date_validate(cls, in_date: Union[date, int]): # pylint: disable=E0213
"""Validate value."""
if isinstance(in_date, int):
return date(in_date, 12, 31)
return date
class OECDGdpNominalFetcher(
Fetcher[OECDGdpNominalQueryParams, List[OECDGdpNominalData]]
):
"""Transform the query, extract and transform the data from the OECD endpoints."""
"""OECD GDP Nominal Fetcher."""
@staticmethod
def transform_query(params: Dict[str, Any]) -> OECDGdpNominalQueryParams:
"""Transform the query."""
transformed_params = params.copy()
if transformed_params["start_date"] is None:
transformed_params["start_date"] = date(1950, 1, 1)
if transformed_params["end_date"] is None:
if transformed_params.get("start_date") is None:
transformed_params["start_date"] = (
date(2020, 1, 1)
if transformed_params.get("country") == "all"
else date(1947, 1, 1)
)
if transformed_params.get("end_date") is None:
transformed_params["end_date"] = date(date.today().year, 12, 31)
if transformed_params.get("country") is None:
transformed_params["country"] = "united_states"
return OECDGdpNominalQueryParams(**transformed_params)
@staticmethod
def extract_data(
async def aextract_data(
query: OECDGdpNominalQueryParams,
credentials: Optional[Dict[str, str]],
**kwargs: Any,
) -> List[Dict]:
"""Return the raw data from the OECD endpoint."""
# pylint: disable=import-outside-toplevel
from openbb_oecd.utils import helpers
from io import StringIO # noqa
from openbb_oecd.utils.helpers import oecd_date_to_python_date
from numpy import nan
from pandas import read_csv
from openbb_core.provider.utils.helpers import amake_request
if query.units == "index":
unit = "INDICES"
elif query.units == "capita":
unit = "CAPITA"
else:
unit = "USD"
frequency = "Q" if query.frequency == "quarter" else "A"
price_base = "V" if query.price_base == "current_prices" else "LR"
if unit == "INDICES" and price_base == "V":
price_base = "DR"
def country_string(input_str: str):
"""Convert the list of countries to an abbreviated string."""
if input_str == "all":
return ""
_countries = input_str.split(",")
return "+".join([COUNTRY_TO_CODE_GDP[country] for country in _countries])
country = country_string(query.country) if query.country else ""
unit = "MLN_USD" if query.units == "usd" else "USD_CAP"
url = (
f"https://stats.oecd.org/sdmx-json/data/DP_LIVE/.GDP.TOT.{unit}.A/OECD"
"?contentType=csv&detail=code&separator=comma&csv-lang=en"
f"&startPeriod={query.start_date}&endPeriod={query.end_date}"
f"https://sdmx.oecd.org/public/rest/data/OECD.SDD.NAD,DSD_NAMAIN1@DF_QNA_EXPENDITURE_{unit},1.1"
+ f"/{frequency}..{country}.S1..B1GQ.....{price_base}..?"
+ f"&startPeriod={query.start_date}&endPeriod={query.end_date}"
+ "&dimensionAtObservation=TIME_PERIOD&detail=dataonly&format=csvfile"
)
data_df = helpers.fetch_data(url, csv_kwargs={"encoding": "utf-8"}, **kwargs)
# Sometimes there is weird unicode characters in the column names, so we need to rename them.
# Even changing the encoding on the fetch doesn't seem to help.
data_df = data_df.rename(
columns={
"LOCATION": "country",
"TIME_PERIOD": "date",
"OBS_VALUE": "value",
"Location": "country",
}
if query.units == "capita":
url = url.replace("B1GQ", "B1GQ_POP")
async def response_callback(response, _):
"""Response callback."""
if response.status != 200:
raise OpenBBError(f"Error with the OECD request: {response.status}")
return await response.text()
response = await amake_request(
url, timeout=30, response_callback=response_callback
)
data_df["country"] = data_df["country"].map(constants.CODE_TO_COUNTRY_GDP)
if query.country != "all":
data_df = data_df[data_df["country"] == query.country]
data_df = data_df[["country", "date", "value"]]
data_df["date"] = data_df["date"].apply(helpers.oecd_date_to_python_date)
data_df = data_df[
(data_df["date"] <= query.end_date) & (data_df["date"] >= query.start_date)
]
data_df["date"] = data_df["date"].apply(
lambda x: x.year
) # Validator won't accept datetime.date?
return data_df.to_dict(orient="records")
df = read_csv(StringIO(response)).get( # type: ignore
["REF_AREA", "TIME_PERIOD", "OBS_VALUE"]
)
if df.empty: # type: ignore
raise EmptyDataError()
df = df.rename( # type: ignore
columns={"REF_AREA": "country", "TIME_PERIOD": "date", "OBS_VALUE": "value"}
)
def apply_map(x):
"""Apply the country map."""
v = CODE_TO_COUNTRY_GDP.get(x, x)
v = v.replace("_", " ").title()
return v
df["country"] = df["country"].apply(apply_map).str.replace("Oecd", "OECD")
df["date"] = df["date"].apply(oecd_date_to_python_date)
df = df[(df["date"] <= query.end_date) & (df["date"] >= query.start_date)]
if query.units == "level":
df["value"] = (df["value"].astype(float) * 1_000_000).astype("int64")
df = df.sort_values(by=["date", "value"], ascending=False)
return df.replace({nan: None}).to_dict(orient="records")
@staticmethod
def transform_data(
query: OECDGdpNominalQueryParams, data: List[Dict], **kwargs: Any
query: OECDGdpNominalQueryParams,
data: List[Dict],
**kwargs: Any,
) -> List[OECDGdpNominalData]:
"""Transform the data from the OECD endpoint."""
return [OECDGdpNominalData.model_validate(d) for d in data]

View File

@@ -1,25 +1,36 @@
"""Constants for the OECD provider."""
COUNTRY_TO_CODE_GDP = {
"oecd": "OECD",
"oecd_26": "OECD26",
"oecd_europe": "OECDE",
"g7": "G7",
"g20": "G20",
"euro_area": "EA20",
"european_union_27": "EU27_2020",
"european_union_15": "EU15",
"nafta": "USMCA",
"argentina": "ARG",
"australia": "AUS",
"austria": "AUT",
"belgium": "BEL",
"bulgaria": "BGR",
"brazil": "BRA",
"canada": "CAN",
"chile": "CHL",
"colombia": "COL",
"costa_rica": "CRI",
"croatia": "HRV",
"czech_republic": "CZE",
"denmark": "DNK",
"estonia": "EST",
"euro_area": "EA",
"european_union": "EU",
"finland": "FIN",
"france": "FRA",
"germany": "DEU",
"greece": "GRC",
"hungary": "HUN",
"iceland": "ISL",
"india": "IND",
"indonesia": "IDN",
"ireland": "IRL",
"israel": "ISR",
@@ -35,7 +46,9 @@ COUNTRY_TO_CODE_GDP = {
"norway": "NOR",
"poland": "POL",
"portugal": "PRT",
"romania": "ROU",
"russia": "RUS",
"saudi_arabia": "SAU",
"slovak_republic": "SVK",
"slovenia": "SVN",
"south_africa": "ZAF",

View File

@@ -3,89 +3,55 @@ interactions:
body: null
headers:
Accept:
- '*/*'
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://stats.oecd.org/sdmx-json/data/DP_LIVE/.GDP.TOT.MLN_USD.A/OECD?contentType=csv&csv-lang=en&detail=code&endPeriod=2023-06-06&separator=comma&startPeriod=2020-01-01
uri: https://sdmx.oecd.org/public/rest/data/OECD.SDD.NAD,DSD_NAMAIN1@DF_QNA_EXPENDITURE_USD,1.1/Q..USA.S1..B1GQ.....V..?detail=dataonly&dimensionAtObservation=TIME_PERIOD&endPeriod=2023-06-06&format=csvfile&startPeriod=2020-01-01
response:
body:
string: !!binary |
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
lBzB/wMA2DKSMiUAAA==
VmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ip4evzl+
9vzL746evTr9idHx0+989frNF6cv3oxenT77/Y9fnR6PXp+evPny1ejky69evDl99fL41ZvfXz96
8+r4xevjkzdnX74Ynb14/ebV73/8+vXpmxE++smzN7/P6PT3fnn64unZm69enY6+enH25vf/4vT4
Nf54+ers5PT3f3L8+lSAPPvy1RfHDOfN8ZPnp7//2VNC4ezZ2Sl1cvbF6e//8vTV2ZdPR18+ef37
/+Tx869OGbvf5/T41e/PkEaAhEaE5Ytnv//rN8dvvno9enp6cvbF8fPX/Jp+Jlh89fzN6OSrV69O
X5z8Pr9x8uXpydPx66dPxy+Onz56+vrp7//i+Ivjsxe7v+fTZ7//T7w4/v29Ufz+X71+urU73r0z
+onR7zP66jVRZxf/e7L7+U+Mfv+f0v9Ro9//5cuXo58cPT8evdnZ3dkb7e3s7W3/xP5o79P9nYP9
nfsjeX5one9s/8S90d7up/sPCAHqGM8PrfPd7Z/YHe3tfbqzs3vwQx85dU4/7+093Lv36R51jOeH
2TmR/d7B3sHDB/eoYzw/zM6J4fY/vb//6c5g5z9bnRO305zf39l7uLv7KY0azw9t5NQ5/bx/f39/
74dP9ns88k8Pdu99urNLHeP5oXVOIyeGu//w4f6n9x5Sx3h+aJ2TkqGR7z7Y+fT+7g+d7NT53mj3
4cPde7v7Pxedk6jRL/vE8dQxnt84+X8AYyF/4lwHAAA=
headers:
Access-Control-Allow-Headers:
- Content-Type
Access-Control-Allow-Methods:
- POST,GET,OPTIONS
Access-Control-Allow-Origin:
- '*'
Accept-Ranges:
- values
Cache-Control:
- private
- no-store,no-cache
Content-Disposition:
- attachment;filename=DP_LIVE_01072024211330756.csv
- attachment; filename="OECD.SDD.NAD,DSD_NAMAIN1@DF_QNA_EXPENDITURE_USD,1.1+Q..USA.S1..B1GQ.....V...csv"
Content-Encoding:
- gzip
Content-Language:
- en,en-US
Content-Type:
- text/csv
- application/vnd.sdmx.data+csv; charset=utf-8
Date:
- Mon, 01 Jul 2024 19:13:30 GMT
- Fri, 12 Jul 2024 19:06:48 GMT
Pragma:
- no-cache
Strict-Transport-Security:
- max-age=2592000
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
- Accept,Accept-Encoding,Accept-Encoding
X-Server-Node:
- Server 3
api-supported-versions:
- '1'
status:
code: 200
message: OK

View File

@@ -45,11 +45,11 @@ def test_oecd_cpi_fetcher(credentials=test_credentials):
assert result is None
@pytest.mark.skip(reason="Downloads a huge file, code needs to be fixed to use params.")
@pytest.mark.record_http
def test_oecd_nominal_gdp_fetcher(credentials=test_credentials):
"""Test the OECD Nominal GDP fetcher."""
params = {
"country": "united_states",
"start_date": datetime.date(2020, 1, 1),
"end_date": datetime.date(2023, 6, 6),
}