[Feature] Add Svensson Nominal Yield Curve From Federal Reserve (#7338)

* add svensson yield curve, cleanup fomc documents endpoint, make provider a standalone extension, move apps from platform-api into extension, and update some models to add prefix/suffix in widget definitions

* black

* do what codeQL says

* black again

* use get_args instead of Literal.__args__

* linting

* test items

* grammar police

* test functions need to start with test_*

* test params

* add total factor productivity from sf fed

* openpyxl required for Excel file handling

* grammar police

* inflation expectations

* Update pr-description check action to properly handle quotes

---------

Co-authored-by: deeleeramone <>
Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com>
This commit is contained in:
Danglewood
2026-02-02 08:05:57 -08:00
committed by GitHub
parent 4ab9e27a56
commit 06041a8b3a
39 changed files with 49139 additions and 515 deletions

View File

@@ -1,6 +1,7 @@
# OpenBB Federal Reserve Provider
This extension integrates the [Federal Reserve](https://www.federalreserve.gov/data.htm) data provider into the OpenBB Platform.
It focuses on Federal Reserve data not published to FRED. No authorization is required for access.
## Installation
@@ -10,4 +11,56 @@ To install the extension:
pip install openbb-federal-reserve
```
Documentation available [here](https://docs.openbb.co/platform/developer_guide/contributing).
Then build the Python static assets by running:
```sh
openbb-build
```
## Quick Start
The fastest way to get started is by connecting to the OpenBB Workspace as a custom backend.
### Start Server
```sh
openbb-api
```
This starts the FastAPI server over localhost on port 6900.
### Add to Workspace
See the documentation [here](https://docs.openbb.co/odp/python/quickstart/workspace) for more details.
### Click to Open App
Once added, click on the app to open the dashboard.
The dashboard contains widgets with metadata and information, as well ones for exploring and retrieving the data.
## Coverage
This extension creates multiple OpenBB Workspace apps, along with individual widgets for each endpoint.
### Apps
- FOMC Documents - Current and historical PDF documents of minutes, projections, Beige Books, policy statements, and more.
- Federal Reserve System - Stats & Indicators - Data statistics and indicators from the regional members of the Federal Reserve System.
### Endpoints
- `.economy.money_measures`
- `.economy.central_bank_holdings`
- `.economy.primary_dealer_positioning`
- `.economy.primary_dealer_fails`
- `.economy.fomc_documents`
- `.economy.total_factor_productivity`
- `.economy.survey.inflation_expectations`
- `.fixedincome.rate.sofr`
- `.fixedincome.rate.effr`
- `.fixedincome.rate.overnight_bank_funding`
- `.fixedincome.government.yield_curve`
- `.fixedincome.government.treasury_rates`
- `.fixedincome.government.svensson_yield_curve`

View File

@@ -0,0 +1,56 @@
"""Test Federal Reserve API."""
# pylint: disable=too-many-lines,redefined-outer-name
import base64
import pytest
import requests
from openbb_core.env import Env
from openbb_core.provider.utils.helpers import get_querystring
@pytest.fixture(scope="session")
def headers():
"""Get the headers for the API request."""
userpass = f"{Env().API_USERNAME}:{Env().API_PASSWORD}"
userpass_bytes = userpass.encode("ascii")
base64_bytes = base64.b64encode(userpass_bytes)
return {"Authorization": f"Basic {base64_bytes.decode('ascii')}"}
@pytest.mark.integration
def test_federal_reserve_fomc_documents_download(headers):
"""Test the federal reserve fomc documents download endpoint."""
params = {
"url": [
"https://www.federalreserve.gov/monetarypolicy/files/BeigeBook_20230118.pdf"
]
}
url = "http://localhost:8000/api/v1/federal_reserve/fomc_documents_download"
result = requests.post(url, headers=headers, timeout=10, json=params)
assert isinstance(result, requests.Response)
assert result.status_code == 200
@pytest.mark.parametrize(
"params",
[
{
"year": 2022,
"document_type": "minutes",
}
],
)
@pytest.mark.integration
def test_federal_reserve_fomc_documents_choices(headers, params):
"""Test the federal reserve fomc documents choices endpoint."""
url = (
"http://localhost:8000/api/v1/federal_reserve/fomc_documents_choices?"
+ get_querystring(params, [])
)
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200

View File

@@ -0,0 +1,54 @@
"""Federal Reserve Utilities module integration tests."""
import pytest
from openbb_core.app.model.obbject import OBBject
# pylint: disable=redefined-outer-name
@pytest.fixture(scope="session")
def obb(pytestconfig): # pylint: disable=inconsistent-return-statements
"""Fixture to setup obb."""
if pytestconfig.getoption("markexpr") != "not integration":
import openbb # pylint: disable=import-outside-toplevel
return openbb.obb
@pytest.mark.skip(reason="Not implemented in Python Interface.")
@pytest.mark.parametrize(
"params",
[{"params": {}}],
)
@pytest.mark.integration
def test_federal_reserve_fomc_documents_download(params, obb):
"""Test federal_reserve_fomc_documents_download endpoint."""
params = {
"url": [
"https://www.federalreserve.gov/monetarypolicy/files/BeigeBook_20230118.pdf"
]
}
result = obb.federal_reserve.fomc_documents_download(**params)
assert result
assert isinstance(result, OBBject)
@pytest.mark.skip(reason="Not implemented in Python Interface.")
@pytest.mark.parametrize(
"params",
[
{
"year": 2022,
"document_type": "minutes",
}
],
)
@pytest.mark.integration
def test_federal_reserve_fomc_documents_choices(params, obb):
"""Test federal_reserve_fomc_documents_choices endpoint."""
result = obb.federal_reserve.fomc_documents_choices(**params)
assert result
assert isinstance(result, OBBject)

View File

@@ -10,6 +10,9 @@ from openbb_federal_reserve.models.federal_funds_rate import (
from openbb_federal_reserve.models.fomc_documents import (
FederalReserveFomcDocumentsFetcher,
)
from openbb_federal_reserve.models.inflation_expectations import (
FederalReserveInflationExpectationsFetcher,
)
from openbb_federal_reserve.models.money_measures import (
FederalReserveMoneyMeasuresFetcher,
)
@@ -23,6 +26,12 @@ from openbb_federal_reserve.models.primary_dealer_positioning import (
FederalReservePrimaryDealerPositioningFetcher,
)
from openbb_federal_reserve.models.sofr import FederalReserveSOFRFetcher
from openbb_federal_reserve.models.svensson_yield_curve import (
FederalReserveSvenssonFetcher,
)
from openbb_federal_reserve.models.total_factor_productivity import (
FederalReserveTfpFetcher,
)
from openbb_federal_reserve.models.treasury_rates import (
FederalReserveTreasuryRatesFetcher,
)
@@ -36,11 +45,14 @@ federal_reserve_provider = Provider(
"CentralBankHoldings": FederalReserveCentralBankHoldingsFetcher,
"FederalFundsRate": FederalReserveFederalFundsRateFetcher,
"FomcDocuments": FederalReserveFomcDocumentsFetcher,
"InflationExpectations": FederalReserveInflationExpectationsFetcher,
"MoneyMeasures": FederalReserveMoneyMeasuresFetcher,
"OvernightBankFundingRate": FederalReserveOvernightBankFundingRateFetcher,
"PrimaryDealerFails": FederalReservePrimaryDealerFailsFetcher,
"PrimaryDealerPositioning": FederalReservePrimaryDealerPositioningFetcher,
"SOFR": FederalReserveSOFRFetcher,
"SvenssonYieldCurve": FederalReserveSvenssonFetcher,
"TotalFactorProductivity": FederalReserveTfpFetcher,
"TreasuryRates": FederalReserveTreasuryRatesFetcher,
"YieldCurve": FederalReserveYieldCurveFetcher,
},

View File

@@ -0,0 +1,726 @@
[
{
"name": "FOMC Documents",
"img": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Flag_of_the_United_States_Federal_Reserve.svg/640px-Flag_of_the_United_States_Federal_Reserve.svg.png",
"img_dark": "",
"img_light": "",
"description": "Read current and historical FOMC documents, beginning 1959.",
"allowCustomization": true,
"tabs": {
"overview": {
"id": "overview",
"name": "overview",
"layout": [
{
"i": "economy_fomc_documents_federal_reserve_obb",
"x": 0,
"y": 0,
"w": 40,
"h": 42,
"state": {
"params": {
"year": 2025
}
}
}
]
}
},
"groups": []
},
{
"name": "Federal Reserve System - Stats & Indicators",
"img": "https://upload.wikimedia.org/wikipedia/commons/1/1a/Seal_of_the_United_States_Federal_Reserve_System.svg",
"img_dark": "https://upload.wikimedia.org/wikipedia/commons/1/1a/Seal_of_the_United_States_Federal_Reserve_System.svg",
"img_light": "https://upload.wikimedia.org/wikipedia/commons/1/1a/Seal_of_the_United_States_Federal_Reserve_System.svg",
"description": "Data statistics and indactors generated from within the regional members of the Federal Reserve System.",
"allowCustomization": true,
"tabs": {
"rates": {
"id": "rates",
"name": "Rates",
"layout": [
{
"i": "fixedincome_rate_sofr_federal_reserve_obb",
"x": 0,
"y": 2,
"w": 19,
"h": 18,
"state": {
"params": {
"start_date": "2020-01-01"
},
"chartModel": {
"modelType": "range",
"chartType": "customCombo",
"chartOptions": {
"line": {
"legend": {
"enabled": false
}
}
},
"cellRange": {
"columns": [
"date",
"rate"
]
},
"suppressChartRanges": true,
"seriesChartTypes": [
{
"colId": "rate",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_1",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_25",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_75",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_99",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "volume",
"chartType": "line",
"secondaryAxis": true
}
]
},
"chartView": {
"enabled": true,
"chartType": "customCombo"
},
"columnState": {
"default": {
"columnPinning": {
"leftColIds": [
"date"
],
"rightColIds": []
},
"columnOrder": {
"orderedColIds": [
"date",
"rate",
"percentile_1",
"percentile_25",
"percentile_75",
"percentile_99",
"volume"
]
}
}
}
},
"groups": [
"Group 1"
]
},
{
"i": "fixedincome_rate_effr_federal_reserve_obb",
"x": 0,
"y": 20,
"w": 40,
"h": 16,
"state": {
"params": {
"start_date": "2020-01-01"
},
"chartModel": {
"modelType": "range",
"chartType": "line",
"chartOptions": {},
"cellRange": {
"columns": [
"date",
"rate",
"target_range_upper",
"target_range_lower"
]
},
"suppressChartRanges": true
},
"chartView": {
"enabled": true,
"chartType": "line"
},
"columnState": {
"default": {
"columnPinning": {
"leftColIds": [
"date"
],
"rightColIds": []
},
"columnVisibility": {
"hiddenColIds": [
"revision_indicator"
]
},
"columnOrder": {
"orderedColIds": [
"date",
"rate",
"target_range_upper",
"target_range_lower",
"percentile_1",
"percentile_25",
"percentile_75",
"percentile_99",
"volume",
"revision_indicator"
]
}
}
}
},
"groups": [
"Group 1"
]
},
{
"i": "fixedincome_rate_overnight_bank_funding_federal_reserve_obb",
"x": 19,
"y": 2,
"w": 21,
"h": 18,
"state": {
"params": {
"start_date": "2020-01-01"
},
"chartModel": {
"modelType": "range",
"chartType": "customCombo",
"chartOptions": {
"line": {
"legend": {
"enabled": false
}
}
},
"cellRange": {
"columns": [
"date",
"rate"
]
},
"suppressChartRanges": true,
"seriesChartTypes": [
{
"colId": "rate",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_1",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_25",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_75",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "percentile_99",
"chartType": "line",
"secondaryAxis": false
},
{
"colId": "volume",
"chartType": "line",
"secondaryAxis": true
}
]
},
"chartView": {
"enabled": true,
"chartType": "customCombo"
},
"columnState": {
"default": {
"columnPinning": {
"leftColIds": [
"date"
],
"rightColIds": []
},
"columnOrder": {
"orderedColIds": [
"date",
"rate",
"percentile_1",
"percentile_25",
"percentile_75",
"percentile_99",
"volume"
]
}
}
}
},
"groups": [
"Group 1"
]
}
]
},
"svensson-yield-curve": {
"id": "svensson-yield-curve",
"name": "Svensson Yield Curve",
"layout": [
{
"i": "fixedincome_government_svensson_yield_curve_federal_reserve_obb",
"x": 0,
"y": 2,
"w": 40,
"h": 23,
"state": {
"params": {
"series_type": [
"forward_1y"
],
"start_date": "2020-01-01"
},
"chartModel": {
"modelType": "range",
"chartType": "line",
"chartOptions": {},
"cellRange": {
"columns": [
"date",
"sven1f01",
"sven1f04",
"sven1f09"
]
},
"suppressChartRanges": true
},
"chartView": {
"enabled": true,
"chartType": "line"
},
"columnState": {
"default": {
"columnPinning": {
"leftColIds": [
"date"
],
"rightColIds": []
},
"columnOrder": {
"orderedColIds": [
"date",
"sven1f01",
"sven1f04",
"sven1f09"
]
}
}
}
},
"groups": [
"Group 1"
]
}
]
},
"money-measures": {
"id": "money-measures",
"name": "Money Measures",
"layout": [
{
"i": "economy_money_measures_federal_reserve_obb",
"x": 0,
"y": 2,
"w": 40,
"h": 22,
"state": {
"params": {
"start_date": "2020-01-01",
"adjusted": "false"
},
"chartView": {
"enabled": false,
"chartType": "line"
},
"columnState": {
"default": {
"columnOrder": {
"orderedColIds": [
"month",
"currency",
"demand_deposits",
"retail_money_market_funds",
"small_denomination_time_deposits",
"other_liquid_deposits",
"m1",
"m2"
]
}
}
}
},
"groups": [
"Group 1"
]
}
]
},
"inflation-expectations": {
"id": "inflation-expectations",
"name": "Inflation Expectations",
"layout": [
{
"i": "economy_survey_inflation_expectations_federal_reserve_obb",
"x": 0,
"y": 2,
"w": 40,
"h": 27,
"state": {
"params": {
"start_date": "2020-01-01"
},
"chartModel": {
"modelType": "range",
"chartType": "line",
"chartOptions": {},
"cellRange": {
"columns": [
"date",
"infpgdp1yr",
"infcpi1yr",
"infcpi10yr"
]
},
"suppressChartRanges": true
},
"chartView": {
"enabled": true,
"chartType": "line"
}
},
"groups": [
"Group 1"
]
}
]
},
"central-bank-holdings": {
"id": "central-bank-holdings",
"name": "Central Bank Holdings",
"layout": [
{
"i": "economy_central_bank_holdings_federal_reserve_obb",
"x": 0,
"y": 2,
"w": 40,
"h": 23,
"state": {
"params": {
"monthly": "true"
},
"chartView": {
"enabled": false,
"chartType": "line"
},
"columnState": {
"default": {
"columnPinning": {
"leftColIds": [
"date"
],
"rightColIds": []
},
"columnOrder": {
"orderedColIds": [
"date",
"security_type",
"cusip",
"issuer",
"maturity_date",
"par_value",
"coupon",
"spread",
"percent_outstanding",
"change_prior_week",
"change_prior_year",
"tips_inflation_compensation"
]
}
}
}
},
"groups": []
}
]
},
"primary-dealer-positioning": {
"id": "primary-dealer-positioning",
"name": "Primary Dealer Positioning",
"layout": [
{
"i": "economy_primary_dealer_positioning_federal_reserve_obb",
"x": 0,
"y": 2,
"w": 20,
"h": 23,
"state": {
"params": {
"start_date": "2020-01-01",
"category": "bills"
},
"chartModel": {
"modelType": "range",
"chartType": "line",
"chartOptions": {},
"cellRange": {
"columns": [
"date",
"value"
]
},
"suppressChartRanges": true
},
"chartView": {
"enabled": false,
"chartType": "line"
},
"columnState": {
"default": {
"columnPinning": {
"leftColIds": [
"date",
"symbol",
"title"
],
"rightColIds": []
},
"columnVisibility": {
"hiddenColIds": [
"symbol",
"name"
]
},
"columnOrder": {
"orderedColIds": [
"date",
"symbol",
"value",
"title",
"name"
]
}
}
}
},
"groups": [
"Group 1"
]
},
{
"i": "economy_primary_dealer_fails_federal_reserve_obb",
"x": 20,
"y": 2,
"w": 20,
"h": 23,
"state": {
"params": {
"start_date": "2020-01-01",
"asset_class": "treasuries"
},
"chartModel": {
"modelType": "range",
"chartType": "line",
"chartOptions": {},
"cellRange": {
"columns": [
"date",
"value"
]
},
"suppressChartRanges": true
},
"chartView": {
"enabled": true,
"chartType": "line"
},
"columnState": {
"default": {
"pivot": {
"pivotMode": false,
"pivotColIds": [
"title"
]
},
"columnPinning": {
"leftColIds": [
"date",
"symbol"
],
"rightColIds": []
},
"columnOrder": {
"orderedColIds": [
"date",
"title",
"value",
"symbol"
]
}
}
}
},
"groups": [
"Group 1"
]
}
]
},
"total-factor-productivity": {
"id": "total-factor-productivity",
"name": "Total Factor Productivity",
"layout": [
{
"i": "economy_total_factor_productivity_federal_reserve_obb",
"x": 0,
"y": 2,
"w": 40,
"h": 12,
"state": {
"params": {
"frequency": "summary"
},
"chartView": {
"enabled": false,
"chartType": "line"
},
"columnState": {
"default": {
"columnOrder": {
"orderedColIds": [
"variable",
"variable_title",
"full_sample_mean",
"past_4_quarters",
"past_8_quarters",
"since_2019",
"period_2004_2019",
"period_1995_2004",
"period_1973_1995",
"period_1947_1973"
]
},
"rowSelection": [
"2"
]
}
}
},
"groups": []
},
{
"i": "economy_total_factor_productivity_federal_reserve_obb",
"x": 0,
"y": 14,
"w": 40,
"h": 16,
"state": {
"params": {
"frequency": "annual"
},
"chartModel": {
"modelType": "range",
"chartType": "line",
"chartOptions": {
"line": {
"legend": {
"enabled": true
}
}
},
"cellRange": {
"columns": [
"date",
"d_tfp",
"d_hours",
"d_y"
]
},
"suppressChartRanges": true
},
"chartView": {
"enabled": true,
"chartType": "line"
},
"columnState": {
"default": {
"columnPinning": {
"leftColIds": [
"date"
],
"rightColIds": []
},
"columnOrder": {
"orderedColIds": [
"date",
"d_y_prod",
"d_y_inc",
"d_y",
"d_hours",
"d_lp",
"d_k",
"d_lq_bls_interpolated",
"d_lq_aaronson_sullivan",
"d_lq",
"alpha",
"d_tfp",
"d_util",
"d_tfp_util",
"relative_price",
"inv_share",
"d_tfp_i",
"d_tfp_c",
"d_u_invest",
"d_u_consumption",
"d_tfp_i_util",
"d_tfp_c_util"
]
}
}
}
},
"groups": []
}
]
}
},
"groups": [
{
"name": "Group 1",
"type": "param",
"paramName": "start_date",
"defaultValue": "2020-01-01"
}
]
}
]

View File

@@ -138,4 +138,4 @@ class FederalReserveFederalFundsRateFetcher(
_ = d.pop("footnoteId", None)
results.append(FederalReserveFederalFundsRateData.model_validate(d))
return results
return sorted(results, key=lambda x: x.date)

View File

@@ -2,15 +2,27 @@
# pylint: disable=unused-argument
from datetime import datetime
from datetime import (
date as dateType,
datetime,
)
from typing import Any
from openbb_core.app.service.system_service import SystemService
from openbb_core.provider.abstract.data import Data
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.abstract.query_params import QueryParams
from openbb_core.provider.utils.errors import EmptyDataError
from openbb_federal_reserve.utils.fomc_documents import FomcDocumentType
from pydantic import Field, field_validator
from pydantic import ConfigDict, Field, field_validator
api_prefix = (
SystemService()
.system_settings.python_settings.model_dump()
.get("api_settings", {})
.get("prefix", "")
or "/api/v1"
)
choice_types = list(FomcDocumentType.__args__)
choices = [
@@ -45,17 +57,10 @@ class FederalReserveFomcDocumentsQueryParams(QueryParams):
},
"document_type": {
"x-widget_config": {
"type": "text",
"value": None,
"options": choices,
"description": "Filter by document type. Default is all.",
}
},
"pdf_only": {
"x-widget_config": {"value": True, "type": "boolean", "show": False}
},
"as_choices": {
"x-widget_config": {"value": True, "type": "boolean", "show": False}
},
}
year: int | None = Field(
@@ -66,15 +71,6 @@ class FederalReserveFomcDocumentsQueryParams(QueryParams):
default=None,
description=f"Filter by document type. Default is all. Choose from: {', '.join(choice_types)}",
)
pdf_only: bool = Field(
default=False,
description="Whether to return as a list with only the PDF documents. Default is False.",
)
as_choices: bool = Field(
default=False,
description="Whether to return cast as a list of valid Workspace parameter choices."
+ " Leave as False for typical use.",
)
@field_validator("document_type", mode="before", check_fields=False)
@classmethod
@@ -90,19 +86,55 @@ class FederalReserveFomcDocumentsQueryParams(QueryParams):
class FederalReserveFomcDocumentsData(Data):
"""Federal Reserve FOMC Documents Data."""
content: Any = Field(
default=None,
description="The content of request results."
+ " If `url` was provided, the content is a dictionary with keys `filename` and `content`."
+ " Otherwise, it is a list of dictionaries with a mapping of FOMC documents to URLs."
+ " The endpoint response will not be an OBBject.results object, but the content directly.",
model_config = ConfigDict(
json_schema_extra={
"x-widget_config": {
"$.type": "multi_file_viewer",
"$.name": "FOMC PDF Document Viewer",
"$.description": "Current and historical FOMC PDF materials.",
"$.gridData": {
"w": 30,
"h": 27,
},
"$.refetchInterval": False,
"$.endpoint": f"{api_prefix}/federal_reserve/fomc_documents_download",
"$.params": [
{
"type": "endpoint",
"paramName": "url",
"optionsEndpoint": f"{api_prefix}/federal_reserve/fomc_documents_choices",
"optionsParams": {
"document_type": "$document_type",
"year": "$year",
},
"show": False,
"multiSelect": True,
"roles": ["fileSelector"],
},
],
"$.data": {},
}
}
)
date: dateType = Field(
description="The date of the document, formatted as YYYY-MM-DD.",
)
doc_type: str = Field(
description="The type of the FOMC document.",
)
doc_format: str = Field(
description="The format of the document (e.g., pdf, htm).",
)
url: str = Field(
description="The URL of the document.",
)
class FederalReserveFomcDocumentsFetcher(
Fetcher[
FederalReserveFomcDocumentsQueryParams,
FederalReserveFomcDocumentsData,
list[FederalReserveFomcDocumentsData],
]
):
"""Federal Reserve FOMC Documents Fetcher."""
@@ -115,55 +147,26 @@ class FederalReserveFomcDocumentsFetcher(
return FederalReserveFomcDocumentsQueryParams(**params)
@staticmethod
def extract_data(
async def aextract_data(
query: FederalReserveFomcDocumentsQueryParams,
credentials: dict[str, str] | None,
**kwargs: Any,
) -> dict:
) -> list[dict]:
"""Extract the raw data."""
# pylint: disable=import-outside-toplevel
from openbb_federal_reserve.utils.fomc_documents import (
get_fomc_documents_by_year,
)
docs = get_fomc_documents_by_year(
query.year, query.document_type, query.pdf_only
)
if query.as_choices is True:
choices_list: list = []
for doc in docs:
if query.pdf_only is True and doc.get("doc_format", "") != "pdf":
continue
title = (
doc.get("doc_type", "").replace("_", " ").title()
+ " - "
+ doc.get("date", "")
)
value = doc.get("url", "")
if title and value:
choices_list.append(
{
"label": title,
"value": value,
}
)
output = {"content": choices_list}
return output
output = {"content": docs}
return output
return get_fomc_documents_by_year(query.year, query.document_type)
@staticmethod
def transform_data(
query: FederalReserveFomcDocumentsQueryParams,
data: dict,
data: list[dict],
**kwargs: Any,
) -> FederalReserveFomcDocumentsData:
) -> list[FederalReserveFomcDocumentsData]:
"""Transform data."""
if not data:
raise EmptyDataError("No FOMC documents found.")
return FederalReserveFomcDocumentsData(content=data.get("content"))
return [FederalReserveFomcDocumentsData.model_validate(d) for d in data]

View File

@@ -0,0 +1,200 @@
"""Survey of Professional Forecasters - Inflation Expectations Data Model."""
# pylint: disable=unused-argument
from datetime import date as dateType
from typing import Any
from openbb_core.app.model.abstract.error import OpenBBError
from openbb_core.provider.abstract.data import Data
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.abstract.query_params import QueryParams
from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS
from openbb_core.provider.utils.lru import ttl_cache
from pydantic import AliasGenerator, ConfigDict, Field
URL = (
"https://www.philadelphiafed.org/-/media/FRBP/Assets/Surveys-And-Data"
"/survey-of-professional-forecasters/historical-data/Inflation.xlsx"
)
@ttl_cache(ttl=86400)
def download_inflation_excel() -> bytes:
"""Download the Inflation Expectations Excel file from the Philadelphia Fed.
Returns:
bytes: The Excel file content.
"""
# pylint: disable=import-outside-toplevel
from openbb_core.provider.utils.helpers import make_request
response = make_request(URL)
response.raise_for_status()
return response.content
class FederalReserveInflationExpectationsQueryParams(QueryParams):
"""Federal Reserve Inflation Expectations Query Parameters."""
start_date: dateType | None = Field(
default=None,
description=QUERY_DESCRIPTIONS.get("start_date", "")
+ " Data begins from 1970-04-01 and is quarterly.",
)
end_date: dateType | None = Field(
default=None,
description=QUERY_DESCRIPTIONS.get("end_date", ""),
)
class FederalReserveInflationExpectationsData(Data):
"""Survey of Professional Forecasters Inflation Expectations Data.
Contains one-year-ahead and ten-year-ahead inflation forecasts from the
Philadelphia Fed's Survey of Professional Forecasters.
The one-year-ahead series are expectations for average inflation over the
four quarters following the survey quarter.
Source: https://www.philadelphiafed.org/surveys-and-data/real-time-data-research/inflation-forecasts
"""
model_config = ConfigDict(
populate_by_name=True,
alias_generator=AliasGenerator(
validation_alias=lambda field_name: field_name,
serialization_alias=lambda field_name: field_name,
),
json_schema_extra={
"x-widget_config": {
"description": "One-year-ahead and ten-year-ahead inflation forecasts "
"from the Philadelphia Fed's Survey of Professional Forecasters."
}
},
)
date: dateType = Field(
description="The date of the survey (first day of the survey quarter).",
title="Date",
)
infpgdp1yr: float | None = Field(
default=None,
description=(
"One-year-ahead annual-average GDP price index inflation forecast. "
"Computed from median forecasts of GDP price index levels (PGDP2 and PGDP6). "
"Formula: ((PGDP6/PGDP2) - 1) * 100. Available from 1970:Q2."
),
title="GDP Deflator Inflation (1-Year)",
json_schema_extra={"x-unit_measurement": "percent"},
)
infcpi1yr: float | None = Field(
default=None,
description=(
"One-year-ahead annual-average CPI inflation forecast. "
"Computed as the geometric average of quarter-over-quarter median CPI forecasts "
"(CPI3 to CPI6). Available from 1981:Q3."
),
title="CPI Inflation (1-Year)",
json_schema_extra={"x-unit_measurement": "percent"},
)
infcpi10yr: float | None = Field(
default=None,
description=(
"Ten-year-ahead annual-average CPI inflation forecast. "
"Expected average annual rate of CPI inflation over the next 10 years. "
"Available from 1991:Q4."
),
title="CPI Inflation (10-Year)",
json_schema_extra={"x-unit_measurement": "percent"},
)
class FederalReserveInflationExpectationsFetcher(
Fetcher[
FederalReserveInflationExpectationsQueryParams,
list[FederalReserveInflationExpectationsData],
]
):
"""Federal Reserve Inflation Expectations Fetcher."""
@staticmethod
def transform_query(
params: dict[str, Any],
) -> FederalReserveInflationExpectationsQueryParams:
"""Transform input parameters into query params."""
return FederalReserveInflationExpectationsQueryParams(**params)
@staticmethod
def extract_data(
query: FederalReserveInflationExpectationsQueryParams,
credentials: dict[str, str] | None,
**kwargs: Any,
) -> dict:
"""Download the Excel data from the Philadelphia Fed."""
try:
return {"file": download_inflation_excel()}
except Exception as e: # pylint: disable=broad-except
raise OpenBBError(e) from e
@staticmethod
def transform_data(
query: FederalReserveInflationExpectationsQueryParams,
data: dict,
**kwargs: Any,
) -> list[FederalReserveInflationExpectationsData]:
"""Transform the Excel data into validated Pydantic models."""
# pylint: disable=import-outside-toplevel
from io import BytesIO # noqa
from openpyxl import load_workbook
from pandas import DataFrame, to_datetime
wb = load_workbook(
filename=BytesIO(data["file"]),
read_only=True,
data_only=True,
keep_vba=False,
)
ws = wb["INFLATION"]
df = DataFrame(ws.values)
df.columns = df.iloc[0]
df = df.iloc[1:]
wb.close()
df.columns = df.columns.str.lower()
quarter_to_month = {1: 1, 2: 4, 3: 7, 4: 10}
df["date"] = to_datetime(
df["year"].astype(int).astype(str)
+ "-"
+ df["quarter"].map(quarter_to_month).astype(str)
+ "-01"
).dt.date
# Apply date filters
if query.start_date:
df = df[df["date"] >= query.start_date]
if query.end_date:
df = df[df["date"] <= query.end_date]
df = (
df[["date", "infpgdp1yr", "infcpi1yr", "infcpi10yr"]]
.replace({"#N/A": None})
.set_index("date")
.sort_index()
.dropna(how="all", axis=0)
.reset_index()
)
results = [
FederalReserveInflationExpectationsData.model_validate(row.to_dict())
for _, row in df.iterrows()
]
if not results:
raise OpenBBError(
"The query filters resulted in no data. "
"Try again with different date parameters."
)
return results

View File

@@ -12,8 +12,8 @@ from openbb_core.provider.standard_models.money_measures import (
)
titles = {
"M1": "M1",
"M2": "M2",
"M1": "m1",
"M2": "m2",
"MCU": "currency",
"MDD": "demand_deposits",
"MMFGB": "retail_money_market_funds",
@@ -109,4 +109,4 @@ class FederalReserveMoneyMeasuresFetcher(
d[k] = None
fed_data.append(FederalReserveMoneyMeasuresData.model_validate(d))
return fed_data
return sorted(fed_data, key=lambda x: x.month)

View File

@@ -119,4 +119,4 @@ class FederalReserveOvernightBankFundingRateFetcher(
_ = d.pop("footnoteId", None)
results.append(FederalReserveOvernightBankFundingRateData.model_validate(d))
return results
return sorted(results, key=lambda x: x.date)

View File

@@ -65,6 +65,7 @@ class FederalReservePrimaryDealerPositioningData(PrimaryDealerPositioningData):
json_schema_extra={
"x-unit_measurement": "currency",
"x-frontend_multiply": 1e6,
"x-widget_config": {"prefix": "$", "suffix": "M"},
},
)
name: str = Field(
@@ -145,8 +146,15 @@ class FederalReservePrimaryDealerPositioningFetcher(
lambda x: POSITION_SERIES_TO_FIELD["dealer_position"].get(x)
)
df["title"] = df.symbol.map(lambda x: POSITION_SERIES_TO_TITLE.get(x))
df["date"] = df["date"].astype("datetime64[ns]").dt.date
if query.start_date:
df = df[df["date"] >= query.start_date]
if query.end_date:
df = df[df["date"] <= query.end_date]
return [
FederalReservePrimaryDealerPositioningData.model_validate(d)
for d in df.to_dict(orient="records")
for d in df.sort_values(by="date").to_dict(orient="records")
]

View File

@@ -15,11 +15,11 @@ from pydantic import field_validator
class FederalReserveSOFRQueryParams(SOFRQueryParams):
"""FederalReserve FED Query."""
"""Federal Reserve SOFR Query."""
class FederalReserveSOFRData(SOFRData):
"""FederalReserve FED Data."""
"""Federal Reserve SOFR Data."""
__alias_dict__ = {
"date": "effectiveDate",
@@ -105,4 +105,4 @@ class FederalReserveSOFRFetcher(
_ = d.pop("revisionIndicator", None)
results.append(FederalReserveSOFRData.model_validate(d))
return results
return sorted(results, key=lambda x: x.date)

View File

@@ -0,0 +1,632 @@
"""Federal Reserve Total Factor Productivity Model."""
# pylint: disable=unused-argument
from datetime import date as dateType
from typing import Any, Literal
from openbb_core.app.model.abstract.error import OpenBBError
from openbb_core.provider.abstract.data import Data
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.abstract.query_params import QueryParams
from openbb_core.provider.utils.descriptions import (
DATA_DESCRIPTIONS,
QUERY_DESCRIPTIONS,
)
from openbb_core.provider.utils.lru import ttl_cache
from pydantic import ConfigDict, Field, model_serializer
TFP_URL = "http://www.frbsf.org/economic-research/files/quarterly_tfp.xlsx"
EXCEL_TO_FIELD = {
"dY_prod": "d_y_prod",
"dY_inc": "d_y_inc",
"dY": "d_y",
"dhours": "d_hours",
"dLP": "d_lp",
"dk": "d_k",
"dLQ_BLS_interpolated": "d_lq_bls_interpolated",
"dLQ_Aaronson_Sullivan": "d_lq_aaronson_sullivan",
"dLQ": "d_lq",
"alpha": "alpha",
"dtfp": "d_tfp",
"dutil": "d_util",
"dtfp_util": "d_tfp_util",
"relativePrice": "relative_price",
"invShare": "inv_share",
"dtfp_I": "d_tfp_i",
"dtfp_C": "d_tfp_c",
"du_invest": "d_u_invest",
"du_consumption": "d_u_consumption",
"dtfp_I_util": "d_tfp_i_util",
"dtfp_C_util": "d_tfp_c_util",
}
NUMERIC_FIELDS = tuple(EXCEL_TO_FIELD.values())
SUMMARY_FIELDS = (
"full_sample_mean",
"past_4_quarters",
"past_8_quarters",
"since_2019",
"period_2004_2019",
"period_1995_2004",
"period_1973_1995",
"period_1947_1973",
)
ALL_FLOAT_FIELDS = NUMERIC_FIELDS + SUMMARY_FIELDS
PERIOD_COLUMN_MAP = {
"Full sample mean": "full_sample_mean",
"1947:1-1973:1": "period_1947_1973",
"1973:1-1995:4": "period_1973_1995",
"1995:4-2004:4": "period_1995_2004",
"2004:4-2019:4": "period_2004_2019",
"Since 2019:4": "since_2019",
"Past 8 qtrs": "past_8_quarters",
"Past 4 qtrs": "past_4_quarters",
}
VARIABLE_TITLES = {
"d_y_prod": "Output (Product Side)",
"d_y_inc": "Output (Income Side)",
"d_y": "Output",
"d_hours": "Hours",
"d_lp": "Labor Productivity",
"d_k": "Capital Input",
"d_lq_bls_interpolated": "Labor Quality (BLS Interpolated)",
"d_lq_aaronson_sullivan": "Labor Quality (Aaronson-Sullivan)",
"d_lq": "Labor Quality",
"alpha": "Capital Share",
"d_tfp": "TFP",
"d_util": "Utilization",
"d_tfp_util": "Utilization-Adjusted TFP",
"relative_price": "Relative Price",
"inv_share": "Investment Share",
"d_tfp_i": "TFP (Investment)",
"d_tfp_c": "TFP (Consumption)",
"d_u_invest": "Utilization (Investment)",
"d_u_consumption": "Utilization (Consumption)",
"d_tfp_i_util": "Utilization-Adjusted TFP (Investment)",
"d_tfp_c_util": "Utilization-Adjusted TFP (Consumption)",
}
TIME_SERIES_FIELDS = {"date", *NUMERIC_FIELDS}
SUMMARY_RECORD_FIELDS = {"variable", "variable_title", *SUMMARY_FIELDS}
@ttl_cache(ttl=86400)
def download_tfp_excel() -> bytes:
"""Download the TFP Excel file from the San Francisco Federal Reserve.
Returns:
bytes: The Excel file content.
"""
# pylint: disable=import-outside-toplevel
from openbb_core.provider.utils.helpers import make_request
response = make_request(TFP_URL)
response.raise_for_status()
return response.content
class FederalReserveTfpQueryParams(QueryParams):
"""Federal Reserve Total Factor Productivity Query Parameters.
This data contains Total Factor Productivity estimates from the
San Francisco Federal Reserve, including quarterly and annual time series
as well as summary statistics across different time periods.
Source: http://www.frbsf.org/economic-research/indicators-data/total-factor-productivity-tfp/
"""
frequency: Literal["quarter", "annual", "summary"] = Field(
default="quarter",
description="Type of data to return. "
"'quarter' for quarterly time series, "
"'annual' for annual time series, "
"'summary' for summary statistics (period means).",
)
start_date: dateType | None = Field(
default=None,
description=QUERY_DESCRIPTIONS.get("start_date", "")
+ " Only applicable for time series data (quarter/annual).",
)
end_date: dateType | None = Field(
default=None,
description=QUERY_DESCRIPTIONS.get("end_date", "")
+ " Only applicable for time series data (quarter/annual).",
)
class FederalReserveTfpTimeSeriesData(Data):
"""Federal Reserve Total Factor Productivity time series fields.
Base class containing time series specific fields.
"""
model_config = ConfigDict(populate_by_name=True)
date: dateType | None = Field(
default=None,
description=DATA_DESCRIPTIONS.get("date", ""),
)
d_y_prod: float | None = Field(
default=None,
title="Output (Product Side)",
description=(
"Business output, expenditure (product) side. "
"From NIPA tables, Gross Value Added: Total Business: Quantity Index."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_y_inc: float | None = Field(
default=None,
title="Output (Income Side)",
description=(
"Business output, measured from income side. "
"Nominal business output is GDI less nominal non-business output. "
"Real business income uses expenditure-side deflator."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_y: float | None = Field(
default=None,
title="Output",
description=(
"Output. Average of d_y_prod and d_y_inc (weighted equally). "
"If d_y_inc not yet available, equals d_y_prod."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_hours: float | None = Field(
default=None,
title="Hours",
description="Hours worked in the business sector. From BLS productivity and cost release.",
json_schema_extra={"x-unit_measurement": "percent"},
)
d_lp: float | None = Field(
default=None,
title="Labor Productivity",
description=(
"Business-sector labor productivity, defined as d_y - d_hours. "
"Note: Labor productivity in the BLS productivity-and-cost release equals d_y_prod - d_hours."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_k: float | None = Field(
default=None,
title="Capital Input",
description=(
"Capital input. Perpetual inventory stocks calculated from disaggregated quarterly NIPA "
"investment data, then growth rates are weighted by estimated rental prices."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_lq_bls_interpolated: float | None = Field(
default=None,
title="Labor Quality (BLS Interpolated)",
description=(
"Labor composition/quality from BLS. Pre-1979 is interpolated annual BLS MFP estimate "
"of labor composition (interpolated using Denton (1971) relative to changes in hours)."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_lq_aaronson_sullivan: float | None = Field(
default=None,
title="Labor Quality (Aaronson-Sullivan)",
description=(
"Labor composition/quality following Aaronson-Sullivan. 1979:Q1 - present follows "
"Aaronson and Sullivan (2001), as extended by Bart Hobijn and Joyce Kwok (FRBSF)."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_lq: float | None = Field(
default=None,
title="Labor Quality",
description=(
"Labor composition/quality actually used. Pre-1979 is d_lq_bls_interpolated, "
"1979:Q1 onward uses d_lq_aaronson_sullivan."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
alpha: float | None = Field(
default=None,
title="Capital Share",
description=(
"Capital's share of income (ratio between 0 and 1). Based primarily on NIPA data for "
"the corporate sector, assuming private noncorporate factor shares match corporate shares."
),
)
d_tfp: float | None = Field(
default=None,
title="TFP",
description=(
"Business sector Total Factor Productivity. Calculated as d_y - alpha*d_k - "
"(1-alpha)*(d_hours+d_lq), i.e., output growth less the contribution of capital and labor."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_util: float | None = Field(
default=None,
title="Utilization",
description=(
"Utilization adjustment for capital and labor. Uses Basu, Fernald, Fisher, and Kimball "
"(2013) estimates applied to quarterly data."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_tfp_util: float | None = Field(
default=None,
title="Utilization-Adjusted TFP",
description=(
"Utilization-adjusted Total Factor Productivity. Calculated as d_tfp - d_util, "
"adjusting for variations in factor utilization."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
relative_price: float | None = Field(
default=None,
title="Relative Price",
description=(
"Relative price growth of 'consumption' to price of 'equipment'. Measures the relative "
"price of non-equipment goods and services to price of equipment (with consumer durables "
"classified as equipment)."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
inv_share: float | None = Field(
default=None,
title="Investment Share",
description=(
"Equipment and consumer durables share of business output (ratio between 0 and 1). "
"Represents the proportion of output devoted to equipment investment and consumer durables."
),
)
d_tfp_i: float | None = Field(
default=None,
title="TFP (Investment)",
description=(
"TFP in equipment and consumer durables sector. Calculated from d_tfp assuming that "
"relative price growth reflects relative TFP growth."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_tfp_c: float | None = Field(
default=None,
title="TFP (Consumption)",
description=(
"TFP in non-equipment business output ('consumption' goods and services). Calculated from "
"d_tfp assuming that relative price growth reflects relative TFP growth."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_u_invest: float | None = Field(
default=None,
title="Utilization (Investment)",
description=(
"Utilization adjustment in producing investment goods. Uses estimates from Basu, Fernald, "
"Fisher, and Kimball to calculate utilization for producing equipment and consumer durables."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_u_consumption: float | None = Field(
default=None,
title="Utilization (Consumption)",
description=(
"Utilization adjustment in producing non-investment business output ('consumption'). Uses "
"estimates from Basu, Fernald, Fisher, and Kimball to calculate utilization for producing "
"non-investment goods and services."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_tfp_i_util: float | None = Field(
default=None,
title="Utilization-Adjusted TFP (Investment)",
description=(
"Utilization-adjusted TFP in producing equipment and consumer durables. "
"Calculated as d_tfp_i - d_u_invest."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
d_tfp_c_util: float | None = Field(
default=None,
title="Utilization-Adjusted TFP (Consumption)",
description=(
"Utilization-adjusted TFP in producing non-equipment business output ('consumption'). "
"Calculated as d_tfp_c - d_u_consumption."
),
json_schema_extra={"x-unit_measurement": "percent"},
)
class FederalReserveTfpSummaryData(Data):
"""Federal Reserve Total Factor Productivity summary fields.
Base class containing summary statistics specific fields.
"""
model_config = ConfigDict(populate_by_name=True)
variable: str | None = Field(
default=None,
title="Variable",
description="The variable name (e.g., 'd_y', 'd_tfp', 'd_tfp_util').",
)
variable_title: str | None = Field(
default=None,
title="Variable Title",
description="Human-readable title for the variable.",
)
full_sample_mean: float | None = Field(
default=None,
title="Full Sample Mean",
description="Mean value over the full sample period.",
json_schema_extra={"x-unit_measurement": "percent"},
)
past_4_quarters: float | None = Field(
default=None,
title="Past 4 Quarters",
description="Mean value over the past 4 quarters.",
json_schema_extra={"x-unit_measurement": "percent"},
)
past_8_quarters: float | None = Field(
default=None,
title="Past 8 Quarters",
description="Mean value over the past 8 quarters.",
json_schema_extra={"x-unit_measurement": "percent"},
)
since_2019: float | None = Field(
default=None,
title="Since 2019:4",
description="Mean value since 2019:Q4.",
json_schema_extra={"x-unit_measurement": "percent"},
)
period_2004_2019: float | None = Field(
default=None,
title="2004:4-2019:4",
description="Mean value for the period 2004:Q4 to 2019:Q4.",
json_schema_extra={"x-unit_measurement": "percent"},
)
period_1995_2004: float | None = Field(
default=None,
title="1995:4-2004:4",
description="Mean value for the period 1995:Q4 to 2004:Q4.",
json_schema_extra={"x-unit_measurement": "percent"},
)
period_1973_1995: float | None = Field(
default=None,
title="1973:1-1995:4",
description="Mean value for the period 1973:Q1 to 1995:Q4.",
json_schema_extra={"x-unit_measurement": "percent"},
)
period_1947_1973: float | None = Field(
default=None,
title="1947:1-1973:1",
description="Mean value for the period 1947:Q1 to 1973:Q1.",
json_schema_extra={"x-unit_measurement": "percent"},
)
class FederalReserveTfpData(
FederalReserveTfpTimeSeriesData, FederalReserveTfpSummaryData
):
"""Federal Reserve Total Factor Productivity data.
Combined model containing both time series and summary fields.
For time series data (frequency='quarter' or 'annual'):
- date: Date of the observation
- d_y_prod, d_y_inc, d_y: Output measures
- d_hours, d_lp, d_k: Labor and capital inputs
- d_tfp, d_tfp_util: TFP measures
- And other productivity variables
For summary data (frequency='summary'):
- variable: The variable name
- full_sample_mean: Mean over full sample
- period_*: Means for specific time periods
- past_*_quarters: Recent period means
Source: http://www.frbsf.org/economic-research/indicators-data/total-factor-productivity-tfp/
"""
model_config = ConfigDict(
json_schema_extra={
"x-widget_config": {
"$.description": "A Quarterly, Utilization-Adjusted Series on Total Factor Productivity (SF Fed)",
"$.refetchInterval": False,
}
},
populate_by_name=True,
)
@classmethod
def __get_pydantic_json_schema__( # pylint: disable=W0221
cls, core_schema, handler
) -> dict[str, Any]:
"""Override JSON schema generation to preserve all inherited field properties.
This method ensures all fields are included in the OpenAPI schema.
"""
json_schema = handler(core_schema)
if "properties" not in json_schema or not json_schema["properties"]:
json_schema["properties"] = {}
for field_name, field_info in cls.model_fields.items():
field_schema: dict[str, Any] = {}
annotation = field_info.annotation
if hasattr(annotation, "__origin__"):
args = getattr(annotation, "__args__", ())
if type(None) in args:
inner_type = next((a for a in args if a is not type(None)), str)
if inner_type is float:
field_schema["anyOf"] = [
{"type": "number"},
{"type": "null"},
]
elif inner_type is str:
field_schema["anyOf"] = [
{"type": "string"},
{"type": "null"},
]
else:
field_schema["anyOf"] = [
{"type": "string", "format": "date"},
{"type": "null"},
]
else:
field_schema["type"] = "string"
field_schema["default"] = field_info.default
field_schema["title"] = (
field_info.title or field_name.replace("_", " ").title()
)
if field_info.description:
field_schema["description"] = field_info.description
if field_info.json_schema_extra:
field_schema.update(field_info.json_schema_extra)
json_schema["properties"][field_name] = field_schema
# Preserve x-widget_config from model_config.json_schema_extra
config_extra = cls.model_config.get("json_schema_extra", {})
if "x-widget_config" in config_extra:
json_schema["x-widget_config"] = config_extra["x-widget_config"]
return json_schema
@model_serializer(mode="wrap")
def _serialize(self, handler) -> dict[str, Any]:
"""Serialize only relevant fields based on record type."""
data = handler(self)
if self.variable is not None:
return {k: v for k, v in data.items() if k in SUMMARY_RECORD_FIELDS}
return {k: v for k, v in data.items() if k in TIME_SERIES_FIELDS}
class FederalReserveTfpFetcher(
Fetcher[FederalReserveTfpQueryParams, list[FederalReserveTfpData]]
):
"""Federal Reserve Total Factor Productivity Fetcher."""
@staticmethod
def transform_query(params: dict[str, Any]) -> FederalReserveTfpQueryParams:
"""Transform input parameters into FederalReserveTfpQueryParams."""
return FederalReserveTfpQueryParams(**params)
@staticmethod
def extract_data(
query: FederalReserveTfpQueryParams,
credentials: dict[str, str] | None,
**kwargs: Any,
) -> dict:
"""Download the Excel data from the San Francisco Federal Reserve."""
try:
return {"file": download_tfp_excel()}
except Exception as e: # pylint: disable=broad-except
raise OpenBBError(e) from e
@staticmethod
def transform_data(
query: FederalReserveTfpQueryParams,
data: dict,
**kwargs: Any,
) -> list[FederalReserveTfpData]:
"""Transform the Excel data into validated Pydantic models."""
# pylint: disable=import-outside-toplevel
from io import BytesIO # noqa
import numpy as np
import pandas as pd
excel_file = pd.ExcelFile(BytesIO(data["file"]))
frequency = query.frequency
sheet_name = "quarterly" if frequency in ("quarter", "summary") else "annual"
skiprows = 1 if sheet_name == "quarterly" else None
df = pd.read_excel(excel_file, sheet_name=sheet_name, skiprows=skiprows)
date_col = df.columns[0]
# Rename Excel columns to snake_case field names
df = df.rename(columns=EXCEL_TO_FIELD)
if sheet_name == "quarterly":
valid_mask = df[date_col].astype(str).str.match(r"^\d{4}:Q[1-4]$")
else:
valid_mask = df[date_col].apply(
lambda x: np.issubdtype(type(x), np.integer)
or (isinstance(x, float) and x == int(x))
)
if frequency == "summary":
# Summary rows are those that don't match the date pattern
summary_df = df[~valid_mask].copy()
summary_df = summary_df.rename(columns={date_col: "period"})
summary_df = summary_df[summary_df["period"].isin(PERIOD_COLUMN_MAP.keys())]
summary_df = summary_df.set_index("period").T.reset_index()
summary_df = summary_df.rename(
columns={"index": "variable", **PERIOD_COLUMN_MAP}
)
summary_df["variable_title"] = summary_df["variable"].map(VARIABLE_TITLES)
summary_df = summary_df.replace({np.nan: None})
results: list[FederalReserveTfpData] = [
FederalReserveTfpData.model_validate(row.to_dict())
for _, row in summary_df.iterrows()
]
if not results:
raise OpenBBError(
"No summary data found. The data source may have changed."
)
return results
# Time series data
data_df = df[valid_mask].copy()
if frequency == "quarter":
# Convert "YYYY:QN" to proper dates
date_series = pd.PeriodIndex(
data_df[date_col].str.replace(":", ""), freq="Q"
).to_timestamp()
data_df[date_col] = date_series.date
else:
# Annual: convert year to January 1 of that year
data_df[date_col] = pd.to_datetime(
data_df[date_col].astype(int), format="%Y"
).dt.date
data_df = data_df.rename(columns={date_col: "date"})
# Apply date filters
if query.start_date:
data_df = data_df[data_df["date"] >= query.start_date]
if query.end_date:
data_df = data_df[data_df["date"] <= query.end_date]
data_df = data_df.replace({np.nan: None})
results = [
FederalReserveTfpData.model_validate(row.to_dict())
for _, row in data_df.iterrows()
]
if not results:
raise OpenBBError(
"The query filters resulted in no data. "
"Try again with different date parameters."
)
return results

View File

@@ -0,0 +1,141 @@
"""OpenBB Federal Reserve Router Module."""
from typing import Annotated
from fastapi import APIRouter, Body
from openbb_core.app.model.abstract.error import OpenBBError
router = APIRouter()
@router.get("/apps.json", include_in_schema=False)
async def get_apps_json():
"""Get the apps.json for the Federal Reserve provider."""
# pylint: disable=import-outside-toplevel
import json
from pathlib import Path
apps_json_path = Path(__file__).parent / "assets" / "apps.json"
with open(apps_json_path, encoding="utf-8") as file:
apps_data = json.load(file)
return apps_data
@router.post(
"/fomc_documents_download",
include_in_schema=False,
openapi_extra={},
)
async def fomc_documents_download(params: Annotated[dict, Body()]) -> list:
"""Download FOMC documents from the Federal Reserve's website.
PDFs are base64 encoded under the `content` key in the response.
Parameters
----------
params : dict
A dictionary with a key "url" containing a list of URLs to download.
Returns
-------
list
A list of dictionaries, each containing keys `filename`, `content`, and `data_format`.
"""
# pylint: disable=import-outside-toplevel
import base64 # noqa
from io import BytesIO
from urllib.parse import urlparse
from openbb_core.provider.utils.helpers import make_request
urls = params.get("url", [])
results: list = []
for url in urls:
parsed_url = urlparse(url)
hostname = parsed_url.hostname or ""
if parsed_url.scheme != "https" or hostname not in {
"www.federalreserve.gov",
"federalreserve.gov",
}:
raise OpenBBError(
"Invalid URL provided for download. Must be from federalreserve.gov -> "
+ url
)
is_pdf = url.lower().endswith(".pdf")
if (
not is_pdf
and not url.lower().endswith(".htm")
and not url.lower().endswith(".html")
):
raise OpenBBError(
"Unsupported document format. File must be PDF or HTM type -> " + url
)
try:
response = make_request(url)
response.raise_for_status()
pdf = (
base64.b64encode(BytesIO(response.content).getvalue()).decode("utf-8")
if isinstance(response.content, bytes)
else response.content
)
results.append(
{
"content": pdf,
"data_format": {
"data_type": "pdf" if is_pdf else "markdown",
"filename": url.split("/")[-1],
},
}
)
except Exception as exc:
results.append(
{
"error_type": "download_error",
"content": f"{exc.__class__.__name__}: {exc.args[0]}",
"filename": url.split("/")[-1],
}
)
continue
return results
@router.get("/fomc_documents_choices", include_in_schema=False)
async def fomc_documents_choices(
year: int | None = None, document_type: str | None = None
) -> list:
"""Get the available choices for FOMC document types.
Returns
-------
list
A list of available document choices with URLs for download.
"""
# pylint: disable=import-outside-toplevel
from openbb_federal_reserve.utils.fomc_documents import (
get_fomc_documents_by_year,
)
docs = get_fomc_documents_by_year(year, document_type, True)
choices_list: list = []
for doc in docs:
title = (
doc.get("doc_type", "").replace("_", " ").title()
+ " - "
+ doc.get("date", "")
)
value = doc.get("url", "")
if title and value:
choices_list.append(
{
"label": title,
"value": value,
}
)
return choices_list

View File

@@ -3,6 +3,8 @@
from functools import lru_cache
from typing import Literal
from openbb_core.provider.utils.lru import ttl_cache
FomcDocumentType = Literal[
"all",
"monetary_policy",
@@ -27,18 +29,20 @@ def load_historical_fomc_documents() -> list:
"""Load historical FOMC documents map from the static assets."""
# pylint: disable=import-outside-toplevel
import json
from pathlib import Path
historical_docs: list = []
historical_docs_path = __file__.replace(
"utils/fomc_documents.py", "assets/historical_releases.json"
historical_docs_path = (
Path(__file__).parent.parent / "assets" / "historical_releases.json"
)
with open(historical_docs_path, encoding="utf-8") as file:
historical_docs = json.load(file)
return historical_docs
@lru_cache(maxsize=64)
@ttl_cache(maxsize=1, ttl=3600)
def get_current_fomc_documents(url: str | None = None) -> list:
"""
Get the current FOMC documents from https://www.federalreserve.gov/monetarypolicy/fomccalendars.htm.
@@ -123,7 +127,7 @@ def get_current_fomc_documents(url: str | None = None) -> list:
return data_releases
@lru_cache(maxsize=32)
@ttl_cache(maxsize=32, ttl=3600)
def get_fomc_documents_by_year(
year: int | None = None,
document_type: FomcDocumentType | None = None,

View File

@@ -302,7 +302,7 @@ def _get_endpoints( # pylint: disable=R0917
async def fetch_data(url: str) -> dict:
"""Fetch the JSON response from the API."""
try:
response = await amake_request(url)
response = await amake_request(url, timeout=30)
except Exception as e: # pylint: disable=broad-except
raise e from e
return response # type: ignore

View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.3.1 and should not be changed by hand.
[[package]]
name = "aiohappyeyeballs"
@@ -426,6 +426,42 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "deepdiff"
version = "8.6.1"
description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "deepdiff-8.6.1-py3-none-any.whl", hash = "sha256:ee8708a7f7d37fb273a541fa24ad010ed484192cd0c4ffc0fa0ed5e2d4b9e78b"},
{file = "deepdiff-8.6.1.tar.gz", hash = "sha256:ec56d7a769ca80891b5200ec7bd41eec300ced91ebcc7797b41eb2b3f3ff643a"},
]
[package.dependencies]
orderly-set = ">=5.4.1,<6"
[package.extras]
cli = ["click (>=8.1.0,<8.2.0)", "pyyaml (>=6.0.0,<6.1.0)"]
coverage = ["coverage (>=7.6.0,<7.7.0)"]
dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)", "jsonpickle (>=4.0.0,<4.1.0)", "nox (==2025.5.1)", "numpy (>=2.0,<3.0) ; python_version < \"3.10\"", "numpy (>=2.2.0,<2.3.0) ; python_version >= \"3.10\"", "orjson (>=3.10.0,<3.11.0)", "pandas (>=2.2.0,<2.3.0)", "polars (>=1.21.0,<1.22.0)", "python-dateutil (>=2.9.0,<2.10.0)", "tomli (>=2.2.0,<2.3.0)", "tomli-w (>=1.2.0,<1.3.0)", "uuid6 (==2025.0.1)"]
docs = ["Sphinx (>=6.2.0,<6.3.0)", "sphinx-sitemap (>=2.6.0,<2.7.0)", "sphinxemoji (>=0.3.0,<0.4.0)"]
optimize = ["orjson"]
static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)", "pydantic (>=2.10.0,<2.11.0)"]
test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"]
[[package]]
name = "et-xmlfile"
version = "2.0.0"
description = "An implementation of lxml.xmlfile for the standard library"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"},
{file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"},
]
[[package]]
name = "exceptiongroup"
version = "1.3.1"
@@ -683,158 +719,158 @@ type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-myp
[[package]]
name = "multidict"
version = "6.7.0"
version = "6.7.1"
description = "multidict implementation"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349"},
{file = "multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e"},
{file = "multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3"},
{file = "multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046"},
{file = "multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32"},
{file = "multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73"},
{file = "multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc"},
{file = "multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62"},
{file = "multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84"},
{file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0"},
{file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e"},
{file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4"},
{file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648"},
{file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111"},
{file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36"},
{file = "multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85"},
{file = "multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7"},
{file = "multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0"},
{file = "multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc"},
{file = "multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721"},
{file = "multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6"},
{file = "multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c"},
{file = "multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7"},
{file = "multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7"},
{file = "multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9"},
{file = "multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8"},
{file = "multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd"},
{file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb"},
{file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6"},
{file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2"},
{file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff"},
{file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b"},
{file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34"},
{file = "multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff"},
{file = "multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81"},
{file = "multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912"},
{file = "multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184"},
{file = "multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45"},
{file = "multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa"},
{file = "multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7"},
{file = "multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e"},
{file = "multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546"},
{file = "multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4"},
{file = "multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1"},
{file = "multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d"},
{file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304"},
{file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12"},
{file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62"},
{file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0"},
{file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a"},
{file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8"},
{file = "multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4"},
{file = "multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b"},
{file = "multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec"},
{file = "multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6"},
{file = "multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159"},
{file = "multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca"},
{file = "multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8"},
{file = "multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60"},
{file = "multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4"},
{file = "multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f"},
{file = "multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf"},
{file = "multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32"},
{file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036"},
{file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec"},
{file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e"},
{file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64"},
{file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd"},
{file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288"},
{file = "multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17"},
{file = "multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390"},
{file = "multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e"},
{file = "multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00"},
{file = "multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb"},
{file = "multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b"},
{file = "multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c"},
{file = "multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1"},
{file = "multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b"},
{file = "multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5"},
{file = "multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad"},
{file = "multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c"},
{file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5"},
{file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10"},
{file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754"},
{file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c"},
{file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762"},
{file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6"},
{file = "multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d"},
{file = "multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6"},
{file = "multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792"},
{file = "multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842"},
{file = "multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b"},
{file = "multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38"},
{file = "multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128"},
{file = "multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34"},
{file = "multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99"},
{file = "multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202"},
{file = "multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1"},
{file = "multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3"},
{file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d"},
{file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6"},
{file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7"},
{file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb"},
{file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f"},
{file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f"},
{file = "multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885"},
{file = "multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c"},
{file = "multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000"},
{file = "multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63"},
{file = "multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718"},
{file = "multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2"},
{file = "multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e"},
{file = "multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064"},
{file = "multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e"},
{file = "multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd"},
{file = "multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a"},
{file = "multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96"},
{file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e"},
{file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599"},
{file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394"},
{file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38"},
{file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9"},
{file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0"},
{file = "multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13"},
{file = "multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd"},
{file = "multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827"},
{file = "multidict-6.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:363eb68a0a59bd2303216d2346e6c441ba10d36d1f9969fcb6f1ba700de7bb5c"},
{file = "multidict-6.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d874eb056410ca05fed180b6642e680373688efafc7f077b2a2f61811e873a40"},
{file = "multidict-6.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b55d5497b51afdfde55925e04a022f1de14d4f4f25cdfd4f5d9b0aa96166851"},
{file = "multidict-6.7.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f8e5c0031b90ca9ce555e2e8fd5c3b02a25f14989cbc310701823832c99eb687"},
{file = "multidict-6.7.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cf41880c991716f3c7cec48e2f19ae4045fc9db5fc9cff27347ada24d710bb5"},
{file = "multidict-6.7.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cfc12a8630a29d601f48d47787bd7eb730e475e83edb5d6c5084317463373eb"},
{file = "multidict-6.7.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3996b50c3237c4aec17459217c1e7bbdead9a22a0fcd3c365564fbd16439dde6"},
{file = "multidict-6.7.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7f5170993a0dd3ab871c74f45c0a21a4e2c37a2f2b01b5f722a2ad9c6650469e"},
{file = "multidict-6.7.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ec81878ddf0e98817def1e77d4f50dae5ef5b0e4fe796fae3bd674304172416e"},
{file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9281bf5b34f59afbc6b1e477a372e9526b66ca446f4bf62592839c195a718b32"},
{file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:68af405971779d8b37198726f2b6fe3955db846fee42db7a4286fc542203934c"},
{file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3ba3ef510467abb0667421a286dc906e30eb08569365f5cdb131d7aff7c2dd84"},
{file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b61189b29081a20c7e4e0b49b44d5d44bb0dc92be3c6d06a11cc043f81bf9329"},
{file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fb287618b9c7aa3bf8d825f02d9201b2f13078a5ed3b293c8f4d953917d84d5e"},
{file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:521f33e377ff64b96c4c556b81c55d0cfffb96a11c194fd0c3f1e56f3d8dd5a4"},
{file = "multidict-6.7.0-cp39-cp39-win32.whl", hash = "sha256:ce8fdc2dca699f8dbf055a61d73eaa10482569ad20ee3c36ef9641f69afa8c91"},
{file = "multidict-6.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:7e73299c99939f089dd9b2120a04a516b95cdf8c1cd2b18c53ebf0de80b1f18f"},
{file = "multidict-6.7.0-cp39-cp39-win_arm64.whl", hash = "sha256:6bdce131e14b04fd34a809b6380dbfd826065c3e2fe8a50dbae659fa0c390546"},
{file = "multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3"},
{file = "multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5"},
{file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"},
{file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"},
{file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"},
{file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"},
{file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"},
{file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"},
{file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"},
{file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"},
{file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"},
{file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"},
{file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"},
{file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"},
{file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"},
{file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"},
{file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"},
{file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"},
{file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"},
{file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"},
{file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"},
{file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"},
{file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"},
{file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"},
{file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"},
{file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"},
{file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"},
{file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"},
{file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"},
{file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"},
{file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"},
{file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"},
{file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"},
{file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"},
{file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"},
{file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"},
{file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"},
{file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"},
{file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"},
{file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"},
{file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"},
{file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"},
{file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"},
{file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"},
{file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"},
{file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"},
{file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"},
{file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"},
{file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"},
{file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"},
{file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"},
{file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"},
{file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"},
{file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"},
{file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"},
{file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"},
{file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"},
{file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"},
{file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"},
{file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"},
{file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"},
{file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"},
{file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"},
{file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"},
{file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"},
{file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"},
{file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"},
{file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"},
{file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"},
{file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"},
{file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"},
{file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"},
{file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"},
{file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"},
{file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"},
{file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"},
{file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"},
{file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"},
{file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"},
{file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"},
{file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"},
{file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"},
{file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"},
{file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"},
{file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"},
{file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"},
{file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"},
{file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"},
{file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"},
{file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"},
{file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"},
{file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"},
{file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"},
{file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"},
{file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"},
{file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"},
{file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"},
{file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"},
{file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"},
{file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"},
{file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"},
{file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"},
{file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"},
{file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"},
{file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"},
{file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"},
{file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"},
{file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"},
{file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"},
{file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"},
{file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"},
{file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"},
{file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"},
{file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"},
{file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"},
{file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"},
{file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"},
{file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"},
{file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"},
{file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"},
{file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"},
{file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"},
{file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"},
{file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"},
{file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"},
{file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"},
{file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"},
{file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"},
{file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"},
{file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"},
{file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"},
{file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"},
{file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"},
{file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"},
{file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"},
{file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"},
{file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"},
{file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"},
{file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"},
{file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"},
{file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"},
{file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"},
{file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"},
{file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"},
{file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"},
{file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"},
{file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"},
{file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"},
]
[package.dependencies]
@@ -908,105 +944,105 @@ files = [
[[package]]
name = "numpy"
version = "2.4.0"
version = "2.4.1"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.11"
groups = ["main"]
markers = "python_version >= \"3.11\""
files = [
{file = "numpy-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:316b2f2584682318539f0bcaca5a496ce9ca78c88066579ebd11fd06f8e4741e"},
{file = "numpy-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2718c1de8504121714234b6f8241d0019450353276c88b9453c9c3d92e101db"},
{file = "numpy-2.4.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:21555da4ec4a0c942520ead42c3b0dc9477441e085c42b0fbdd6a084869a6f6b"},
{file = "numpy-2.4.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:413aa561266a4be2d06cd2b9665e89d9f54c543f418773076a76adcf2af08bc7"},
{file = "numpy-2.4.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0feafc9e03128074689183031181fac0897ff169692d8492066e949041096548"},
{file = "numpy-2.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8fdfed3deaf1928fb7667d96e0567cdf58c2b370ea2ee7e586aa383ec2cb346"},
{file = "numpy-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e06a922a469cae9a57100864caf4f8a97a1026513793969f8ba5b63137a35d25"},
{file = "numpy-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:927ccf5cd17c48f801f4ed43a7e5673a2724bd2171460be3e3894e6e332ef83a"},
{file = "numpy-2.4.0-cp311-cp311-win32.whl", hash = "sha256:882567b7ae57c1b1a0250208cc21a7976d8cbcc49d5a322e607e6f09c9e0bd53"},
{file = "numpy-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:8b986403023c8f3bf8f487c2e6186afda156174d31c175f747d8934dfddf3479"},
{file = "numpy-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:3f3096405acc48887458bbf9f6814d43785ac7ba2a57ea6442b581dedbc60ce6"},
{file = "numpy-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2a8b6bb8369abefb8bd1801b054ad50e02b3275c8614dc6e5b0373c305291037"},
{file = "numpy-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e284ca13d5a8367e43734148622caf0b261b275673823593e3e3634a6490f83"},
{file = "numpy-2.4.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:49ff32b09f5aa0cd30a20c2b39db3e669c845589f2b7fc910365210887e39344"},
{file = "numpy-2.4.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:36cbfb13c152b1c7c184ddac43765db8ad672567e7bafff2cc755a09917ed2e6"},
{file = "numpy-2.4.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35ddc8f4914466e6fc954c76527aa91aa763682a4f6d73249ef20b418fe6effb"},
{file = "numpy-2.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc578891de1db95b2a35001b695451767b580bb45753717498213c5ff3c41d63"},
{file = "numpy-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98e81648e0b36e325ab67e46b5400a7a6d4a22b8a7c8e8bbfe20e7db7906bf95"},
{file = "numpy-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d57b5046c120561ba8fa8e4030fbb8b822f3063910fa901ffadf16e2b7128ad6"},
{file = "numpy-2.4.0-cp312-cp312-win32.whl", hash = "sha256:92190db305a6f48734d3982f2c60fa30d6b5ee9bff10f2887b930d7b40119f4c"},
{file = "numpy-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:680060061adb2d74ce352628cb798cfdec399068aa7f07ba9fb818b2b3305f98"},
{file = "numpy-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:39699233bc72dd482da1415dcb06076e32f60eddc796a796c5fb6c5efce94667"},
{file = "numpy-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a152d86a3ae00ba5f47b3acf3b827509fd0b6cb7d3259665e63dafbad22a75ea"},
{file = "numpy-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:39b19251dec4de8ff8496cd0806cbe27bf0684f765abb1f4809554de93785f2d"},
{file = "numpy-2.4.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:009bd0ea12d3c784b6639a8457537016ce5172109e585338e11334f6a7bb88ee"},
{file = "numpy-2.4.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5fe44e277225fd3dff6882d86d3d447205d43532c3627313d17e754fb3905a0e"},
{file = "numpy-2.4.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f935c4493eda9069851058fa0d9e39dbf6286be690066509305e52912714dbb2"},
{file = "numpy-2.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cfa5f29a695cb7438965e6c3e8d06e0416060cf0d709c1b1c1653a939bf5c2a"},
{file = "numpy-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba0cb30acd3ef11c94dc27fbfba68940652492bc107075e7ffe23057f9425681"},
{file = "numpy-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60e8c196cd82cbbd4f130b5290007e13e6de3eca79f0d4d38014769d96a7c475"},
{file = "numpy-2.4.0-cp313-cp313-win32.whl", hash = "sha256:5f48cb3e88fbc294dc90e215d86fbaf1c852c63dbdb6c3a3e63f45c4b57f7344"},
{file = "numpy-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:a899699294f28f7be8992853c0c60741f16ff199205e2e6cdca155762cbaa59d"},
{file = "numpy-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:9198f447e1dc5647d07c9a6bbe2063cc0132728cc7175b39dbc796da5b54920d"},
{file = "numpy-2.4.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74623f2ab5cc3f7c886add4f735d1031a1d2be4a4ae63c0546cfd74e7a31ddf6"},
{file = "numpy-2.4.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:0804a8e4ab070d1d35496e65ffd3cf8114c136a2b81f61dfab0de4b218aacfd5"},
{file = "numpy-2.4.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:02a2038eb27f9443a8b266a66911e926566b5a6ffd1a689b588f7f35b81e7dc3"},
{file = "numpy-2.4.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1889b3a3f47a7b5bee16bc25a2145bd7cb91897f815ce3499db64c7458b6d91d"},
{file = "numpy-2.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85eef4cb5625c47ee6425c58a3502555e10f45ee973da878ac8248ad58c136f3"},
{file = "numpy-2.4.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6dc8b7e2f4eb184b37655195f421836cfae6f58197b67e3ffc501f1333d993fa"},
{file = "numpy-2.4.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:44aba2f0cafd287871a495fb3163408b0bd25bbce135c6f621534a07f4f7875c"},
{file = "numpy-2.4.0-cp313-cp313t-win32.whl", hash = "sha256:20c115517513831860c573996e395707aa9fb691eb179200125c250e895fcd93"},
{file = "numpy-2.4.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b48e35f4ab6f6a7597c46e301126ceba4c44cd3280e3750f85db48b082624fa4"},
{file = "numpy-2.4.0-cp313-cp313t-win_arm64.whl", hash = "sha256:4d1cfce39e511069b11e67cd0bd78ceff31443b7c9e5c04db73c7a19f572967c"},
{file = "numpy-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c95eb6db2884917d86cde0b4d4cf31adf485c8ec36bf8696dd66fa70de96f36b"},
{file = "numpy-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:65167da969cd1ec3a1df31cb221ca3a19a8aaa25370ecb17d428415e93c1935e"},
{file = "numpy-2.4.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3de19cfecd1465d0dcf8a5b5ea8b3155b42ed0b639dba4b71e323d74f2a3be5e"},
{file = "numpy-2.4.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6c05483c3136ac4c91b4e81903cb53a8707d316f488124d0398499a4f8e8ef51"},
{file = "numpy-2.4.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36667db4d6c1cea79c8930ab72fadfb4060feb4bfe724141cd4bd064d2e5f8ce"},
{file = "numpy-2.4.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9a818668b674047fd88c4cddada7ab8f1c298812783e8328e956b78dc4807f9f"},
{file = "numpy-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1ee32359fb7543b7b7bd0b2f46294db27e29e7bbdf70541e81b190836cd83ded"},
{file = "numpy-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e493962256a38f58283de033d8af176c5c91c084ea30f15834f7545451c42059"},
{file = "numpy-2.4.0-cp314-cp314-win32.whl", hash = "sha256:6bbaebf0d11567fa8926215ae731e1d58e6ec28a8a25235b8a47405d301332db"},
{file = "numpy-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:3d857f55e7fdf7c38ab96c4558c95b97d1c685be6b05c249f5fdafcbd6f9899e"},
{file = "numpy-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:bb50ce5fb202a26fd5404620e7ef820ad1ab3558b444cb0b55beb7ef66cd2d63"},
{file = "numpy-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:355354388cba60f2132df297e2d53053d4063f79077b67b481d21276d61fc4df"},
{file = "numpy-2.4.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:1d8f9fde5f6dc1b6fc34df8162f3b3079365468703fee7f31d4e0cc8c63baed9"},
{file = "numpy-2.4.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e0434aa22c821f44eeb4c650b81c7fbdd8c0122c6c4b5a576a76d5a35625ecd9"},
{file = "numpy-2.4.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40483b2f2d3ba7aad426443767ff5632ec3156ef09742b96913787d13c336471"},
{file = "numpy-2.4.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6a7664ddd9746e20b7325351fe1a8408d0a2bf9c63b5e898290ddc8f09544"},
{file = "numpy-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ecb0019d44f4cdb50b676c5d0cb4b1eae8e15d1ed3d3e6639f986fc92b2ec52c"},
{file = "numpy-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d0ffd9e2e4441c96a9c91ec1783285d80bf835b677853fc2770a89d50c1e48ac"},
{file = "numpy-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:77f0d13fa87036d7553bf81f0e1fe3ce68d14c9976c9851744e4d3e91127e95f"},
{file = "numpy-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b1f5b45829ac1848893f0ddf5cb326110604d6df96cdc255b0bf9edd154104d4"},
{file = "numpy-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:23a3e9d1a6f360267e8fbb38ba5db355a6a7e9be71d7fce7ab3125e88bb646c8"},
{file = "numpy-2.4.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b54c83f1c0c0f1d748dca0af516062b8829d53d1f0c402be24b4257a9c48ada6"},
{file = "numpy-2.4.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:aabb081ca0ec5d39591fc33018cd4b3f96e1a2dd6756282029986d00a785fba4"},
{file = "numpy-2.4.0-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:8eafe7c36c8430b7794edeab3087dec7bf31d634d92f2af9949434b9d1964cba"},
{file = "numpy-2.4.0-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2f585f52b2baf07ff3356158d9268ea095e221371f1074fadea2f42544d58b4d"},
{file = "numpy-2.4.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32ed06d0fe9cae27d8fb5f400c63ccee72370599c75e683a6358dd3a4fb50aaf"},
{file = "numpy-2.4.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:57c540ed8fb1f05cb997c6761cd56db72395b0d6985e90571ff660452ade4f98"},
{file = "numpy-2.4.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a39fb973a726e63223287adc6dafe444ce75af952d711e400f3bf2b36ef55a7b"},
{file = "numpy-2.4.0.tar.gz", hash = "sha256:6e504f7b16118198f138ef31ba24d985b124c2c469fe8467007cf30fd992f934"},
{file = "numpy-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0cce2a669e3c8ba02ee563c7835f92c153cf02edff1ae05e1823f1dde21b16a5"},
{file = "numpy-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:899d2c18024984814ac7e83f8f49d8e8180e2fbe1b2e252f2e7f1d06bea92425"},
{file = "numpy-2.4.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:09aa8a87e45b55a1c2c205d42e2808849ece5c484b2aab11fecabec3841cafba"},
{file = "numpy-2.4.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:edee228f76ee2dab4579fad6f51f6a305de09d444280109e0f75df247ff21501"},
{file = "numpy-2.4.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a92f227dbcdc9e4c3e193add1a189a9909947d4f8504c576f4a732fd0b54240a"},
{file = "numpy-2.4.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:538bf4ec353709c765ff75ae616c34d3c3dca1a68312727e8f2676ea644f8509"},
{file = "numpy-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ac08c63cb7779b85e9d5318e6c3518b424bc1f364ac4cb2c6136f12e5ff2dccc"},
{file = "numpy-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f9c360ecef085e5841c539a9a12b883dff005fbd7ce46722f5e9cef52634d82"},
{file = "numpy-2.4.1-cp311-cp311-win32.whl", hash = "sha256:0f118ce6b972080ba0758c6087c3617b5ba243d806268623dc34216d69099ba0"},
{file = "numpy-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:18e14c4d09d55eef39a6ab5b08406e84bc6869c1e34eef45564804f90b7e0574"},
{file = "numpy-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:6461de5113088b399d655d45c3897fa188766415d0f568f175ab071c8873bd73"},
{file = "numpy-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2"},
{file = "numpy-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8"},
{file = "numpy-2.4.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a"},
{file = "numpy-2.4.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0"},
{file = "numpy-2.4.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c"},
{file = "numpy-2.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02"},
{file = "numpy-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162"},
{file = "numpy-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9"},
{file = "numpy-2.4.1-cp312-cp312-win32.whl", hash = "sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f"},
{file = "numpy-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87"},
{file = "numpy-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8"},
{file = "numpy-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d797454e37570cfd61143b73b8debd623c3c0952959adb817dd310a483d58a1b"},
{file = "numpy-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c55962006156aeef1629b953fd359064aa47e4d82cfc8e67f0918f7da3344f"},
{file = "numpy-2.4.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:71abbea030f2cfc3092a0ff9f8c8fdefdc5e0bf7d9d9c99663538bb0ecdac0b9"},
{file = "numpy-2.4.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5b55aa56165b17aaf15520beb9cbd33c9039810e0d9643dd4379e44294c7303e"},
{file = "numpy-2.4.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0faba4a331195bfa96f93dd9dfaa10b2c7aa8cda3a02b7fd635e588fe821bf5"},
{file = "numpy-2.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e3087f53e2b4428766b54932644d148613c5a595150533ae7f00dab2f319a8"},
{file = "numpy-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:49e792ec351315e16da54b543db06ca8a86985ab682602d90c60ef4ff4db2a9c"},
{file = "numpy-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79e9e06c4c2379db47f3f6fc7a8652e7498251789bf8ff5bd43bf478ef314ca2"},
{file = "numpy-2.4.1-cp313-cp313-win32.whl", hash = "sha256:3d1a100e48cb266090a031397863ff8a30050ceefd798f686ff92c67a486753d"},
{file = "numpy-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:92a0e65272fd60bfa0d9278e0484c2f52fe03b97aedc02b357f33fe752c52ffb"},
{file = "numpy-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:20d4649c773f66cc2fc36f663e091f57c3b7655f936a4c681b4250855d1da8f5"},
{file = "numpy-2.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f93bc6892fe7b0663e5ffa83b61aab510aacffd58c16e012bb9352d489d90cb7"},
{file = "numpy-2.4.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:178de8f87948163d98a4c9ab5bee4ce6519ca918926ec8df195af582de28544d"},
{file = "numpy-2.4.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:98b35775e03ab7f868908b524fc0a84d38932d8daf7b7e1c3c3a1b6c7a2c9f15"},
{file = "numpy-2.4.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941c2a93313d030f219f3a71fd3d91a728b82979a5e8034eb2e60d394a2b83f9"},
{file = "numpy-2.4.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:529050522e983e00a6c1c6b67411083630de8b57f65e853d7b03d9281b8694d2"},
{file = "numpy-2.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2302dc0224c1cbc49bb94f7064f3f923a971bfae45c33870dcbff63a2a550505"},
{file = "numpy-2.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9171a42fcad32dcf3fa86f0a4faa5e9f8facefdb276f54b8b390d90447cff4e2"},
{file = "numpy-2.4.1-cp313-cp313t-win32.whl", hash = "sha256:382ad67d99ef49024f11d1ce5dcb5ad8432446e4246a4b014418ba3a1175a1f4"},
{file = "numpy-2.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:62fea415f83ad8fdb6c20840578e5fbaf5ddd65e0ec6c3c47eda0f69da172510"},
{file = "numpy-2.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a7870e8c5fc11aef57d6fea4b4085e537a3a60ad2cdd14322ed531fdca68d261"},
{file = "numpy-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3869ea1ee1a1edc16c29bbe3a2f2a4e515cc3a44d43903ad41e0cacdbaf733dc"},
{file = "numpy-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e867df947d427cdd7a60e3e271729090b0f0df80f5f10ab7dd436f40811699c3"},
{file = "numpy-2.4.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e3bd2cb07841166420d2fa7146c96ce00cb3410664cbc1a6be028e456c4ee220"},
{file = "numpy-2.4.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:f0a90aba7d521e6954670550e561a4cb925713bd944445dbe9e729b71f6cabee"},
{file = "numpy-2.4.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d558123217a83b2d1ba316b986e9248a1ed1971ad495963d555ccd75dcb1556"},
{file = "numpy-2.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f44de05659b67d20499cbc96d49f2650769afcb398b79b324bb6e297bfe3844"},
{file = "numpy-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:69e7419c9012c4aaf695109564e3387f1259f001b4326dfa55907b098af082d3"},
{file = "numpy-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd257026eb1b34352e749d7cc1678b5eeec3e329ad8c9965a797e08ccba205"},
{file = "numpy-2.4.1-cp314-cp314-win32.whl", hash = "sha256:727c6c3275ddefa0dc078524a85e064c057b4f4e71ca5ca29a19163c607be745"},
{file = "numpy-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:7d5d7999df434a038d75a748275cd6c0094b0ecdb0837342b332a82defc4dc4d"},
{file = "numpy-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:ce9ce141a505053b3c7bce3216071f3bf5c182b8b28930f14cd24d43932cd2df"},
{file = "numpy-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e53170557d37ae404bf8d542ca5b7c629d6efa1117dac6a83e394142ea0a43f"},
{file = "numpy-2.4.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:a73044b752f5d34d4232f25f18160a1cc418ea4507f5f11e299d8ac36875f8a0"},
{file = "numpy-2.4.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:fb1461c99de4d040666ca0444057b06541e5642f800b71c56e6ea92d6a853a0c"},
{file = "numpy-2.4.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423797bdab2eeefbe608d7c1ec7b2b4fd3c58d51460f1ee26c7500a1d9c9ee93"},
{file = "numpy-2.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52b5f61bdb323b566b528899cc7db2ba5d1015bda7ea811a8bcf3c89c331fa42"},
{file = "numpy-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42d7dd5fa36d16d52a84f821eb96031836fd405ee6955dd732f2023724d0aa01"},
{file = "numpy-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7b6b5e28bbd47b7532698e5db2fe1db693d84b58c254e4389d99a27bb9b8f6b"},
{file = "numpy-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:5de60946f14ebe15e713a6f22850c2372fa72f4ff9a432ab44aa90edcadaa65a"},
{file = "numpy-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8f085da926c0d491ffff3096f91078cc97ea67e7e6b65e490bc8dcda65663be2"},
{file = "numpy-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6436cffb4f2bf26c974344439439c95e152c9a527013f26b3577be6c2ca64295"},
{file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8ad35f20be147a204e28b6a0575fbf3540c5e5f802634d4258d55b1ff5facce1"},
{file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8097529164c0f3e32bb89412a0905d9100bf434d9692d9fc275e18dcf53c9344"},
{file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:ea66d2b41ca4a1630aae5507ee0a71647d3124d1741980138aa8f28f44dac36e"},
{file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d3f8f0df9f4b8be57b3bf74a1d087fec68f927a2fab68231fdb442bf2c12e426"},
{file = "numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2023ef86243690c2791fd6353e5b4848eedaa88ca8a2d129f462049f6d484696"},
{file = "numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8361ea4220d763e54cff2fbe7d8c93526b744f7cd9ddab47afeff7e14e8503be"},
{file = "numpy-2.4.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4f1b68ff47680c2925f8063402a693ede215f0257f02596b1318ecdfb1d79e33"},
{file = "numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690"},
]
[[package]]
name = "openbb-core"
version = "1.5.8"
version = "1.5.9"
description = "OpenBB package with core functionality."
optional = false
python-versions = "<3.14,>=3.10"
groups = ["main"]
files = [
{file = "openbb_core-1.5.8-py3-none-any.whl", hash = "sha256:d82663d28102f7dd8d0b5bf6e0ee770af04e3c4bd8dc6d06eb39d15be2ca12ce"},
{file = "openbb_core-1.5.8.tar.gz", hash = "sha256:e5be811aeb0acd03902ba0850d4bfac5a8feb3bc5fd4f36c6ed088dcd3056d2e"},
{file = "openbb_core-1.5.9-py3-none-any.whl", hash = "sha256:de1caece63a0ebbe7bcd1109b6308404ca8f606b855b49d24d42eee4aec7f87f"},
{file = "openbb_core-1.5.9.tar.gz", hash = "sha256:a5fdde0269cdbf4eb6e56f1bc5d6e22847a8270d0c8aad42d928b03702cedbbf"},
]
[package.dependencies]
aiohttp = ">=3.13.2,<4.0.0"
aiohttp = ">=3.13.3"
fastapi = ">=0.128.0,<0.129.0"
html5lib = ">=1.1,<2.0"
importlib-metadata = ">=6.8.0"
pandas = ">=1.5.3"
pandas = ">=1.5.3,<3"
pydantic = ">=2.12.3,<3.0.0"
pyjwt = ">=2.10.1,<3.0.0"
python-dotenv = ">=1.0.0,<2.0.0"
@@ -1017,6 +1053,86 @@ uuid7 = ">=0.1.0,<0.2.0"
uvicorn = ">=0.40.0,<0.41.0"
websockets = ">=15.0,<16.0"
[[package]]
name = "openbb-economy"
version = "1.5.1"
description = "Economy extension for OpenBB"
optional = false
python-versions = "<3.14,>=3.10"
groups = ["main"]
files = [
{file = "openbb_economy-1.5.1-py3-none-any.whl", hash = "sha256:786b9e9b43f7aad5a589601bdc22e0f151c585c85c9f69bf343de0f5c47bd379"},
{file = "openbb_economy-1.5.1.tar.gz", hash = "sha256:3a9060f25bdacba5a3e4df82a16dd37f9137d715137317b65b72f6d8460aca9e"},
]
[package.dependencies]
openbb-core = ">=1.5.7,<2.0.0"
[[package]]
name = "openbb-fixedincome"
version = "1.5.1"
description = "Fixed income extension for OpenBB"
optional = false
python-versions = "<3.14,>=3.10"
groups = ["main"]
files = [
{file = "openbb_fixedincome-1.5.1-py3-none-any.whl", hash = "sha256:6dc3f2457ac9ab06847c428e799d04ee8fdf2d60ffda2a02ccc651f952724a77"},
{file = "openbb_fixedincome-1.5.1.tar.gz", hash = "sha256:904e91959525fc585d2578cf3bf6c700e08310d1388bede349d09451f88bb0e4"},
]
[package.dependencies]
openbb-core = ">=1.5.7,<2.0.0"
[[package]]
name = "openbb-platform-api"
version = "1.2.3"
description = "OpenBB Platform API: Launch script and widgets builder for the Open Data Platform REST API and Workspace Backend Connector."
optional = false
python-versions = "<3.14,>=3.10"
groups = ["main"]
files = [
{file = "openbb_platform_api-1.2.3-py3-none-any.whl", hash = "sha256:201d6fcc21f841a61b9170df9beac585bf4f57a4d59d094b16afc8c628cec191"},
{file = "openbb_platform_api-1.2.3.tar.gz", hash = "sha256:9d0997de865eb85f6c4a78d6fa87d3bb0037fb52d61c580d1e8d5443b175c2a8"},
]
[package.dependencies]
deepdiff = ">=8.6.1"
openbb-core = ">=1.5.7,<2.0.0"
[[package]]
name = "openpyxl"
version = "3.1.5"
description = "A Python library to read/write Excel 2010 xlsx/xlsm files"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"},
{file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"},
]
[package.dependencies]
et-xmlfile = "*"
[[package]]
name = "orderly-set"
version = "5.5.0"
description = "Orderly set"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "orderly_set-5.5.0-py3-none-any.whl", hash = "sha256:46f0b801948e98f427b412fcabb831677194c05c3b699b80de260374baa0b1e7"},
{file = "orderly_set-5.5.0.tar.gz", hash = "sha256:e87185c8e4d8afa64e7f8160ee2c542a475b738bc891dc3f58102e654125e6ce"},
]
[package.extras]
coverage = ["coverage (>=7.6.0,<7.7.0)"]
dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)"]
optimize = ["orjson"]
static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)"]
test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"]
[[package]]
name = "pandas"
version = "2.3.3"
@@ -1542,14 +1658,14 @@ files = [
[[package]]
name = "soupsieve"
version = "2.8.1"
version = "2.8.3"
description = "A modern CSS selector implementation for Beautiful Soup."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434"},
{file = "soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350"},
{file = "soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95"},
{file = "soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349"},
]
[[package]]
@@ -1919,4 +2035,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<3.14"
content-hash = "0c6fd58e25ed2b3c2a3e56ee27de54350695643c072ff80e79febbee6f602a52"
content-hash = "bf5ee239f10aa6e2cc346f0550cdaa6a10ea7fb39aff344782c9bc519ac90492"

View File

@@ -9,7 +9,11 @@ packages = [{ include = "openbb_federal_reserve" }]
[tool.poetry.dependencies]
python = ">=3.10,<3.14"
openbb-core = "^1.5.8"
openpyxl = "^3.1.5"
openbb-core = "^1.5.9"
openbb-economy = "^1.5.1"
openbb-fixedincome = "^1.5.1"
openbb-platform-api = "^1.2.3"
beautifulsoup4 = "^4.13.4"
[build-system]
@@ -18,3 +22,6 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry.plugins."openbb_provider_extension"]
federal_reserve = "openbb_federal_reserve:federal_reserve_provider"
[tool.poetry.plugins."openbb_core_extension"]
federal_reserve = "openbb_federal_reserve.router:router"

View File

@@ -0,0 +1,272 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate, br
Connection:
- keep-alive
method: GET
uri: https://www.philadelphiafed.org/-/media/FRBP/Assets/Surveys-And-Data/survey-of-professional-forecasters/historical-data/Inflation.xlsx
response:
body:
string: !!binary |
UEsDBBQAAAgIAEC7bFsv+0ThdQEAAN0FAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbK2UXU+DMBSG
7038D01vDXTzwhgD7sKPS13i/AGVHqCOfqTtJvv3HjqzmGUCbruh0NP3ed9COdmsVQ1Zg/PS6JxO
0wkloAsjpK5y+r54Tm4p8YFrwRujIacb8HR2f3mRLTYWPEG19jmtQ7B3jPmiBsV9aixorJTGKR7w
0VXM8mLJK2DXk8kNK4wOoEMSOgZFGiEke8UUTgogc+7CC1doxtqGfRm39DVA8CwO0xTJlDxsEV2K
nHJrG1nwgHtgay32/BNTlrIAYYqVQknqrQMuIkw16Y5/1XHZcJgPY5ZnzhDHVHGpx4TwYdOAP3eE
CB1lX3MH4i04PCJnT/GbPSZMwAMH2+vpByNiBl1x+dwZ6xnCT7aEFpUCRGIRCS7IEd9gF6AwDv6f
4OdPTDv1X7aPUPJVE8hTF2/bGhw0/jgjVMY1vpZ20KZ/OwNiUOWeWKqu6bRJV+kRflqoDipjoUdo
9WFdN9/rd5ydXx/W4fzuxWYstma8+wZQSwMEFAAACAgAQLtsW1kcMj0QGwAAGNgAABgAAAB4bC93
b3Jrc2hlZXRzL3NoZWV0MS54bWyVnVtz20iWhN83Yv8DQ+8joe5VDtsTbRMdMxE9uxPjnp1nWqJs
RkuigqTb7f71C1JX5DmFSvRLW3QaZKoA8GPiIPn2r3/c3ix+X+/2m+3duzNz3p0t1neX26vN3Zd3
Z//+9ee/5LPF/rC6u1rdbO/W785+rPdnf33/3//19vt299v+63p9WAxbuNu/O/t6ONy/ubjYX35d
367259v79d3wN9fb3e3qMPy4+3Kxv9+tV1enf3R7c2G7Ll7crjZ3Zw9beLNjtrG9vt5crpfby2+3
67vDw0Z265vVYXj9+6+b+/3T1m4vmc3drna/fbv/y+X29n7YxOfNzebw47TRs8Xt5Zu/f7nb7laf
bwbffxi/unza9ukHsfnbzeVuu99eH86HzT2+UOm5XJSLYUvDr3CxeHt6/J+7xfXm5rDe/WN7NTzT
aQWOT/rz6XV+3N5dbU7uPq5uLr89OD2qTlsYtnG/+rL+tD78+/60ncOv238ODxwFFw/PcfH4JA8/
XW2G39txsRe79fW7s5/Mm97a8KQ9Sf9vs/6+f9r68yOLP7fb20+Xq+Mvw3TDi3z++X+Or/MGHz2+
il9WP7bfTv/68W+PO83n7fa340N/v3rl4uTjbr3449P9sASnX8KPxz+as8Vhe//L+vrwcX0zPM1P
9myxujxsfh+e4rhHft4eDtvbf22+fD2cdtXD8Nj1bvvn+u7R1fPv4Pisr38nL0YfbD78wodf4+fV
fv1xe/OfzdXh6/GVny2u1terbzeHf22//219fKbhUXe2uPy2H576+ZFh9zjuGG+ufizX+8th93y1
Cpfbm+ff6fDnxe3m7vQvbld/nP7//fG5zHkcNvx5vT/8/Gj+4UmeXsuLp+et2Met2Jet2PlbcY9b
cS9bifO34h+34l+24uZvJTxuJbxsJXBbeXvx/It+WNPl6rA6nq522++L3enfnZYqycU7qi6Pmp8G
0f5hv3t3tj97//b3993bi9/fD9t+1nyQGoOajw8a+0pjUbOUGoeaXmr8K83FYO2VQ/voMEw5tKct
Dr/Q0wsvqTvvhv+EybFM1Xx80PhXLy4Ik4Smn9aASceYdJzJkczqJt3Ti3vQlBzEai8dYXJaAyY9
Y9JzJkcyp5v0r02689S5JEx6wuS0BkwGxmTgTI5kXjcZxiaDN16YDITJaQ2YjIzJCCb14+1DJI7J
CCZdJ04qy0iYnNaAycSYTJzJRByTaWzSmyhXMhEmpzVgMjMmM2cyE8dkHps0LhRhMhMmpzVgsjAm
C2eyEMdkwZUsciULYXJaAyaPVNd2eVSNbOo74wfQ6T4fRa+Oy6IAQUc4bYjQqqGsGtKqIQ7OR9Gz
VZdDllYNY3VahFYp/DHIPzWrljhEjR1bjcYqVhkEaojQKgVBBimoZtURB6pxYLUUeToyDAg1RGiV
QiGDLKQv2AfQVawiDcVOscrgUEOEVikgMkhENauBOVaBiVKyEhcMA0UNEVqlsMggF9WsRuZYHZHR
sJerOzCDRg0RWqXgyCAd1awm5lgd8VE4d1H5zGIYQGqI0CqFSAYZSXfxAXQVq3lsNQarvK8ymNQQ
oVUKlAySUs1qYY7VAlaNjdIqA0sNEaYKFC1ZpKWK1bGucqxaAoSWjKhviNAqRUsWaalm1RDHqh3R
UjqPWflUahlaaojQKhcWIS2FilUqLrJjq9YbeaxaKjCaRUuWoiWLtFSzyoRG1o2P1VCMDFQsQ0sN
EVqlaMkiLdWsMtGR9WOrxQdlB2ZoqSFCqxQtWaSlmlUmQLIjWorntsvKqjK01BChVYqWLNJSrFhl
YiQbx1ZNdsqxytBSQ4RWKVqySEs1q0yYZIGWStcpVhlaaojQKkVLFmmpZpWJlGwer2oXghAtLUNL
DRFapWjJIi3VrDLBkgVaSrYoVhlaaojw8gRFSw5pKVUuUDDZkuvGVqP30qpjaKkhQqsULTmkpZpV
JltyBs7AMcnAxTG01BChVYqWHNJSzSqTLTk7XtVcsvy86hhaaojQKneBDWmpZpXJlhzQUglBvq86
hpYaIrRK0ZJDWsoVq0y25JCWOi9p6UU0ZXUWLTmKlhzSUs0qky05oKXgrLKqDC01RGiVoiWHtFSz
ymRLDmipDG+s0ipDSw0RWqVoySEt1awy2ZIb0dJw1BdtVRlaaojQKkVLDmmpVKwy2ZLLY6vORgmG
jqGlhgitUrTkkJZqVplsyZWx1WFRlfdVhpYaIpxzoGjJIy1VrHomW/IjWhoOBauEo56hpYYIrVK0
5JGWalaZbMmbsVWTk2KVoaWGCK1StOSBlnJtfoXJlrwdW41FQQjP0FJDhFYpWvKOtMpkS96NrWZv
ZA7sGVpqiNAqRUvek1aZbMn7sdXilE82L6Ipq7NoyVO05ANplcmW/IiWyrlLViKEZ2ipIUKrFC15
oKVcGfnwTLbk49hqF438ZOMZWmqI0CpFSz6RVplsySc4LSUlMfQMLTVEaJWiJZ9Jq0y25IGWcmeV
VUWR9ULU+1m05Cla8oW0ymRLHmgpmCxpCUWxFCHq/SxaChQtBaClXBn7CEy2FLqxi25AEmF1LIrn
0XppNcyipUDRUjCkVSZbCpgtOYWBUdS5JD6/92EWLQWKlgLSUs0qky0FzJaSk8cqikpSjtUwi5YC
RUsBaalmlcmWAl6Jy/IwXKLIFzmG2IdZtBQoWgpIS5WxD9BVrEK21HXK9dWxyJ8H65UJ51m0FLhB
bqSlmlUmWwph7CJbZWAdRUk9Lc2ipUDRUkBaqlllsqUAc0vFKyOyKAouKas6i5YCRUsBaalmlcmW
AlyJUxNDFBmvvK+GWbQUKFoKSEuVsY/AZEshw6om+T6yRFE2Vnx+78MsWgoULQWkpZpVJlsKcCXO
Ze20BCJbJGf0YRYtRYqWItJSxWpksqXYwRnHR/l5FUXaAd3HWbQUKVqKSEs1q0y2FM3YhTdOZktC
ZL1c1TiLliJFSxFpqTL2EZlsKcKUdylOWVU7tmqsF3t5H2fRUqRoKSIt1awy2VJ0YxdOu2ouRF45
VuMsWooULUWkpZpVJluKAELWKBMuQqRanUVLkaKliLRUs8pkSxGmvAeSl282KMqq1Xn3vnE3vyEt
VcY+IpMtRbj/zQ3/Sat4k5ySi/dxFi1FipYi0lLNKpMtRbgLzgwoL62KW+Xkm28fZ9FSpGgpIi3V
rDLZUhyBkD2PRrm+Oha544c4+Xk1zqKlSNFSRFqqWWWypQh3xBljFKsgUgOXOIuWEkVLCWmpMvaR
mGwpwT1x6l3HKMoaGKZZtJQoWkpISzWrTLaU4J64YrJ8s0lASy7KSwB9mkVLiaKlhLRUs8pkSwlB
yFuJEChSj9U0i5YSRUsJaalmlcmWkoPD0BR5rCakJS1GS7NoKVG0lJCWKmMfoKtY9XCsRqOsKtCS
UY/VWbSUKFpKSEs1q0y2lJCWvFNWFbKloK7qLFpKFC0lpKWaVSZbShAbmexkOIqikuTQcJ9m0VLi
CgOQlmpWmWwpJTy5KuOUKCrKlvo0i5YSRUsJaaky9pGYbClBbBSCVo+A2ZLXzsCzaClRtJSQlmpW
mWwpFTwMk4IQICpG3uTap1m0lClaykhLFauZyZYyxEbOdvK0hKIYlB04z6KlTNFSRlqqWWWypYy0
lJXPqxloyVrltJRn0VKmaCkDLZXK2EdmsqUMINRZ5UYxFDntWM2zaClTtJQdaZXJljLQUjZRvtlk
oCWjXTXPs2gpU7SUPWmVyZYygJDLytwSiryWA7+IKKsULeVAWmWypQwgZKMEoSWKgpE3ufZ5Fi1l
ipYy0FKp9fEw2VKG2GhYL+W0BKIYZSrT51m0lClayom0ymRLGWIjl5VsCUVZu+iYZ9FS5kqWMmmV
qlmC2MgFpcMFRSlpqzqLljJFS7mQVplsKWO2pF3IQFFQ32wAqeDpsFSKoqUCtFQqYx+FyZYKxEZW
uUq8RJHTUggUpWmrFC0VQ1plsqUCtGQ65VIyioI2eIeiMm2VoqWCtFSzymRLZQRC9jwVpZmnwOU6
p4EhilKYtErRUkFaqlllsqXiwGoX5ZR3cWIvV1YVU6rpVaVoqSAtVcY+QFex6sFqVm7AHosGq0YJ
R1EUpq1StFSQlmpWmWypBLAalG60scjpiSGKGqclipYK0lLNKpMtFQChTmvmQZHTAhcU+eljlaKl
grRUs8pkSyWNVzU75VJyAVrqnGYVL9dNW6VoqSAtVcY+CpMtFbgSl6Iy9lGAlqy6qni5btoqV0yJ
tFSzymRLpcCqFoWBC9CS1cJRFE2flk5t6W2vJxljFoS1erSuw+NVSSKESn1zFaqWYa6kskNqqhpm
QqYn1StuUm5YECqvG0a8ahjmqio7ZKfKEAgKa4at2KE1w0BGXnujFSrXMEwB1EnGGWYCpyfVs+Hi
lBt4QXVEY3WFQeUmT1emozDqJOMMM7HTk+rZcIhKHA6qyjlLqhorTMHUScYZZsKnJ9Wz4WFVZCgu
VEVLxUElfsXCMFdh2SFTVYZDUFgzHMFw1Ao7UZX0FUZCaxjmiiw7JKuqYSaIelK97NKdahgJTENm
ULUNc3WWHfJV1TATRz2pXhlWOppAddyWepYWqmnDXKllh5RVNcyEUk+qVyct1TAwVKefpVE1bZgs
Ascm8FIZGkFhxfC4C3wwnJRhIION4Z02DSRVDcNkHTiSVtUwVwhuxoa9VXJHoSpaGidUefp9mCwF
x1bwumGqFtwAaXmtZ02o1EvwBjvGWyvMkRZ2g9cNM2GVMUBatijX9oQqKtvqpaqxwhxpYUN4qQyT
oLBmGEjLOmVyRqq0i0FCNR3QGbImHHvC64aZ4OpJ9fwiO5+V92FUeX2XBlXj0xJZFo5t4XXDVF24
AYbqnLxRcilUXiUtVLUMc6SFneF1w1Rp+Lg13AxnVqWBAlQDgBp1lxbUNm2YIy1sDi+VIRMU1gzn
seHgvVKobYDHjIqWqGp8Hibrw7E/vG6YKhAfN4ib8+S1T0sGeExN74SqscJcibjBFvGqYapG3NgO
dukor1AvQTWsnVLS0QtVyzBHWtglXjdMZVrjNvHBsNFIywJD6YmHUDUMk1+/MgKo475VM0xlWuNO
cXNecla+6sAij6ksjaqWYY60oC98wjCVaVkkLaOhJapiJ5OvXqhahjnSGreGTxmmMi3r8ej0Cnig
KqmpJapahjnSGneHTxmmMi0LdGSDcleBUEUVPFDVMsyR1rhBfDBcGUoxVNW4sUBHw5lH+xYlJK2s
TBsJVcswR1rQIz5hmMq0LNBRF4sCHqgK+i49j7S40nEzbhOfMkxlWhboqMtFO0vjXX4qeKCqZZgj
rXGn+JRhKtOySFpOC+ItMJRaZSFUYfrzMFdAbsbN4oPh6peDUZmWA9JK2vcFgMoep3sVlkZVY4W5
GnID/eIThqlMywFpFauBhwOGUie3haplmCMth6RVNUxlWg5IKxennLQcMJTNSj+WULUMc6TlkLSq
hqlMa9xKflzhoICHA4Yy6tsSqqaHHQxXTG7GjeOD4dqXhlHV5GbcTT6ssNe+926sOr5ba+CBqtYK
c6TlkLSqhqlMa9xQPpy0kryNegkqe2y8Vr6nG1UtwxxpOSStqmEq0xr3lA+GrfYVYqjKWmsLqNqG
OdJySFpVw1Sm5SDTSkH7JjyXqF16HmlxheXGIWnVhlqoynLjMNOKWVthUEWrnqXnkRZXW24cklbV
MJVpOSCt7JSBNFANK+zkR4xeqBqGufJy45G0aoap+nLjkaG0+xWESh2sFKqWYY60PJJW1TCVaXkk
raJ9dbIHhrJRJl+9ULUMc6TlkbRqQy1UlbnxmGklLbX0SFrqUAuqGuDB1Zkbj6RVNUxlWh7oyDqj
kBaqnJp4oKq1whxpjdvKpwxTmZYHOrI+aLs0qLxLSoiHqpZhjrQ8klbVMJVpeaCjgZKVtyVUOeX+
pF6oWoY50vJIWrWhFqri3HjMtIpR3pZQ5a2M+nqhahnmSMsjaVUNU5mWT3j+7bQVxquHOWqG55EW
V3ZuPJJW1TCVaXm84leUFnuhilZeNu+FqmWYIy2PpFU1TGVaHq8LRuWWOqGKJmvH8DzS4orPTUDS
qg21UNXnJiBpOaW4VKh8iMoKo6oxPszVn5uApFU1TGVaARmqaF+mjSrvvGzPk6rGCnOkFZC0qoap
TCsgQ8WkgIdQ2ayctFDVMsyRVkDSqhqmMq2ApOW1GQ9Uea/NeAhVwzBHWuOm88FwbaiFqkQ3waNh
bYoHVS7Lc3kvVK2TFkdaAUmrapjKtIJgKO02HlTFKHORXqhahjnSCkhaVcNUphUiHp3apRZUBWUE
tZeqhmGOtAKSVtUwlWkFyLSK19ASVSnIKuoeVG3DHGkFJK3aUAtVlW4CpFU2aEMtqApK1NeDqn3S
4kgrIGlVDVOZVoBMy0el8l+oUhe1k9Y80uJK001E0qoZpmrTTYSrhz5oHw9RlTuJJz2o2oY50opI
WlXDVKYVIdPyWfkON6GKTt6w14PqNGScpgxzpBWBtExtqIWqUDcRMq3gtLclVKWsfVqKQFquTK8w
R1rQjz5hmMq0xiXpw9ppd/oLVVaivh5UzZMWV6Zuxi3pU4apTGtclW6ON2ppuzSokpXXGHtQNadp
uUp1EwNrmMq0xoXpg2GrFN0KVexko34PKjFzKwxzpBWBtExtqIWqVjcx4gprMx6oSurVwxjnrTBH
WtCbPmGYyrQiMlTSwCPi1UPXKZ+WUNU6hjnSipk1TGVaERgqK9MbS4Nt7J06mIaqlmGOtGJhDVOZ
VgSGKk6pnpGqKK9A9aBqggdXuG4SkJapDbVQlesm4ZyWehtPAobq1EstqGocw1ztuoE+9QnDVKaV
8Oqh09AyAUOZLK8i90Ll87RhjrQSklbVMJVpJZzTCsqXU4JqMNxpo4eoaqSWXAW7SUhaVcNUppWA
oUrR3pYSMJQp6grjNcbGLs2R1rhhfTBcG2qhqtjNuGb9OJgmE+clqI4rrF0fRlXLMEdaCUmrapjK
tBIwVI5ZeVtKwFCdV0pGhaplmCOthKRVNUxlWgknsLQv15KqKIm7B9URLcOkYY60EpJW1TCVaSUg
rdxF5eMhqopSq9uDqr3CHGklJK3aUAtV0W4SkpbThlqESrm7qQdV2zBHWglJq2qYyrQSzmklbRIP
VSVoAUDCK5HTb0tcWbvJSFo1w1Rdu8lAWiUq3wUIquNwqfbxEFWNj4dcZbvJSFpVw1SmlQ2ejoJy
lkZVMdqdaRkzrYZhjrQyklZtqIWqbjcZ06rUKSctVOUimwJ6UIl3a2GYI62MpFU1TGVaGUgrG6UA
W6hK0kgrI4+5ybclrsTdjNvZpwxTmda4on1Y4RiUDw9j1RE8tFwaVaZx0uJIKyNpVQ1TmVZG0gpa
iJcFaclvyOmFqmWYI62MpFUbaqEq3U1Ghurktf2lUA3goaSWGWe+7LRhjrQyklbVMJVpZSQtdUA8
A0N1QRsQR1XrLM2RVkbSqhqmMq0sGEojrQwMZa2MCXqhau3SHGllJK2qYSrTyshQXsu0MjKU0n7Z
S5WJZsIwV/RuCpJWbaiFqno3Bee0lC60pVC5IG+67aVqepfm6t5NQdKqGqYyrQJ01BlthVGl1zyi
qmWYI62CpFU1TGVaBSfivRbxYDv88ElX+fAgVNPHMFf9bgqSVtUwlWkVZKgipyiXBjviuyIBtBeq
xlmaK4A342b3wXBtqIWqgDfYAd85ORi8FCpr5FXkXqoaK8yRVkHSqhqmMi1sgjedNsWDKhuUb1QU
qtYxzJFWQdKqGqYyrSLmtJQvCpKqIL+mr5eqhmGOtAqSVtUwlWlhK7w1WuKBqmG/Vz4eym1NG+ZI
qyBp1YZaqGp4g93wptM68VBl1dFDoWqsMEdaBUmrapjKtLAhvlNjWqHK8sure6GaNmy5jnjbIWlV
DFuqI952mGkpTVlLUJ3O5fIYFqqWYYq0bIekVTXMZFq2w7RKa0wD1THLkNcneqFqGaZIy3ZAWrYy
1GKpjnjbIWlZpcjTYpO8CbLBtheqlmGKtCxUv08YZjIt2wFpOSWtWgpVDkpMa7FvfjrTslxHvB1X
v08ZZjItO+51N+fBKBfEhSpFBTws9s3Dd5oIwxRp2S6whplMy3aYaSVlTstiR3wXk7bCSG2TEY/l
OuJtB6RlK0MtluqItx2mVcHJ68MWO+JNkO2XvVC1jmGKtCxUv08YZjIti+3vrlPqpaQqKjdbKtua
NkyRlu0ya5jJtCx2xNug3JkmVC4rAYBQeRcnxoct1xFvu8IaZjItKzriU6e9LYl7D9VdelafluU6
4q0B0rKVoRZLdcRb7IjPnXIxTaiKsh/0QuVLngjxLNcRb6H6fcIwk2nZca/78euxlLEloYqdMuNh
RUf89DHMdcRbg6RVNcxkWlb0ums9HkIVlBHU3oom+YZhjrQMklbVMJNpWex1L1E7aY1Vp29SkiGe
3FbjGOZIa1z9PhiuDLVYqiPeil73Iq0shaoE5RYAoXJp2jBHWgZJq2qYybSeVC9nVqdEPEKVx9cU
ngxjphXCxJfpWq4j3hokraphJtOystddufdQqKJS99kL1fS8tOU64q1B0qoaZjIti73uNspZ96VQ
haTcAiBULcMcaRkkrcpQi6U64q1of++U23iEymVZftELlfXThjnSMkhaVcNMpmWx191oX3IuVEG7
91Co4MsC0TDXEW8tklbNMNURb7HX3XinnLRQ5TujvA+LJvnpXZrriLcWSatqmMq0sNfdKuffpVC5
Thk9lNtqrDBHWtgRbytDLZbqiLei191rEQ+qhpO0wtKoaq0wR1rYEV83TGVa2OuejZZ4WCCtzquG
YVvDW7qdMsyRFnbE1w1TmZboiPdJW2HksSib5Hu5rcl5act1xFvsiK8bpjIt7HX3Sft4iKqkTdMK
lZu8q8U+d8Q7afhiEC4Wby/2X9frw3J1WD38fL/b3B3+9/6w2d7tF1/Xq6vN3ZfhGY+n++1u8+f2
7rC6+bi+O6x366vTw7+vd4fNJTz4Zbe5+mVztz79y8dnul99Wf9jtfuyGTZ8s74eXkR3PtjZPbyg
058P2/vHP33eHoZX+/jD8WWsd6cNX2+3h4c/vtrqp/Xh2/3ifnW/3n3a/Lk+ultcbw6/bv+zuTp8
ffnxxfxiP7zio/B4ZWPwNbz21dHyu7P77e6wW20Or/0u7zfDKnevzD4/8vgqHl7hz6cXd3pkeGx7
dfW308Pvf/26Xnz66dPi04/9YX379uLlb16kj//29JevtvP2Ajb99uL7dvfbadGGn/4fUEsDBBQA
AAgIAEC7bFv5kiWifAAAAJAAAAAjAAAAeGwvd29ya3NoZWV0cy9fcmVscy9zaGVldDEueG1sLnJl
bHNNzDEOAiEQheHexDuQ6V3QwhizuJ0HMHqACTsCEQbCEKO3l9Ly5c/75uWTk3pTk1jYwn4yoIhd
WSN7C4/7dXcCJR15xVSYLHxJYLlsN/ONEvZxkhCrqKGwWAi917PW4gJllKlU4lGepWXsYzavK7oX
etIHY466/RugB/sDUEsDBBQAAAgIAEC7bFts33E4PwEAACICAAAPAAAAeGwvd29ya2Jvb2sueG1s
jVFBTsMwELwj8QfLd+q0CARVQlUKlSKh0kPp3TibxqrtjWyHlN+zSQhqb5zsmfXOzqzTxcka9gU+
aHQZn04SzsApLLQ7ZPxjt7554CxE6Qpp0EHGvyHwxdP1VdqiP34iHhkJuJDxKsZ6LkRQFVgZJliD
o0qJ3spI0B9EqD3IIlQA0RoxS5J7YaV2fFCY+/9oYFlqBS+oGgsuDiIejIxkP1S6Dpy8MZaW2sB+
SMVkXW+kJe8nw5mRIb4WOkKR8TuC2MIF4Zv6udGGwONtMuNMDHpj2q1nocI2d8elcxj7uRmnpckm
4gotRQxhq1Vs6NIVfvu73r2GNvTwTLAjxyHi8lXar+qvo0fM9UnyzfptucvfN/Q5HZ2T3ymZn2u6
+LyYjnPFmUaqpFEUoDu6BnKt0KnGe1rlisjRbypGdwR+AFBLAwQUAAAICABAu2xbcrc9wFkCAACM
CAAADQAAAHhsL3N0eWxlcy54bWzVVltr2zAUfi/sPwj1dY3tkJQlxC1rwdCHlUFT2Ktsy46oLkaW
g91fvyNLttNkG6FssOZF5/qd7yjnKNnctoKjPdU1UzLG0SzEiMpM5UyWMX7eJldfMKoNkTnhStIY
d7TGtzcXm9p0nD7tKDUIEGQd450x1ToI6mxHBalnqqISPIXSghhQdRnUlaYkr22S4ME8DK8DQZjE
DmEtsnNABNEvTXWVKVERw1LGmel6LIxEtn4opdIk5cC0jRYkG7B75QResEyrWhVmBnCBKgqW0VOW
q2AVABI0LRuRCFOjTDXSxHgONoS8FbnjIYdbvF5g5DjfqxyoXF6GOPhd7PIo9jNEz8I+YRP4iiAW
Sp5UtjYrgFi/oj3hgOcrgSlTXGmkyzTGSRL2n9EniaAu4WF7j+6UehFEeo7BAHuInwbHhaK/Vcid
fY+M85Meweax4As3VMsELMjL266CO5MwmiOmjz8rsdSki+bLt7nutHxSpXNYjYFR5Bg5q4fmtDBD
r5qVu1ExqhrEVBkD8+W1nJFSScJ9zQFtkGzdjHL+ZBfsR3FcvC0Ohie0oyNHEVh70UE5pZ+jQ0Rf
4AB7+V5s1BZeIFXFu0Q5pl6DnEm769Mm/StnpRR0aG1DBh3tlGavgGSHxl6v66AtTjn6RXMso3NZ
PjYipTrpd+5fcu/H4U/klx+Z/OId8/HfkF9+HPJud6e17bf4+FUYHci+tzF+tCz5QQdpw7hh8lcv
ggXO2+kxcH5jf0Tf1gKYnBak4WY7OmM8yd9ozhqxGqO+s70yPmqSXdTCkZj+Rdx8uvgJUEsDBBQA
AAgIAEC7bFs8tbW6wwAAADwBAAAUAAAAeGwvc2hhcmVkU3RyaW5ncy54bWx9j0FrwkAQRu8F/8My
nutEESllsxKsihdJRQ8el2RqFrKzMbMp7b/v0kLpIfT4vcfwGL3+8K16p15c4BzmswwUcRVqx7cc
Lufd4xMoiZZr2wamHD5JYG0mD1okqnTLkkMTY/eMKFVD3sosdMTJvIXe25hmf0PperK1NETRt7jI
shV66xhUFQaOqbtM3YHdfaDND1nBd8QZHc11W5w0RqMx7V/6eilO5+2IOBx35f6lnF/H3aY8/Key
MTc9YvGXYvrefAFQSwMEFAAACAgAQLtsW7VETOFgAgAAvQ0AABMAAAB4bC90aGVtZS90aGVtZTEu
eG1s7ZfdbpswFMfvJ+0dLN+vfAQoicqqhgTtYlov0j2AA4bQGoNst2nefifQoCTYItVu1m1cROR8
/Pif44Od3Ny+Vgy9UCHLmkfYubIxojyts5IXEf75kHwJMZKK8IywmtMI76jEt18/f7ohM7WhFUWQ
z+WMRHijVDOzLJmCmciruqEcfHktKqLgqyisTJAtcCtmubYdWBUpOUacVIC9X6zQw56HgY0QOuCX
DD64kp21c6RMrNL22frcPjB7co4tnVGKYh0zgV4Ii7DdXtg6SbQGmZDG1Bgraa8h6yyz1eWOsJzE
m14vdLrcga4x1nK5jJeOTtc5i6Qp9HqsTi8JnblGmya7Z45pjG3f9oxMvc7JCHM6n8/9qYk50TK9
EWZoB96da2J6WqY/1s/5XRwHJqavZQZjs3g9DTwjMzhjbljJny54U3TTPciFxLxm3y5AhoAMNS/f
IH1v7F/6450gr7m6bCuoyGMtEggfamJElRypXUNzkgIjrp9FSQX6Qben2rpwSo5idQGpNAbsC9Eq
2Sss+Z+icKCkW5VDr09WoLpwAfKSsZXaMfpdaiqUNSuzBELOXG/e9gn93DQbuB3WZZkxH/4J7QIY
OrgfEG5uLeMorZoswpIXGBFWwDGfKoHRFrZI3/UxSkkT4RyGDOuVm+t6R2kj/etIjZBqQeSmA7Wx
2h4x/r46Xd+DU/4fKHQSOn9DoZ3FMOw0z2mqzAN/5NdK6vyQqtNhTv5w5DPXsJHrIvm/Kf/mpmzo
YbtfVyfn5d6k+UsDKur1IyzSAs7jZ6ak1dvpqxIkPvzueVv8HgP3vwBQSwMEFAAACAgAQLtsW4ly
T/uKAQAAggMAABAAAABkb2NQcm9wcy9hcHAueG1snVPBTuMwEL2vxD9YvlMngFaryglCwGoPICq1
wNk4k8bCtSPPELX79TgxDUUBDtw87808z/N45Pl2Y1kHAY13Bc9nGWfgtK+MWxf8fvX3+A9nSMpV
ynoHBd8B8vPy6JdcBN9CIAPIooTDgjdE7VwI1A1sFM4i7SJT+7BRFMOwFr6ujYYrr1824EicZNlv
AVsCV0F13I6CPCnOO/qpaOV13x8+rHZt1Iv9MiYv2tYarSg6LW+NDh59Tex6q8FKcUgO2VFwCfol
GNqVmRSH4cAvtbJwGS8pa2URpHgHBv4fqP4RF8oEHJCIdTTvQJMPDM3/+JgnnD0phL7JgncqGOWI
vyW/pSdwxBJqW6RQPvrwjA0AoRQjOBaLT6q/VjRnZT6UxMM3EgkaLCSXYmJTrgxZwLt6oQJ96Tw/
dD50/tF3MrPs3eUTd9MupnfKG+Oe8b5d+StFsJ/RRzDNsVEBqjjecY4jkOYYWwy2r7tslFtDtc+b
Evtf9pDWqczPZtlplg2fa4/FzRHvqxPDV1BLAwQUAAAICABAu2xbORmDeu4AAADSAgAAGgAAAHhs
L19yZWxzL3dvcmtib29rLnhtbC5yZWxzrZLPasMwDIfvg72D0X1x0o0xRrxexqDXrXsA4yhxaGIb
S/uTt59ooU1hrDvkZPQz+vRhuV5/j4P6xEx9DAaqogSFwcWmD52B9+3LzQMoYhsaO8SABiYkWD9d
X9WvOFiWJvJ9IiWUQAY8c3rUmpzH0VIREwa5aWMeLUuZO52s29kO9aos73WeM0CoSqkzsNo0BvKm
qUBtp4T/GRDbtnf4HN3HiIF/maO/Yt6RR2SB2twhGzhGpPdHVQgV9B9GqyWNiKdB3vWoc6gvOtwu
6uBtxuaNs2x+rjKPLxrdLWnE0osnk315CE/rqfXZP5TkB1BLAwQUAAAICABAu2xbgwm2UoIBAAD/
AgAAEQAAAGRvY1Byb3BzL2NvcmUueG1spZJdT8MgFIbvTfwPyD3lY25qs4/EGhMTp4vObHeG0LON
2EID6Ny/l7ZbndE7L+E85+HwwnDyWRboA5zX1owwTxhGYJTNtVmP8Mv8llxi5IM0uSysgRHegceT
8enJUFWpsg5mzlbgggaPosn4VFUjvAmhSin1agOl9EkkTCyurCtliEu3ppVUb3INVDA2oCUEmcsg
aS0kVWfEe2WuOmX17opGkCsKBZRggqc84fSbDeBK/2dDUzkiSx12FfyJHood/el1B26322Tba9A4
P6fL6f1zc1WiTZ2VAlwndEYI8tLH3Nb7gNFVws4TxqcXM3bJ+oIJhgjp2J3fWB+0Wdm6By0H56+c
zZ4e0eLuAXGWsESIgeAILax7iweFWtn25ypVDmSwbpzxLMsYG9Kjvfa9CunDND7tSkN+vfsGf5da
3sGHrsce84bpls15TZjtAZCjGE/ahnmoLHrZzfwWj+Ml+4RzwsVc9FIxSBknrJ+2A/6QHHvL/Sz/
Ex8stZn++rBx9wtQSwMEFAAACAgAQLtsW9Ivm4HuAAAAXwIAAAsAAABfcmVscy8ucmVsc62SvU4D
MQyAdyTeIfLe87VICKELXRBSN4TKA5jE96O7i6MkQPv2mKWiCEoHxjj250+2m/VunswbpzxIsLCs
ajAcnPghdBaetw+LGzC5UPA0SWALe86wvru8aJ54oqJFuR9iNkoJ2UJfSrxFzK7nmXIlkYP+tJJm
KvpMHUZyI3WMq7q+xvSVAUo1xhyBzcZbSBu/BLPdRz6ngbTt4Phe3OvMofzQ51uGkil1XCzsJnyX
NL6IjJVCAU8Irf5TiHeFg2e/iEnrUxl0xgcrL+5Rwxkpxj+1rs7X+n0ROHMhT4XQSeLTUp8ZB6sG
j45CIx9QSwECFAAUAAAICABAu2xbL/tE4XUBAADdBQAAEwAAAAAAAAAAAAAAAAAAAAAAW0NvbnRl
bnRfVHlwZXNdLnhtbFBLAQIUABQAAAgIAEC7bFtZHDI9EBsAABjYAAAYAAAAAAAAAAAAAAAAAKYB
AAB4bC93b3Jrc2hlZXRzL3NoZWV0MS54bWxQSwECFAAUAAAICABAu2xb+ZIlonwAAACQAAAAIwAA
AAAAAAAAAAAAAADsHAAAeGwvd29ya3NoZWV0cy9fcmVscy9zaGVldDEueG1sLnJlbHNQSwECFAAU
AAAICABAu2xbbN9xOD8BAAAiAgAADwAAAAAAAAAAAAAAAACpHQAAeGwvd29ya2Jvb2sueG1sUEsB
AhQAFAAACAgAQLtsW3K3PcBZAgAAjAgAAA0AAAAAAAAAAAAAAAAAFR8AAHhsL3N0eWxlcy54bWxQ
SwECFAAUAAAICABAu2xbPLW1usMAAAA8AQAAFAAAAAAAAAAAAAAAAACZIQAAeGwvc2hhcmVkU3Ry
aW5ncy54bWxQSwECFAAUAAAICABAu2xbtURM4WACAAC9DQAAEwAAAAAAAAAAAAAAAACOIgAAeGwv
dGhlbWUvdGhlbWUxLnhtbFBLAQIUABQAAAgIAEC7bFuJck/7igEAAIIDAAAQAAAAAAAAAAAAAAAA
AB8lAABkb2NQcm9wcy9hcHAueG1sUEsBAhQAFAAACAgAQLtsWzkZg3ruAAAA0gIAABoAAAAAAAAA
AAAAAAAA1yYAAHhsL19yZWxzL3dvcmtib29rLnhtbC5yZWxzUEsBAhQAFAAACAgAQLtsW4MJtlKC
AQAA/wIAABEAAAAAAAAAAAAAAAAA/ScAAGRvY1Byb3BzL2NvcmUueG1sUEsBAhQAFAAACAgAQLts
W9Ivm4HuAAAAXwIAAAsAAAAAAAAAAAAAAAAArikAAF9yZWxzLy5yZWxzUEsFBgAAAAALAAsA0QIA
AMUqAAAAAA==
headers:
Accept-CH:
- Sec-CH-UA-Full-Version-List,Sec-CH-UA-Platform-Version,Sec-CH-UA-Arch,Sec-CH-UA-Model,Sec-CH-UA-Bitness
Accept-Ranges:
- bytes
Alt-Svc:
- h3=":443"; ma=93600
Cache-Control:
- no-cache, no-store
Connection:
- keep-alive
Content-Disposition:
- attachment; filename="Inflation.xlsx"
Content-Length:
- '11692'
Content-Type:
- application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Cross-Origin-Resource-Policy:
- same-origin
Date:
- Fri, 30 Jan 2026 17:40:24 GMT
Expires:
- Fri, 30 Jan 2026 17:40:24 GMT
Permissions-Policy:
- accelerometer=(), autoplay=(), camera=(), cross-origin-isolated=(), display-capture=(),
encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(),
magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(),
publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(self), usb=(),
web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(),
gamepad=(), hid=(), idle-detection=(), interest-cohort=(), serial=()
Pragma:
- no-cache
Request-Context:
- appId=cid-v1:f9022a67-4930-4cc0-ba44-662b99235122
Set-Cookie:
- _abck=DCDEEE818CAA80DB1ACF0479E556F108~-1~YAAQW1MiF4jy/wqcAQAArej9Dw8pwIYyVx2wegyp4U367DnmqvV72JeKuUZ0zmxGBboOVsIfgkn4YYtyUqjdVIXfSH70WW1lxxv25AIe6VYFYjuexURiHLqBheTUxRwNNELY/Dsj1cxvSfTV6iEz00a3sNczsNnrAGmV9qnBnpwN7mgQckZ4z4v9QoxlKF8X+LrFJFTOuaAOXy2aZNGxjyWech/avYpVr3svv1H8WW7rDU+O9lOVb4WJEYbu9WzaJzTpt2OIl7Kp+OOgq9pLmMbDcSB2WfClzMfIIFJy8Dge7FTYKML31cRphmSPgCYrANTaHR7piVTxNRwl2AnnVnPVfmEAaWasvuvZ0L4/nxiFvKbeJLWIQuzhVkpF6TO1FtU31hCTdsqUyBxMFfIRjmsHjDr5CBehgMHfjYORfydpNy1NGkp4JMCJaypcW2Ohq8QSKIMNQJYpiCsrI9yHoOqeo5iRWslE8WwK~-1~-1~-1~-1~-1;
Domain=.philadelphiafed.org; Path=/; Expires=Sat, 30 Jan 2027 17:40:24 GMT;
Max-Age=31536000; Secure
- bm_sz=191D799C5F13370F3F548BA76571014D~YAAQW1MiF4ny/wqcAQAArej9Dx54W23fb3lnkj07VsXh09HkSWVNZ+x1H+EqrPtvkY7J+vJI+yPEqKF4Cbb61GVRFgCpdzKfLQnTgB+Y0fvI2VxD5KoOsPa1lIz2XPsrvMJufJlevew2qbBWBKIZMJFWhSxzmTzFnrF1HQycAc0OQnuXTjI/x9FDJptG9dph1rZ+jH2qgVvi0wqTXBEjP3LC8FJ22ELrhbCdusJqdL6iTj6rryCJ6oOXGyVS5akt3HbicvkhTHKLG2IrTyJxST17gastIOrjjg1kRt87rDlz+nS/dIvQD2w4WkwzcYHCAfRWulh0Ushk5pVSqbULRcDAfphRAlULAk/4RfrN1of8qnkiIw==~3618869~3555905;
Domain=.philadelphiafed.org; Path=/; Expires=Fri, 30 Jan 2026 21:40:24 GMT;
Max-Age=14400
Strict-Transport-Security:
- max-age=86400
X-Content-Type-Options:
- nosniff
X-Permitted-Cross-Domain-Policies:
- none
status:
code: 200
message: OK
version: 1

View File

@@ -13,6 +13,9 @@ from openbb_federal_reserve.models.federal_funds_rate import (
from openbb_federal_reserve.models.fomc_documents import (
FederalReserveFomcDocumentsFetcher,
)
from openbb_federal_reserve.models.inflation_expectations import (
FederalReserveInflationExpectationsFetcher,
)
from openbb_federal_reserve.models.money_measures import (
FederalReserveMoneyMeasuresFetcher,
)
@@ -26,6 +29,12 @@ from openbb_federal_reserve.models.primary_dealer_positioning import (
FederalReservePrimaryDealerPositioningFetcher,
)
from openbb_federal_reserve.models.sofr import FederalReserveSOFRFetcher
from openbb_federal_reserve.models.svensson_yield_curve import (
FederalReserveSvenssonFetcher,
)
from openbb_federal_reserve.models.total_factor_productivity import (
FederalReserveTfpFetcher,
)
from openbb_federal_reserve.models.treasury_rates import (
FederalReserveTreasuryRatesFetcher,
)
@@ -85,6 +94,16 @@ def test_federal_reserve_yield_curve_fetcher(credentials=test_credentials):
assert result is None
@pytest.mark.record_http
def test_federal_reserve_svensson_fetcher(credentials=test_credentials):
"""Test the Federal Reserve Svensson fetcher."""
params = {}
fetcher = FederalReserveSvenssonFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_federal_reserve_central_bank_holdings_fetcher(credentials=test_credentials):
"""Test the Federal Reserve Central Bank Holdings Fetcher."""
@@ -155,3 +174,27 @@ def test_federal_reserve_fomc_documents_fetcher(
fetcher = FederalReserveFomcDocumentsFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_federal_reserve_total_factor_productivity_fetcher(
credentials=test_credentials,
):
"""Test the Federal Reserve Total Factor Productivity Fetcher."""
params = {}
fetcher = FederalReserveTfpFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_federal_reserve_inflation_expectations_fetcher(
credentials=test_credentials,
):
"""Test the Federal Reserve Inflation Expectations Fetcher."""
params = {}
fetcher = FederalReserveInflationExpectationsFetcher()
result = fetcher.test(params, credentials)
assert result is None