diff --git a/openbb_platform/core/openbb_core/provider/standard_models/non_farm_payrolls.py b/openbb_platform/core/openbb_core/provider/standard_models/non_farm_payrolls.py new file mode 100644 index 000000000000..912c777b157b --- /dev/null +++ b/openbb_platform/core/openbb_core/provider/standard_models/non_farm_payrolls.py @@ -0,0 +1,31 @@ +"""NonFarm Payrolls Standard Model.""" + +from datetime import date as dateType +from typing import Optional, Union + +from pydantic import Field + +from openbb_core.provider.abstract.data import Data +from openbb_core.provider.abstract.query_params import QueryParams +from openbb_core.provider.utils.descriptions import ( + DATA_DESCRIPTIONS, + QUERY_DESCRIPTIONS, +) + + +class NonFarmPayrollsQueryParams(QueryParams): + """NonFarm Payrolls Query.""" + + date: Optional[Union[dateType, str]] = Field( + default=None, + description=QUERY_DESCRIPTIONS.get("date", "") + + " Default is the latest report.", + ) + + +class NonFarmPayrollsData(Data): + """NonFarm Payrolls Data.""" + + date: dateType = Field(description=DATA_DESCRIPTIONS.get("date", "")) + symbol: str = Field(description=DATA_DESCRIPTIONS.get("symbol", "")) + value: float = Field(description=DATA_DESCRIPTIONS.get("value", "")) diff --git a/openbb_platform/extensions/economy/integration/test_economy_api.py b/openbb_platform/extensions/economy/integration/test_economy_api.py index 97ddbb456578..e0ac235994f2 100644 --- a/openbb_platform/extensions/economy/integration/test_economy_api.py +++ b/openbb_platform/extensions/economy/integration/test_economy_api.py @@ -949,3 +949,27 @@ def test_economy_primary_dealer_positioning(params, headers): result = requests.get(url, headers=headers, timeout=10) assert isinstance(result, requests.Response) assert result.status_code == 200 + + +@parametrize( + "params", + [ + ( + { + "provider": "fred", + "date": "2024-06-01,2023-06-01", + "category": "avg_earnings_hourly", + } + ), + ], +) +@pytest.mark.integration +def test_economy_survey_nonfarm_payrolls(params, headers): + """Test the economy survey nonfarm payrolls endpoint""" + params = {p: v for p, v in params.items() if v} + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/economy/survey/nonfarm_payrolls?{query_str}" + result = requests.get(url, headers=headers, timeout=10) + assert isinstance(result, requests.Response) + assert result.status_code == 200 diff --git a/openbb_platform/extensions/economy/integration/test_economy_python.py b/openbb_platform/extensions/economy/integration/test_economy_python.py index 4c0db0bb8a56..33665c2d1ba2 100644 --- a/openbb_platform/extensions/economy/integration/test_economy_python.py +++ b/openbb_platform/extensions/economy/integration/test_economy_python.py @@ -898,3 +898,26 @@ def test_economy_primary_dealer_positioning(params, obb): assert result assert isinstance(result, OBBject) assert len(result.results) > 0 + + +@parametrize( + "params", + [ + ( + { + "provider": "fred", + "date": "2024-06-01,2023-06-01", + "category": "avg_earnings_hourly", + } + ), + ], +) +@pytest.mark.integration +def test_economy_survey_nonfarm_payrolls(params, obb): + """Test the economy survery nonfarm payrolls endpoint""" + params = {p: v for p, v in params.items() if v} + + result = obb.economy.survey.nonfarm_payrolls(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 diff --git a/openbb_platform/extensions/economy/openbb_economy/survey/survey_router.py b/openbb_platform/extensions/economy/openbb_economy/survey/survey_router.py index 313999a463ff..6d901f82f2f8 100644 --- a/openbb_platform/extensions/economy/openbb_economy/survey/survey_router.py +++ b/openbb_platform/extensions/economy/openbb_economy/survey/survey_router.py @@ -86,3 +86,25 @@ async def manufacturing_outlook_texas( ) -> OBBject: """Get The Manufacturing Outlook Survey For The Texas Region.""" return await OBBject.from_query(Query(**locals())) + + +@router.command( + model="NonFarmPayrolls", + examples=[ + APIEx(parameters={"provider": "fred"}), + APIEx( + parameters={ + "category": "avg_hours", + "provider": "fred", + } + ), + ], +) +async def nonfarm_payrolls( + cc: CommandContext, + provider_choices: ProviderChoices, + standard_params: StandardParams, + extra_params: ExtraParams, +) -> OBBject: + """Get Nonfarm Payrolls Survey.""" + return await OBBject.from_query(Query(**locals())) diff --git a/openbb_platform/openbb/assets/reference.json b/openbb_platform/openbb/assets/reference.json index b867ecedaa41..f9ff83f1b57b 100644 --- a/openbb_platform/openbb/assets/reference.json +++ b/openbb_platform/openbb/assets/reference.json @@ -3490,6 +3490,161 @@ }, "model": "ManufacturingOutlookTexas" }, + "/economy/survey/nonfarm_payrolls": { + "deprecated": { + "flag": null, + "message": null + }, + "description": "Get Nonfarm Payrolls Survey.", + "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.survey.nonfarm_payrolls(provider='fred')\nobb.economy.survey.nonfarm_payrolls(category=avg_hours, provider='fred')\n```\n\n", + "parameters": { + "standard": [ + { + "name": "date", + "type": "Union[Union[Union[str, date], str], List[Union[Union[str, date], str]]]", + "description": "A specific date to get data for. Default is the latest report. Multiple items allowed for provider(s): fred.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "provider", + "type": "Literal['fred']", + "description": "The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fred.", + "default": null, + "optional": true + } + ], + "fred": [ + { + "name": "category", + "type": "Literal['employees_nsa', 'employees_sa', 'employees_production_and_nonsupervisory', 'employees_women', 'employees_women_percent', 'avg_hours', 'avg_hours_production_and_nonsupervisory', 'avg_hours_overtime', 'avg_hours_overtime_production_and_nonsupervisory', 'avg_earnings_hourly', 'avg_earnings_hourly_production_and_nonsupervisory', 'avg_earnings_weekly', 'avg_earnings_weekly_production_and_nonsupervisory', 'index_weekly_hours', 'index_weekly_hours_production_and_nonsupervisory', 'index_weekly_payrolls', 'index_weekly_payrolls_production_and_nonsupervisory']", + "description": "The category to query.", + "default": "employees_nsa", + "optional": true, + "choices": [ + "employees_nsa", + "employees_sa", + "employees_production_and_nonsupervisory", + "employees_women", + "employees_women_percent", + "avg_hours", + "avg_hours_production_and_nonsupervisory", + "avg_hours_overtime", + "avg_hours_overtime_production_and_nonsupervisory", + "avg_earnings_hourly", + "avg_earnings_hourly_production_and_nonsupervisory", + "avg_earnings_weekly", + "avg_earnings_weekly_production_and_nonsupervisory", + "index_weekly_hours", + "index_weekly_hours_production_and_nonsupervisory", + "index_weekly_payrolls", + "index_weekly_payrolls_production_and_nonsupervisory" + ] + } + ] + }, + "returns": { + "OBBject": [ + { + "name": "results", + "type": "List[NonFarmPayrolls]", + "description": "Serializable results." + }, + { + "name": "provider", + "type": "Optional[Literal['fred']]", + "description": "Provider name." + }, + { + "name": "warnings", + "type": "Optional[List[Warning_]]", + "description": "List of warnings." + }, + { + "name": "chart", + "type": "Optional[Chart]", + "description": "Chart object." + }, + { + "name": "extra", + "type": "Dict[str, Any]", + "description": "Extra info." + } + ] + }, + "data": { + "standard": [ + { + "name": "date", + "type": "date", + "description": "The date of the data.", + "default": "", + "optional": false, + "choices": null + }, + { + "name": "symbol", + "type": "str", + "description": "Symbol representing the entity requested in the data.", + "default": "", + "optional": false, + "choices": null + }, + { + "name": "value", + "type": "float", + "description": "", + "default": "", + "optional": false, + "choices": null + } + ], + "fred": [ + { + "name": "name", + "type": "str", + "description": "The name of the series.", + "default": "", + "optional": false, + "choices": null + }, + { + "name": "element_id", + "type": "str", + "description": "The element id in the parent/child relationship.", + "default": "", + "optional": false, + "choices": null + }, + { + "name": "parent_id", + "type": "str", + "description": "The parent id in the parent/child relationship.", + "default": "", + "optional": false, + "choices": null + }, + { + "name": "children", + "type": "str", + "description": "The element_id of each child, as a comma-separated string.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "level", + "type": "int", + "description": "The indentation level of the element.", + "default": "", + "optional": false, + "choices": null + } + ] + }, + "model": "NonFarmPayrolls" + }, "/economy/calendar": { "deprecated": { "flag": null, diff --git a/openbb_platform/providers/fred/openbb_fred/__init__.py b/openbb_platform/providers/fred/openbb_fred/__init__.py index 24be680a52a1..0ec012b1bb67 100644 --- a/openbb_platform/providers/fred/openbb_fred/__init__.py +++ b/openbb_platform/providers/fred/openbb_fred/__init__.py @@ -24,6 +24,7 @@ ) from openbb_fred.models.moody import FREDMoodyCorporateBondIndexFetcher from openbb_fred.models.mortgage_indices import FredMortgageIndicesFetcher +from openbb_fred.models.non_farm_payrolls import FredNonFarmPayrollsFetcher from openbb_fred.models.overnight_bank_funding_rate import ( FredOvernightBankFundingRateFetcher, ) @@ -75,6 +76,7 @@ "ManufacturingOutlookTexas": FredManufacturingOutlookTexasFetcher, "MoodyCorporateBondIndex": FREDMoodyCorporateBondIndexFetcher, "MortgageIndices": FredMortgageIndicesFetcher, + "NonFarmPayrolls": FredNonFarmPayrollsFetcher, "OvernightBankFundingRate": FredOvernightBankFundingRateFetcher, "CommercialPaper": FREDCommercialPaperFetcher, "FredSearch": FredSearchFetcher, diff --git a/openbb_platform/providers/fred/openbb_fred/models/non_farm_payrolls.py b/openbb_platform/providers/fred/openbb_fred/models/non_farm_payrolls.py new file mode 100644 index 000000000000..c54727387c61 --- /dev/null +++ b/openbb_platform/providers/fred/openbb_fred/models/non_farm_payrolls.py @@ -0,0 +1,386 @@ +"""FRED Nonfarm Payrolls Model.""" + +# pylint: disable=unused-argument + +from datetime import date as dateType +from typing import Any, Dict, List, Literal, Optional + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.non_farm_payrolls import ( + NonFarmPayrollsData, + NonFarmPayrollsQueryParams, +) +from openbb_core.provider.utils.errors import EmptyDataError +from pydantic import Field, field_validator + +EstablishmentData = { + "employees_nsa": "5645", + "employees_sa": "4881", + "employees_production_and_nonsupervisory": "6411", + "employees_women": "6304", + "employees_women_percent": "6433", + "avg_hours": "6462", + "avg_hours_production_and_nonsupervisory": "5923", + "avg_hours_overtime": "6466", + "avg_hours_overtime_production_and_nonsupervisory": "6442", + "avg_earnings_hourly": "6471", + "avg_earnings_hourly_production_and_nonsupervisory": "5943", + "avg_earnings_weekly": "6490", + "avg_earnings_weekly_production_and_nonsupervisory": "6020", + "index_weekly_hours": "6637", + "index_weekly_hours_production_and_nonsupervisory": "6095", + "index_weekly_payrolls": "6654", + "index_weekly_payrolls_production_and_nonsupervisory": "6280", +} + +NFP_SECTOR_ORDER = [ + "Total nonfarm", + "Total private", + "Goods-producing", + "Mining and logging", + "Logging", + "Mining", + "Oil and gas extraction", + "Mining, except oil and gas", + "Coal mining", + "Support activities for mining", + "Construction", + "Construction of buildings", + "Residential building", + "Nonresidential building", + "Heavy and civil engineering construction", + "Specialty trade contractors", + "Residential specialty trade contractors", + "Nonresidential specialty trade contractors", + "Manufacturing", + "Durable goods", + "Wood products", + "Nonmetallic mineral products", + "Primary metals", + "Fabricated metal products", + "Machinery", + "Computer and electronic products", + "Computer and peripheral equipment", + "Communication equipment", + "Semiconductors and electronic components", + "Electronic instruments", + "Electrical equipment and appliances", + "Transportation equipment", + "Motor vehicles and parts", + "Furniture and related products", + "Miscellaneous durable goods manufacturing", + "Nondurable goods", + "Food manufacturing", + "Textile mills", + "Textile product mills", + "Apparel", + "Paper and paper products", + "Printing and related support activities", + "Petroleum and coal products", + "Chemicals", + "Plastics and rubber products", + "Miscellaneous nondurable goods manufacturing", + "Private service-providing", + "Trade, transportation, and utilities", + "Wholesale trade", + "Durable goods", + "Nondurable goods", + "Electronic markets and agents and brokers", + "Retail trade", + "Motor vehicles and parts dealers", + "Automobile dealers", + "Furniture and home furnishings stores", + "Electronics and appliance stores", + "Building material and garden supply stores", + "Food and beverage stores", + "Health and personal care stores", + "Gasoline stations", + "Clothing and clothing accessories stores", + "Sporting goods, hobby, book, and music stores", + "General merchandise stores", + "Transportation and warehousing", + "Air transportation", + "Rail transportation", + "Water transportation", + "Truck transportation", + "Transit and ground passenger transportation", + "Pipeline transportation", + "Scenic and sightseeing transportation", + "Support activities for transportation", + "Couriers and messengers", + "Warehousing and storage", + "Utilities", + "Information", + "Publishing industries, except Internet", + "Motion picture and sound recording industries", + "Broadcasting, except Internet", + "Telecommunications", + "Data processing, hosting and related services", + "Other information services", + "Financial activities", + "Finance and insurance", + "Monetary authorities - central bank", + "Credit intermediation and related activities", + "Depository credit intermediation", + "Commercial banking", + "Securities, commodity contracts, investments, and funds and trusts", + "Insurance carriers and related activities", + "Real estate and rental and leasing", + "Real estate", + "Rental and leasing services", + "Lessors of nonfinancial intangible assets", + "Professional and business services", + "Professional and technical services", + "Legal services", + "Accounting and bookkeeping services", + "Architectural and engineering services", + "Computer systems design and related services", + "Management and technical consulting services", + "Management of companies and enterprises", + "Administrative and waste services", + "Administrative and support services", + "Employment services", + "Temporary help services", + "Business support services", + "Services to buildings and dwellings", + "Waste management and remediation services", + "Education and health services", + "Educational services", + "Health care and social assistance", + "Health care", + "Ambulatory health care services", + "Offices of physicians", + "Outpatient care centers", + "Home health care services", + "Hospitals", + "Nursing and residential care facilities", + "Nursing care facilities", + "Social assistance", + "Child day care services", + "Leisure and hospitality", + "Arts, entertainment, and recreation", + "Performing arts and spectator sports", + "Museums, historical sites, and similar institutions", + "Amusements, gambling, and recreation", + "Accommodation and food services", + "Accommodation", + "Food services and drinking places", + "Other services", + "Repair and maintenance", + "Personal and laundry services", + "Membership associations and organizations", + "Government", + "Federal", + "Federal, except U.S. Postal Service", + "U.S. Postal Service", + "State government", + "State government education", + "State government, excluding education", + "Local government", + "Local government education", + "Local government, excluding education", +] + + +class FredNonFarmPayrollsQueryParams(NonFarmPayrollsQueryParams): + """FRED NonFarm Payrolls Query.""" + + __json_schema_extra__ = {"date": {"multiple_items_allowed": True}} + + category: Literal[ + "employees_nsa", + "employees_sa", + "employees_production_and_nonsupervisory", + "employees_women", + "employees_women_percent", + "avg_hours", + "avg_hours_production_and_nonsupervisory", + "avg_hours_overtime", + "avg_hours_overtime_production_and_nonsupervisory", + "avg_earnings_hourly", + "avg_earnings_hourly_production_and_nonsupervisory", + "avg_earnings_weekly", + "avg_earnings_weekly_production_and_nonsupervisory", + "index_weekly_hours", + "index_weekly_hours_production_and_nonsupervisory", + "index_weekly_payrolls", + "index_weekly_payrolls_production_and_nonsupervisory", + ] = Field( + default="employees_nsa", + description="The category to query.", + json_schema_extra={"choices": list(EstablishmentData)}, + ) + + @field_validator("date", mode="before", check_fields=False) + @classmethod + def validate_date(cls, v): + """Validate the dates entered.""" + if v is None: + return None + if isinstance(v, (list, dateType)): + return v + new_dates: List = [] + date_param = v + if isinstance(date_param, str): + new_dates = date_param.split(",") + elif isinstance(date_param, dateType): + new_dates.append(date_param.strftime("%Y-%m-%d")) + elif isinstance(date_param, list) and isinstance(date_param[0], dateType): + new_dates = [d.strftime("%Y-%m-%d") for d in new_dates] + else: + new_dates = date_param + return ",".join(new_dates) if len(new_dates) > 1 else new_dates[0] + + +class FredNonFarmPayrollsData(NonFarmPayrollsData): + """FRED NonFarm Payrolls Data.""" + + __alias_dict__ = { + "date": "observation_date", + "value": "observation_value", + "symbol": "series_id", + } + + name: str = Field( + description="The name of the series.", + ) + element_id: str = Field( + description="The element id in the parent/child relationship.", + ) + parent_id: str = Field( + description="The parent id in the parent/child relationship.", + ) + children: Optional[str] = Field( + default=None, + description="The element_id of each child, as a comma-separated string.", + ) + level: int = Field( + description="The indentation level of the element.", + ) + + +class FredNonFarmPayrollsFetcher( + Fetcher[FredNonFarmPayrollsQueryParams, List[FredNonFarmPayrollsData]] +): + """FRED NonFarm Payrolls Fetcher.""" + + @staticmethod + def transform_query(params: Dict[str, Any]) -> FredNonFarmPayrollsQueryParams: + """Transform query.""" + return FredNonFarmPayrollsQueryParams(**params) + + @staticmethod + async def aextract_data( + query: FredNonFarmPayrollsQueryParams, + credentials: Optional[Dict[str, str]], + **kwargs: Any, + ) -> List[Dict]: + """Extract data.""" + # pylint: disable=import-outside-toplevel + import asyncio # noqa + from openbb_core.provider.utils.helpers import amake_request + from numpy import nan + from pandas import DataFrame, to_datetime + + api_key = credentials.get("fred_api_key") if credentials else "" + element_id = EstablishmentData[query.category] + dates: List = [""] + + if query.date: + if query.date and isinstance(query.date, dateType): + query.date = query.date.strftime("%Y-%m-%d") + dates = query.date.split(",") # type: ignore + dates = [d.replace(d[-2:], "01") if len(d) == 10 else d for d in dates] + dates = list(set(dates)) + dates = ( + [f"&observation_date={date}" for date in dates if date] if dates else "" # type: ignore + ) + + URLS = [ + f"https://api.stlouisfed.org/fred/release/tables?release_id=50&element_id={element_id}" + + f"{date}&include_observation_values=true&api_key={api_key}" + + "&file_type=json" + for date in dates + ] + results: List = [] + + async def get_one(URL): + """Get the observations for a single date.""" + response = await amake_request(URL) + data = [ + v + for v in response.get("elements", {}).values() # type: ignore + if v.get("observation_value") != "." + ] + if data: + df = ( + DataFrame(data) + .set_index(["element_id", "parent_id"]) + .sort_index()[ + [ + "level", + "series_id", + "name", + "observation_date", + "observation_value", + ] + ] + .reset_index() + ) + df["parent_id"] = df.parent_id.astype(str) + df["element_id"] = df.element_id.astype(str) + df["observation_value"] = df.observation_value.str.replace( + ",", "" + ).astype(float) + if query.category.startswith( + "employees" + ) and not query.category.endswith("percent"): + df["observation_value"] = df.observation_value * 1000 + elif query.category.endswith("percent"): + df["observation_value"] = df.observation_value / 100 + + df["observation_date"] = to_datetime( + df["observation_date"], format="%b %Y" + ).dt.date + children = ( + df.groupby("parent_id")["element_id"] + .apply(lambda x: x.sort_values().unique().tolist()) + .to_dict() + ) + children = {k: ",".join(v) for k, v in children.items()} + df["children"] = df.element_id.map(children) + df = ( + df.set_index(["element_id", "children", "parent_id", "level"]) + .sort_index() + .reset_index() + .replace({nan: None}) + ) + results.extend(df.to_dict("records")) + + await asyncio.gather(*[get_one(URL) for URL in URLS]) + + return results + + @staticmethod + def transform_data( + query: FredNonFarmPayrollsQueryParams, + data: List[Dict], + **kwargs: Any, + ) -> List[FredNonFarmPayrollsData]: + """Transform data.""" + if not data: + raise EmptyDataError("The request was returned empty.") + unique_order_index = { + name: index for index, name in enumerate(NFP_SECTOR_ORDER) + } + + return [ + FredNonFarmPayrollsData.model_validate(d) + for d in sorted( + data, + key=lambda x: ( + x["observation_date"], + unique_order_index.get(x["name"], len(NFP_SECTOR_ORDER)), + ), + ) + ] diff --git a/openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_non_farm_payrolls_fetcher_urllib3_v1.yaml b/openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_non_farm_payrolls_fetcher_urllib3_v1.yaml new file mode 100644 index 000000000000..ecedd7a2002c --- /dev/null +++ b/openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_non_farm_payrolls_fetcher_urllib3_v1.yaml @@ -0,0 +1,71 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://api.stlouisfed.org/fred/release/tables?api_key=MOCK_API_KEY&element_id=6490&file_type=json&include_observation_values=true&observation_date=2024-06-01&release_id=50 + response: + body: + string: !!binary | + H4sIAAAAAAAEA6pWykvMTVWyUnIsSy1KTE9VCE9Nzc6pVHBNLMrLzEsvVtJRSs1JzU3NK4nPTFGy + MjOxNNBRKkrNSU0sTgWLKJkaINQUK1lVK5mZmFuAaFR95hao+kwNdJSKU4syU4shxji7BhuYGoCB + oaGSjlJBYhGqpTmZealKVnmlOTk6SiWVBSA3Q/Qr6cD8EJJfkpijUFCUWZZYkqqko5STWpaao2Sl + BDIvP6k4tagssSQzPy++LDGnFKTfUMfIwEAP7AFk6RSQbislr9I8BSMDIxMlHaXkjMyclKLUPCWr + 6GolNH9ZEvaXGdhbBpj+AgUKEf5yz89PKdYtKMpPKU3OzEtH8pmRko4SstMRPjMxstQzAkUNsjRp + PjMh6DNDiMew+cxSR4kIn/lmglKZQmJeikJOfno6queMcXrO3MJUz8gCTRqv52JrddBiztSAsP+M + KPWfc35ecUlRaTIo2SFFG26fmVha6hmTFG2YPjOxMCIYc8aU+sw3Ma80LTG5pLSI2EgzNjPTsyDJ + axgxRoS/oEkSM6+BAoWIFOlSWpSYlJOqkA7Kc0hRBioGkLMSUk4zM9QztKQsMZpYGhKOMmhqJNtr + fvl5KST7zsjAXM8UvZghkNVia7EkSnNTgj40sICkSkwfEllQBkCKfgVQUZ+ZnAoqMssyU1ATKLpf + EBFpaGqmZ0ZSRKIlUBNLwn40gXgRW5FpSlSRGVKUmJKqo1BSlJhXXJBfVAKu0nTARWhpSWZOZklm + KqjWhtV9uIsaAwNLPUvKvGtMMEpNDE3AyRYzSkFhRUR+DM/Iz0ktTsxJBfk4BblWx5cjLfUM0T1O + IM2iVw8mluaEPQf2mgGWuCTSc0GpJYmZOUT7zNzIUM/UnMKSxsKMsL+gtQPZkRaCkjjBabM8sSg1 + I7+0GDUz4o5DQzNjPUNTCv1qRkQcmhiBY5Fsv4ZiyXS4vGWkY2hkqWdOYssFS2FqQbg1DW1MY0mc + oJKYiJznmZeWX5QLLl6Q6kH0bIUoPi0MTPUs0H1OYq4zNSBcpJhCfYYZY0R6zC0zLzEvOTMxRyEx + uSSzjPgS09zQQM+A0jRpSTjqoP0F8qMuoCg/LbW4ODM/D+TJvBSFJFDGSy0uhtWMxNUQpsbmeoaU + ljfmhMsbM0pj1DWlNBmcUMFFTUZqYk5JBmleNTQ20DMnqXGKLVcSLm7MKa3+fVIzi0uLUiEezS8u + yCxJzMksqSQih5qaGegZo7d+SMyfJuZo3X8s3XhoI4781OtfkpFaRFr0GRia6pmid/MJ+A3cSgWN + VlhiGa0Y7dVja9aYj/bqQeNGo716RK0/2quHjQxiqRCGX68eVF6aYCkvCY+lQQdmsFULg69UUTIz + NcD05jAaMlQyM7EwwoxH0CAZ8ug+luod2jekIB5HRw6hsw8moyOHKHMr0BaZqQFmyjQ1GD5jv0pm + JpaGmHlvWFUWOqCKwhTTk6AuOoECZnQUmIjBmdFRYOjcLvqAE6JlamI2OgoMmbPG0jIdHQUuQl56 + YDI6CoxjTcXoKDB4YBFpzcjoKHB+XjyBsTWM2bTRUWDk4mZ0FJjwYi66jQKDmqqWWJqqoDlcAk3V + 0cl88OI9M/DCByJaraOT+YjFh6OT+fiWWWJpsg6byXxQ/98Ys2tsSXjqe+ispgH50RyLHwnPkELW + C2GbfQIVyEQUMvRYVAMaPjXD9N5w7lUpmZmYYYnR4ZErQW0ACyyr1ofNOhvQhAZmmTMMl9uACh4s + ETncV92AhluxFEjDuNsFKoKxlEcWhGuYodb7AsWtAWZlM4yW4gBWWwsA1uLwgYg0AAA= + headers: + Cache-Control: + - max-age=0, no-cache + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Length: + - '1361' + Content-Type: + - application/json; charset=UTF-8 + Date: + - Tue, 09 Jul 2024 15:38:45 GMT + Expires: + - Tue, 09 Jul 2024 15:38:45 GMT + Last-Modified: + - Tue, 09 Jul 2024 15:37:34 GMT + Pragma: + - no-cache + Server: + - Apache + Set-Cookie: + - ak_bmsc=74B55348324C48CB5F65724DA21B1BFE~000000000000000000000000000000~YAAQlr8mF7dLcpaQAQAA9bElmBgJcc/H2SCmjETbR6aEian7MP7hfsodsyrRQwz+KIMA0EuwiiUd6W4BGnftTNkp3NO1TLHF9I2ZVwHNkLjgqo2d0b9lzk9DhYQSPC6trMrWT3TY2rGitT1YoGv2zMtfFK3TJChVoUaN8zhNjrh0pTDIq8bOQ2FuykMzJas6cPJzG/jBVc0byYIf1pLzzvI81a68oHdRyVt7bkhvCKiA4EfS6yv9Uo64RPJqCSDVoYRNbso2uh1pGAV5/Mj21sNHjLtO/llxR97yez1oWVkGHteec+FkQMyV5mCE8EUTK+LlqsFkFd2FA7Y7yWib90oMiUWF+OEeR01qKfN7ALSxRS+17AHR4Url05tTWek=; + Domain=.stlouisfed.org; Path=/; Expires=Tue, 09 Jul 2024 17:38:45 GMT; Max-Age=7200 + Strict-Transport-Security: + - max-age=86400 + Vary: + - Accept-Encoding + status: + code: 200 + message: OK +version: 1 diff --git a/openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_non_farm_payrolls_fetcher_urllib3_v2.yaml b/openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_non_farm_payrolls_fetcher_urllib3_v2.yaml new file mode 100644 index 000000000000..da0150d2e4ba --- /dev/null +++ b/openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_non_farm_payrolls_fetcher_urllib3_v2.yaml @@ -0,0 +1,71 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://api.stlouisfed.org/fred/release/tables?api_key=MOCK_API_KEY&element_id=6490&file_type=json&include_observation_values=true&observation_date=2024-06-01&release_id=50 + response: + body: + string: !!binary | + H4sIAAAAAAAEA6pWykvMTVWyUnIsSy1KTE9VCE9Nzc6pVHBNLMrLzEsvVtJRSs1JzU3NK4nPTFGy + MjOxNNBRKkrNSU0sTgWLKJkaINQUK1lVK5mZmFuAaFR95hao+kwNdJSKU4syU4shxji7BhuYGoCB + oaGSjlJBYhGqpTmZealKVnmlOTk6SiWVBSA3Q/Qr6cD8EJJfkpijUFCUWZZYkqqko5STWpaao2Sl + BDIvP6k4tagssSQzPy++LDGnFKTfUMfIwEAP7AFk6RSQbislr9I8BSMDIxMlHaXkjMyclKLUPCWr + 6GolNH9ZEvaXGdhbBpj+AgUKEf5yz89PKdYtKMpPKU3OzEtH8pmRko4SstMRPjMxstQzAkUNsjRp + PjMh6DNDiMew+cxSR4kIn/lmglKZQmJeikJOfno6queMcXrO3MJUz8gCTRqv52JrddBiztSAsP+M + KPWfc35ecUlRaTIo2SFFG26fmVha6hmTFG2YPjOxMCIYc8aU+sw3Ma80LTG5pLSI2EgzNjPTsyDJ + axgxRoS/oEkSM6+BAoWIFOlSWpSYlJOqkA7Kc0hRBioGkLMSUk4zM9QztKQsMZpYGhKOMmhqJNtr + fvl5KST7zsjAXM8UvZghkNVia7EkSnNTgj40sICkSkwfEllQBkCKfgVQUZ+ZnAoqMssyU1ATKLpf + EBFpaGqmZ0ZSRKIlUBNLwn40gXgRW5FpSlSRGVKUmJKqo1BSlJhXXJBfVAKu0nTARWhpSWZOZklm + KqjWhtV9uIsaAwNLPUvKvGtMMEpNDE3AyRYzSkFhRUR+DM/Iz0ktTsxJBfk4BblWx5cjLfUM0T1O + IM2iVw8mluaEPQf2mgGWuCTSc0GpJYmZOUT7zNzIUM/UnMKSxsKMsL+gtQPZkRaCkjjBabM8sSg1 + I7+0GDUz4o5DQzNjPUNTCv1qRkQcmhiBY5Fsv4ZiyXS4vGWkY2hkqWdOYssFS2FqQbg1DW1MY0mc + oJKYiJznmZeWX5QLLl6Q6kH0bIUoPi0MTPUs0H1OYq4zNSBcpJhCfYYZY0R6zC0zLzEvOTMxRyEx + uSSzjPgS09zQQM+A0jRpSTjqoP0F8qMuoCg/LbW4ODM/D+TJvBSFJFDGSy0uhtWMxNUQpsbmeoaU + ljfmhMsbM0pj1DWlNBmcUMFFTUZqYk5JBmleNTQ20DMnqXGKLVcSLm7MKa3+fVIzi0uLUiEezS8u + yCxJzMksqSQih5qaGegZo7d+SMyfJuZo3X8s3XhoI4781OtfkpFaRFr0GRia6pmid/MJ+A3cSgWN + VlhiGa0Y7dVja9aYj/bqQeNGo716RK0/2quHjQxiqRCGX68eVF6aYCkvCY+lQQdmsFULg69UUTIz + NcD05jAaMlQyM7EwwoxH0CAZ8ug+luod2jekIB5HRw6hsw8moyOHKHMr0BaZqQFmyjQ1GD5jv0pm + JpaGmHlvWFUWOqCKwhTTk6AuOoECZnQUmIjBmdFRYOjcLvqAE6JlamI2OgoMmbPG0jIdHQUuQl56 + YDI6CoxjTcXoKDB4YBFpzcjoKHB+XjyBsTWM2bTRUWDk4mZ0FJjwYi66jQKDmqqWWJqqoDlcAk3V + 0cl88OI9M/DCByJaraOT+YjFh6OT+fiWWWJpsg6byXxQ/98Ys2tsSXjqe+ispgH50RyLHwnPkELW + C2GbfQIVyEQUMvRYVAMaPjXD9N5w7lUpmZmYYYnR4ZErQW0ACyyr1ofNOhvQhAZmmTMMl9uACh4s + ETncV92AhluxFEjDuNsFKoKxlEcWhGuYodb7AsWtAWZlM4yW4gBWWwsA1uLwgYg0AAA= + headers: + Cache-Control: + - max-age=0, no-cache + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Length: + - '1361' + Content-Type: + - application/json; charset=UTF-8 + Date: + - Tue, 09 Jul 2024 15:37:34 GMT + Expires: + - Tue, 09 Jul 2024 15:37:34 GMT + Last-Modified: + - Tue, 09 Jul 2024 15:37:34 GMT + Pragma: + - no-cache + Server: + - Apache + Set-Cookie: + - ak_bmsc=4A04CAE310FB615D89BB47AC19BBB92E~000000000000000000000000000000~YAAQlr8mF4A7cpaQAQAAiZwkmBjEDXq47dtacADgxSiVsqNumu/y3jurk1g0+Fpaqfd0q+9Y9RUleaRfk1h6o8jcH6kj9FiCHwfO/7KqoJAtgvgaa8jK5QsF5rFpYG/vJ7mjDcSL6lCpMdW/1WQ4XAd5cr8htdVaGiGx5AMCsKzFcRTBuB6cfU6PuVWDrXY9jhm0jodlzd5qRplXrqm/h/IvHNLmZzj7l7iBqq/oDlMezpGC6DOgy9SkgszprFi4RK4TsWf4h7u0mM/d/e0r0ESQknG4CNfOhRwR70o/xIMp5tL23W+uk0pPbfNuq6znnx1DBll4JLq9+xnem+Po1OCAbJOn1SRWF77LboB4MLJu/mXNR3b9KYYpnTUGmjNb; + Domain=.stlouisfed.org; Path=/; Expires=Tue, 09 Jul 2024 17:37:34 GMT; Max-Age=7200 + Strict-Transport-Security: + - max-age=86400 + Vary: + - Accept-Encoding + status: + code: 200 + message: OK +version: 1 diff --git a/openbb_platform/providers/fred/tests/test_fred_fetchers.py b/openbb_platform/providers/fred/tests/test_fred_fetchers.py index 918dcf2b9d51..4b7904a344ee 100644 --- a/openbb_platform/providers/fred/tests/test_fred_fetchers.py +++ b/openbb_platform/providers/fred/tests/test_fred_fetchers.py @@ -27,6 +27,7 @@ ) from openbb_fred.models.moody import FREDMoodyCorporateBondIndexFetcher from openbb_fred.models.mortgage_indices import FredMortgageIndicesFetcher +from openbb_fred.models.non_farm_payrolls import FredNonFarmPayrollsFetcher from openbb_fred.models.overnight_bank_funding_rate import ( FredOvernightBankFundingRateFetcher, ) @@ -473,3 +474,16 @@ def test_fred_overnight_bank_funding_rate_fetcher(credentials=test_credentials): fetcher = FredOvernightBankFundingRateFetcher() result = fetcher.test(params, credentials) assert result is None + + +@pytest.mark.record_http +def test_fred_non_farm_payrolls_fetcher(credentials=test_credentials): + """Test FredNonFarmPayrollsFetcher.""" + params = { + "date": "2024-06-01", + "category": "avg_earnings_weekly", + } + + fetcher = FredNonFarmPayrollsFetcher() + result = fetcher.test(params, credentials) + assert result is None