mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Add congress.gov provider extension (#7141)
* Add congress.gov provider extension * Fix congress.gov provider structure * Add congress.gov provider extension * clean up * try 1 command at a time * fix tests * cleanup * black linter * more lint * improve start and end date * lower case * add extension * update reference.json * lint * fix * record http * lint * pylint * lint * lint * [Feature] Congress.gov Bill Viewer Application (#7192) fix 'No record found' error raising instead of returning (#7178) Fix] `openbb-platform-api`: Fix `check_for_platform_extensions` Filter (#7184) * fix tests and remove unused files * fix test * wrap value error and OpenBBError and add some comments * unneeded check in param model validator * don't base64-encode non-pdf document downloads * fix typo - refecthInterval * docstring * docstring --------- Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com>
This commit is contained in:
@@ -25,6 +25,7 @@ openbb-platform-api = { path = "./extensions/platform_api", develop = true }
|
||||
openbb-benzinga = { path = "./providers/benzinga", develop = true }
|
||||
openbb-bls = { path = "./providers/bls", develop = true }
|
||||
openbb-cftc = { path = "./providers/cftc", develop = true }
|
||||
openbb-congress-gov = { path = "./providers/congress_gov", develop = true }
|
||||
openbb-econdb = { path = "./providers/econdb", develop = true }
|
||||
openbb-federal-reserve = { path = "./providers/federal_reserve", develop = true }
|
||||
openbb-fmp = { path = "./providers/fmp", develop = true }
|
||||
|
||||
@@ -542,5 +542,103 @@
|
||||
}
|
||||
},
|
||||
"groups": []
|
||||
},
|
||||
{
|
||||
"name": "The United States Congress",
|
||||
"img": "https://www.congress.gov/img/opengraph1200by630.jpg",
|
||||
"img_dark": "https://www.congress.gov/img/opengraph1200by630.jpg",
|
||||
"img_light": "https://www.congress.gov/img/opengraph1200by630.jpg",
|
||||
"description": "Find and view US federal legislative information and complete bill text.",
|
||||
"allowCustomization": true,
|
||||
"tabs": {
|
||||
"": {
|
||||
"id": "",
|
||||
"name": "",
|
||||
"layout": [
|
||||
{
|
||||
"i": "uscongress_bills_congress_gov_obb",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 40,
|
||||
"h": 11,
|
||||
"state": {
|
||||
"params": {
|
||||
"bill_url": "119/hr/1"
|
||||
},
|
||||
"chartView": {
|
||||
"enabled": false,
|
||||
"chartType": "line"
|
||||
},
|
||||
"columnState": {
|
||||
"default": {
|
||||
"columnVisibility": {
|
||||
"hiddenColIds": [
|
||||
"origin_chamber_code"
|
||||
]
|
||||
},
|
||||
"columnOrder": {
|
||||
"orderedColIds": [
|
||||
"update_date",
|
||||
"latest_action_date",
|
||||
"bill_url",
|
||||
"congress",
|
||||
"bill_number",
|
||||
"origin_chamber",
|
||||
"origin_chamber_code",
|
||||
"bill_type",
|
||||
"title",
|
||||
"latest_action",
|
||||
"update_date_including_text"
|
||||
]
|
||||
},
|
||||
"focusedCell": {
|
||||
"colId": "bill_url",
|
||||
"rowIndex": 2,
|
||||
"rowPinned": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"i": "uscongress_bill_text_congress_gov_obb",
|
||||
"x": 16,
|
||||
"y": 11,
|
||||
"w": 24,
|
||||
"h": 41,
|
||||
"state": {
|
||||
"params": {
|
||||
"bill_url": "119/hr/1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"i": "uscongress_bill_info_congress_gov_obb",
|
||||
"x": 0,
|
||||
"y": 11,
|
||||
"w": 16,
|
||||
"h": 41,
|
||||
"state": {
|
||||
"params": {
|
||||
"bill_url": "119/hr/1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"groups": [
|
||||
{
|
||||
"name": "Group 1",
|
||||
"type": "param",
|
||||
"paramName": "bill_url",
|
||||
"defaultValue": "119/hr/1",
|
||||
"widgetIds": [
|
||||
"uscongress_bills_congress_gov_obb",
|
||||
"uscongress_bill_text_congress_gov_obb",
|
||||
"uscongress_bill_info_congress_gov_obb"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
1
openbb_platform/extensions/uscongress/__init__.py
Normal file
1
openbb_platform/extensions/uscongress/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""US Congress Router module for integration tests."""
|
||||
@@ -0,0 +1,128 @@
|
||||
"""Test Government API."""
|
||||
|
||||
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')}"}
|
||||
|
||||
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"limit": 5,
|
||||
"offset": 0,
|
||||
"sort_by": "desc",
|
||||
"congress": None,
|
||||
"bill_type": None,
|
||||
"start_date": None,
|
||||
"end_date": None,
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bills(params, headers):
|
||||
"""Test the government congress bills endpoint."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
query_str = get_querystring(params, [])
|
||||
url = f"http://0.0.0.0:8000/api/v1/uscongress/bills?{query_str}"
|
||||
result = requests.get(url, headers=headers, timeout=10)
|
||||
assert isinstance(result, requests.Response)
|
||||
assert result.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"bill_url": "119/hr/1",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bill_info(params, headers):
|
||||
"""Test the government congress bill info endpoint."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
query_str = get_querystring(params, [])
|
||||
url = f"http://0.0.0.0:8000/api/v1/uscongress/bill_info?{query_str}"
|
||||
result = requests.get(url, headers=headers, timeout=10)
|
||||
assert isinstance(result, requests.Response)
|
||||
assert result.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"bill_url": "https://api.congress.gov/v3/bill/119/s/1947?format=json",
|
||||
"is_workspace": False,
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bill_text_urls(params, headers):
|
||||
"""Test the government congress bill text URLs endpoint."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
query_str = get_querystring(params, [])
|
||||
url = f"http://0.0.0.0:8000/api/v1/uscongress/bill_text_urls?{query_str}"
|
||||
result = requests.get(url, headers=headers, timeout=10)
|
||||
assert isinstance(result, requests.Response)
|
||||
assert result.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"urls": [
|
||||
"https://www.congress.gov/119/bills/hr1/BILLS-119hr1eh.pdf",
|
||||
],
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bill_text(params, headers):
|
||||
"""Test the government congress bill text endpoint."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
urls = params.pop("urls", [])
|
||||
|
||||
query_str = get_querystring(params, [])
|
||||
url = f"http://0.0.0.0:8000/api/v1/uscongress/bill_text?{query_str}"
|
||||
result = requests.post(url, headers=headers, json=f"'{urls}'", timeout=10)
|
||||
assert isinstance(result, requests.Response)
|
||||
assert result.status_code == 200
|
||||
@@ -0,0 +1,124 @@
|
||||
"""Test Government extension."""
|
||||
|
||||
import pytest
|
||||
from openbb_congress_gov.models.bill_info import CongressBillInfoData
|
||||
from openbb_congress_gov.models.bill_text import CongressBillTextData
|
||||
from openbb_core.app.model.obbject import OBBject
|
||||
|
||||
|
||||
@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
|
||||
|
||||
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"limit": 5,
|
||||
"offset": 0,
|
||||
"sort_by": "desc",
|
||||
"congress": None,
|
||||
"bill_type": None,
|
||||
"start_date": None,
|
||||
"end_date": None,
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bills(params, obb):
|
||||
"""Test US Congress bills."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
result = obb.uscongress.bills(**params)
|
||||
assert result
|
||||
assert isinstance(result, OBBject)
|
||||
assert len(result.results) > 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"bill_url": "119/hr/1",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bill_info(params, obb):
|
||||
"""Test US Congress bill info."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
result = obb.uscongress.bill_info(**params)
|
||||
assert result
|
||||
assert isinstance(result, OBBject)
|
||||
assert isinstance(result.results, CongressBillInfoData)
|
||||
assert isinstance(result.results.markdown_content, str)
|
||||
assert isinstance(result.results.raw_data, dict)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"bill_url": "https://api.congress.gov/v3/bill/119/s/1947?format=json",
|
||||
"is_workspace": False,
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bill_text_urls(params, obb):
|
||||
"""Test US Congress bill text URLs."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
result = obb.uscongress.bill_text_urls(**params)
|
||||
assert result
|
||||
assert isinstance(result, list)
|
||||
assert len(result) > 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
(
|
||||
{
|
||||
"provider": "congress_gov",
|
||||
"urls": [
|
||||
"https://www.congress.gov/119/bills/hr1/BILLS-119hr1eh.pdf",
|
||||
],
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_uscongress_bill_text(params, obb):
|
||||
"""Test US Congress bill text."""
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
result = obb.uscongress.bill_text(**params)
|
||||
assert result
|
||||
assert isinstance(result, list)
|
||||
assert len(result) > 0
|
||||
assert isinstance(result[0], CongressBillTextData)
|
||||
402
openbb_platform/openbb/assets/reference.json
vendored
402
openbb_platform/openbb/assets/reference.json
vendored
@@ -16,12 +16,14 @@
|
||||
"fixedincome@1.4.4",
|
||||
"index@1.4.2",
|
||||
"news@1.4.2",
|
||||
"regulators@1.4.3"
|
||||
"regulators@1.4.3",
|
||||
"uscongress@1.0.0"
|
||||
],
|
||||
"openbb_provider_extension": [
|
||||
"benzinga@1.4.2",
|
||||
"bls@1.1.3",
|
||||
"cftc@1.1.2",
|
||||
"congress_gov@1.0.0",
|
||||
"econdb@1.3.2",
|
||||
"federal_reserve@1.4.4",
|
||||
"fmp@1.4.3",
|
||||
@@ -44142,6 +44144,401 @@
|
||||
"openapi_extra": {
|
||||
"model": "COT"
|
||||
}
|
||||
},
|
||||
"/uscongress/bills": {
|
||||
"deprecated": {
|
||||
"flag": null,
|
||||
"message": null
|
||||
},
|
||||
"description": "Get and filter lists of Congressional Bills.",
|
||||
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.uscongress.bills(provider='congress_gov')\nobb.uscongress.bills(start_date=2025-01-01, end_date=2025-01-31, provider='congress_gov')\n# Get all bills of type 's' (Senate) for the 118th Congress.\nobb.uscongress.bills(bill_type=s, congress=118, limit=0, provider='congress_gov')\n```\n\n",
|
||||
"parameters": {
|
||||
"standard": [],
|
||||
"congress_gov": [
|
||||
{
|
||||
"name": "congress",
|
||||
"type": "int",
|
||||
"description": "Congress number (e.g., 118 for the 118th Congress). The 103rd Congress started in 1993, which is the earliest date supporting full text versions. Each Congress spans two years, starting in odd-numbered years.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "bill_type",
|
||||
"type": "str",
|
||||
"description": "Bill type (e.g., 'hr' for House bills).\n\nMust be one of: hr, s, hjres, sjres, hconres, sconres, hres, sres.\n\nBills\n-----\n\nA bill is the form used for most legislation, whether permanent or temporary, general or special, public or private.\n\nA bill originating in the House of Representatives is designated by the letters \u201cH.R.\u201d,\nsignifying \u201cHouse of Representatives\u201d, followed by a number that it retains throughout all its parliamentary stages.\n\nBills are presented to the President for action when approved in identical form\nby both the House of Representatives and the Senate.\n\nJoint Resolutions\n-----------------\n\nJoint resolutions may originate either in the House of Representatives or in the Senate.\n\nThere is little practical difference between a bill and a joint resolution. Both are subject to the same procedure,\nexcept for a joint resolution proposing an amendment to the Constitution.\n\nOn approval of such a resolution by two-thirds of both the House and Senate,\nit is sent directly to the Administrator of General Services for submission to the individual states for ratification.\n\nIt is not presented to the President for approval.\nA joint resolution originating in the House of Representatives is designated \u201cH.J.Res.\u201d followed by its individual number.\nJoint resolutions become law in the same manner as bills.\n\nConcurrent Resolutions\n----------------------\n\nMatters affecting the operations of both the House of Representatives and Senate\nare usually initiated by means of concurrent resolutions.\n\nA concurrent resolution originating in the House of Representatives is designated \u201cH.Con.Res.\u201d\nfollowed by its individual number.\n\nOn approval by both the House of Representatives and Senate,\nthey are signed by the Clerk of the House and the Secretary of the Senate.\n\nThey are not presented to the President for action.\n\nSimple Resolutions\n------------------\n\nA matter concerning the operation of either the House of Representatives or Senate\nalone is initiated by a simple resolution.\n\nA resolution affecting the House of Representatives is designated \u201cH.Res.\u201d followed by its number.\n\nThey are not presented to the President for action.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "start_date",
|
||||
"type": "Union[date, str]",
|
||||
"description": "Start date of the data, in YYYY-MM-DD format. Filters bills by the last updated date.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "end_date",
|
||||
"type": "Union[date, str]",
|
||||
"description": "End date of the data, in YYYY-MM-DD format. Filters bills by the last updated date.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"type": "int",
|
||||
"description": "The number of data entries to return. When None, default sets to 100 (max 250). Set to 0 for no limit (must be used with 'bill_type' and 'congress').",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "offset",
|
||||
"type": "int",
|
||||
"description": "The starting record returned. 0 is the first record.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "sort_by",
|
||||
"type": "Literal['asc', 'desc']",
|
||||
"description": "Sort by update date. Default is latest first.",
|
||||
"default": "desc",
|
||||
"optional": true,
|
||||
"choices": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"returns": {
|
||||
"OBBject": [
|
||||
{
|
||||
"name": "results",
|
||||
"type": "list[CongressBills]",
|
||||
"description": "Serializable results."
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": "Optional[Literal['congress_gov']]",
|
||||
"description": "Provider name."
|
||||
},
|
||||
{
|
||||
"name": "warnings",
|
||||
"type": "Optional[list[Warning_]]",
|
||||
"description": "list of warnings."
|
||||
},
|
||||
{
|
||||
"name": "chart",
|
||||
"type": "Optional[Chart]",
|
||||
"description": "Chart object."
|
||||
},
|
||||
{
|
||||
"name": "extra",
|
||||
"type": "dict[str, Any]",
|
||||
"description": "Extra info."
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"standard": [],
|
||||
"congress_gov": [
|
||||
{
|
||||
"name": "update_date",
|
||||
"type": "date",
|
||||
"description": "The date the bill was last updated.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "latest_action_date",
|
||||
"type": "date",
|
||||
"description": "The date of the latest action on the bill.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "bill_url",
|
||||
"type": "str",
|
||||
"description": "Base URL to the bill for the congress.gov API.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "congress",
|
||||
"type": "int",
|
||||
"description": "The congress session number.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "bill_number",
|
||||
"type": "int",
|
||||
"description": "The bill number.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "origin_chamber",
|
||||
"type": "str",
|
||||
"description": "The chamber where the bill originated.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "origin_chamber_code",
|
||||
"type": "str",
|
||||
"description": "The chamber code where the bill originated.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "bill_type",
|
||||
"type": "str",
|
||||
"description": "The type of bill (e.g., HR, S).",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "str",
|
||||
"description": "The title of the bill.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "latest_action",
|
||||
"type": "str",
|
||||
"description": "Latest action information for the bill.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "update_date_including_text",
|
||||
"type": "datetime",
|
||||
"description": "The date and time the bill text was last updated.",
|
||||
"default": null,
|
||||
"optional": true,
|
||||
"choices": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"model": "CongressBills",
|
||||
"openapi_extra": {
|
||||
"model": "CongressBills"
|
||||
}
|
||||
},
|
||||
"/uscongress/bill_text_urls": {
|
||||
"deprecated": {
|
||||
"flag": null,
|
||||
"message": null
|
||||
},
|
||||
"description": "Helper function to populate document choices for a specific bill.\n\n This function is used by the Congressional Bills Viewer widget, in OpenBB Workspace,\n to populate PDF document choices for the selected bill.\n\n When 'is_workspace' is False (default), it returns a list of the available text versions\n of the specified bill and their download links for the different formats.",
|
||||
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.uscongress.bill_text_urls(provider='congress_gov', bill_url='https://api.congress.gov/v3/bill/119/s/1947?')\nobb.uscongress.bill_text_urls(provider='congress_gov', bill_url='119/s/1947')\n```\n\n",
|
||||
"parameters": {
|
||||
"standard": [
|
||||
{
|
||||
"name": "bill_url",
|
||||
"type": "str",
|
||||
"description": "The base URL of the bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?format=json').",
|
||||
"default": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": "str",
|
||||
"description": "The provider name, always 'congress_gov'. This is a dummy parameter.",
|
||||
"default": "congress_gov",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "is_workspace",
|
||||
"type": "bool",
|
||||
"description": "Whether the request is coming from the OpenBB Workspace.",
|
||||
"default": "",
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"returns": "list",
|
||||
"data": {},
|
||||
"model": null,
|
||||
"openapi_extra": {
|
||||
"widget_config": {
|
||||
"name": "Congressional Bill Viewer",
|
||||
"description": "View current and historical U.S. Congressional Bills.",
|
||||
"category": "Government",
|
||||
"subCategory": "Congress",
|
||||
"type": "multi_file_viewer",
|
||||
"searchCategory": "Congress",
|
||||
"widgetId": "uscongress_bill_text_congress_gov_obb",
|
||||
"endpoint": "/api/v1/uscongress/bill_text",
|
||||
"params": [
|
||||
{
|
||||
"paramName": "urls",
|
||||
"type": "endpoint",
|
||||
"optionsEndpoint": "/api/v1/uscongress/bill_text_urls",
|
||||
"optionsParams": {
|
||||
"bill_url": "$bill_url",
|
||||
"is_workspace": true
|
||||
},
|
||||
"show": false,
|
||||
"multiSelect": true,
|
||||
"roles": [
|
||||
"fileSelector"
|
||||
]
|
||||
},
|
||||
{
|
||||
"paramName": "is_workspace",
|
||||
"value": true,
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"label": "Bill URL",
|
||||
"description": "Enter a base URL of a bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?format=json'). Alternatively, you can enter a bill number (e.g., '119/s/1947'). Create a group on the 'Bill URL' field of the 'Congressional Bills' widget and click on the cell to view the available documents.",
|
||||
"show": true,
|
||||
"paramName": "bill_url",
|
||||
"value": "119/hr/1"
|
||||
}
|
||||
],
|
||||
"refecthInterval": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"/uscongress/bill_info": {
|
||||
"deprecated": {
|
||||
"flag": null,
|
||||
"message": null
|
||||
},
|
||||
"description": "Get summary, status, and other metadata for a specific bill.\n\nEnter the URL of the bill as: https://api.congress.gov/v3/bill/119/hr/131?\n\nURLs for bills can be found from the `uscongress.bills` endpoint.\n\nThe raw JSON response from the API will be returned along with a formatted\ntext version of the key information from the raw response.\n\nIn OpenBB Workspace, this command returns as a Markdown widget.",
|
||||
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.uscongress.bill_info(provider='congress_gov', bill_url=https://api.congress.gov/v3/bill/119/s/1947?)\n# The bill URL can be shortened to just the bill number (e.g., '119/s/1947').\nobb.uscongress.bill_info(bill_url=119/s/1947, provider='congress_gov')\n```\n\n",
|
||||
"parameters": {
|
||||
"standard": [],
|
||||
"congress_gov": [
|
||||
{
|
||||
"name": "bill_url",
|
||||
"type": "str",
|
||||
"description": "Enter a base URL of a bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?format=json'). Alternatively, you can enter a bill number (e.g., '119/s/1947').",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"returns": {
|
||||
"OBBject": [
|
||||
{
|
||||
"name": "results",
|
||||
"type": "list[CongressBillInfo]",
|
||||
"description": "Serializable results."
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": "Optional[Literal['congress_gov']]",
|
||||
"description": "Provider name."
|
||||
},
|
||||
{
|
||||
"name": "warnings",
|
||||
"type": "Optional[list[Warning_]]",
|
||||
"description": "list of warnings."
|
||||
},
|
||||
{
|
||||
"name": "chart",
|
||||
"type": "Optional[Chart]",
|
||||
"description": "Chart object."
|
||||
},
|
||||
{
|
||||
"name": "extra",
|
||||
"type": "dict[str, Any]",
|
||||
"description": "Extra info."
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"standard": [],
|
||||
"congress_gov": [
|
||||
{
|
||||
"name": "markdown_content",
|
||||
"type": "str",
|
||||
"description": "Aggregated metadata for the bill in Markdown format.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
},
|
||||
{
|
||||
"name": "raw_data",
|
||||
"type": "dict[str, Any]",
|
||||
"description": "Raw JSON data from the collected bill information.",
|
||||
"default": "",
|
||||
"optional": false,
|
||||
"choices": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"model": "CongressBillInfo",
|
||||
"openapi_extra": {
|
||||
"model": "CongressBillInfo"
|
||||
}
|
||||
},
|
||||
"/uscongress/bill_text": {
|
||||
"deprecated": {
|
||||
"flag": null,
|
||||
"message": null
|
||||
},
|
||||
"description": "Download the text of a specific bill in PDF format.\n\n This endpoint accepts a list of URLs to download and returns the base64-encoded\n PDF content along with the filename.\n\n In OpenBB Workspace, this command returns as a multi-file viewer widget.\n\n This command outputs only the results array of the OBBject.",
|
||||
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.uscongress.bill_text(provider='congress_gov', urls=['https://www.congress.gov/119/bills/hr1/BILLS-119hr1eh.pdf'])\n```\n\n",
|
||||
"parameters": {
|
||||
"standard": []
|
||||
},
|
||||
"returns": {
|
||||
"OBBject": [
|
||||
{
|
||||
"name": "results",
|
||||
"type": "list[Data]",
|
||||
"description": "Serializable results."
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": null,
|
||||
"description": "Provider name."
|
||||
},
|
||||
{
|
||||
"name": "warnings",
|
||||
"type": "Optional[list[Warning_]]",
|
||||
"description": "list of warnings."
|
||||
},
|
||||
{
|
||||
"name": "chart",
|
||||
"type": "Optional[Chart]",
|
||||
"description": "Chart object."
|
||||
},
|
||||
{
|
||||
"name": "extra",
|
||||
"type": "dict[str, Any]",
|
||||
"description": "Extra info."
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {},
|
||||
"model": null,
|
||||
"openapi_extra": {
|
||||
"widget_config": {
|
||||
"exclude": true
|
||||
},
|
||||
"model": "CongressBillText"
|
||||
}
|
||||
}
|
||||
},
|
||||
"routers": {
|
||||
@@ -44180,6 +44577,9 @@
|
||||
},
|
||||
"/regulators": {
|
||||
"description": "Financial market regulators data."
|
||||
},
|
||||
"/uscongress": {
|
||||
"description": "Data connector to Congress.gov API."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ Routers:
|
||||
/index
|
||||
/news
|
||||
/regulators
|
||||
/uscongress
|
||||
|
||||
Extensions:
|
||||
- commodity@1.3.2
|
||||
@@ -32,10 +33,12 @@ Extensions:
|
||||
- index@1.4.2
|
||||
- news@1.4.2
|
||||
- regulators@1.4.3
|
||||
- uscongress@1.0.0
|
||||
|
||||
- benzinga@1.4.2
|
||||
- bls@1.1.3
|
||||
- cftc@1.1.2
|
||||
- congress_gov@1.0.0
|
||||
- econdb@1.3.2
|
||||
- federal_reserve@1.4.4
|
||||
- fmp@1.4.3
|
||||
@@ -130,3 +133,10 @@ Extensions:
|
||||
from . import regulators
|
||||
|
||||
return regulators.ROUTER_regulators(command_runner=self._command_runner)
|
||||
|
||||
@property
|
||||
def uscongress(self):
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from . import uscongress
|
||||
|
||||
return uscongress.ROUTER_uscongress(command_runner=self._command_runner)
|
||||
|
||||
439
openbb_platform/openbb/package/uscongress.py
Normal file
439
openbb_platform/openbb/package/uscongress.py
Normal file
@@ -0,0 +1,439 @@
|
||||
### THIS FILE IS AUTO-GENERATED. DO NOT EDIT. ###
|
||||
|
||||
from typing import Any, Literal, Optional
|
||||
|
||||
from openbb_core.app.model.field import OpenBBField
|
||||
from openbb_core.app.model.obbject import OBBject
|
||||
from openbb_core.app.static.container import Container
|
||||
from openbb_core.app.static.utils.decorators import exception_handler, validate
|
||||
from openbb_core.app.static.utils.filters import filter_inputs
|
||||
from typing_extensions import Annotated
|
||||
|
||||
|
||||
class ROUTER_uscongress(Container):
|
||||
"""/uscongress
|
||||
bill_info
|
||||
bill_text
|
||||
bill_text_urls
|
||||
bills
|
||||
"""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.__doc__ or ""
|
||||
|
||||
@exception_handler
|
||||
@validate
|
||||
def bill_info(
|
||||
self,
|
||||
provider: Annotated[
|
||||
Optional[Literal["congress_gov"]],
|
||||
OpenBBField(
|
||||
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: congress_gov."
|
||||
),
|
||||
] = None,
|
||||
**kwargs
|
||||
) -> OBBject:
|
||||
"""Get summary, status, and other metadata for a specific bill.
|
||||
|
||||
Enter the URL of the bill as: https://api.congress.gov/v3/bill/119/hr/131?
|
||||
|
||||
URLs for bills can be found from the `uscongress.bills` endpoint.
|
||||
|
||||
The raw JSON response from the API will be returned along with a formatted
|
||||
text version of the key information from the raw response.
|
||||
|
||||
In OpenBB Workspace, this command returns as a Markdown widget.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
provider : str
|
||||
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: congress_gov.
|
||||
bill_url : Optional[str]
|
||||
Enter a base URL of a bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?format=json'). Alternatively, you can enter a bill number (e.g., '119/s/1947'). (provider: congress_gov)
|
||||
|
||||
Returns
|
||||
-------
|
||||
OBBject
|
||||
results : CongressBillInfo
|
||||
Serializable results.
|
||||
provider : Optional[str]
|
||||
Provider name.
|
||||
warnings : Optional[list[Warning_]]
|
||||
list of warnings.
|
||||
chart : Optional[Chart]
|
||||
Chart object.
|
||||
extra : Dict[str, Any]
|
||||
Extra info.
|
||||
|
||||
CongressBillInfo
|
||||
----------------
|
||||
markdown_content : Optional[str]
|
||||
Aggregated metadata for the bill in Markdown format. (provider: congress_gov)
|
||||
raw_data : Optional[dict[str, Any]]
|
||||
Raw JSON data from the collected bill information. (provider: congress_gov)
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb import obb
|
||||
>>> obb.uscongress.bill_info(provider='congress_gov', bill_url='https://api.congress.gov/v3/bill/119/s/1947?')
|
||||
>>> # The bill URL can be shortened to just the bill number (e.g., '119/s/1947').
|
||||
>>> obb.uscongress.bill_info(bill_url='119/s/1947', provider='congress_gov')
|
||||
""" # noqa: E501
|
||||
|
||||
return self._run(
|
||||
"/uscongress/bill_info",
|
||||
**filter_inputs(
|
||||
provider_choices={
|
||||
"provider": self._get_provider(
|
||||
provider,
|
||||
"uscongress.bill_info",
|
||||
("congress_gov",),
|
||||
)
|
||||
},
|
||||
standard_params={},
|
||||
extra_params=kwargs,
|
||||
info={
|
||||
"bill_url": {
|
||||
"congress_gov": {
|
||||
"x-widget_config": {
|
||||
"label": "Bill URL",
|
||||
"description": "Enter a base URL of a bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?'). Alternatively, you can enter a bill number (e.g., '119/s/1947'). Create a group on the 'Bill URL' field of the 'Congressional Bills' widget and click on the cell to view summary and metadata.",
|
||||
"value": "119/hr/1",
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@exception_handler
|
||||
@validate
|
||||
def bill_text(
|
||||
self,
|
||||
provider: Annotated[
|
||||
Optional[Literal["congress_gov"]],
|
||||
OpenBBField(
|
||||
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: congress_gov."
|
||||
),
|
||||
] = None,
|
||||
**kwargs
|
||||
) -> OBBject:
|
||||
"""Download the text of a specific bill in PDF format.
|
||||
|
||||
This endpoint accepts a list of URLs to download and returns the base64-encoded
|
||||
PDF content along with the filename.
|
||||
|
||||
In OpenBB Workspace, this command returns as a multi-file viewer widget.
|
||||
|
||||
This command outputs only the results array of the OBBject.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
provider : str
|
||||
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: congress_gov.
|
||||
urls : Union[str, list[str], dict[str, list[str]], None]
|
||||
list of direct bill URLs to download. Multiple comma separated items allowed. (provider: congress_gov)
|
||||
|
||||
Returns
|
||||
-------
|
||||
OBBject
|
||||
results : list[CongressBillText]
|
||||
Serializable results.
|
||||
provider : Optional[str]
|
||||
Provider name.
|
||||
warnings : Optional[list[Warning_]]
|
||||
list of warnings.
|
||||
chart : Optional[Chart]
|
||||
Chart object.
|
||||
extra : Dict[str, Any]
|
||||
Extra info.
|
||||
|
||||
CongressBillText
|
||||
----------------
|
||||
error_type : Optional[str]
|
||||
Error type if any error occurs during the download. (provider: congress_gov)
|
||||
content : Optional[str]
|
||||
Base64-encoded PDF document. (provider: congress_gov)
|
||||
filename : Optional[str]
|
||||
The filename of the downloaded PDF. (provider: congress_gov)
|
||||
data_format : Optional[dict[str, str]]
|
||||
Data format information, including data type and filename. (provider: congress_gov)
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb import obb
|
||||
>>> obb.uscongress.bill_text(provider='congress_gov', urls='['https://www.congress.gov/119/bills/hr1/BILLS-119hr1eh.pdf']')
|
||||
""" # noqa: E501
|
||||
|
||||
return self._run(
|
||||
"/uscongress/bill_text",
|
||||
**filter_inputs(
|
||||
provider_choices={
|
||||
"provider": self._get_provider(
|
||||
provider,
|
||||
"uscongress.bill_text",
|
||||
("congress_gov",),
|
||||
)
|
||||
},
|
||||
standard_params={},
|
||||
extra_params=kwargs,
|
||||
info={
|
||||
"urls": {
|
||||
"congress_gov": {
|
||||
"multiple_items_allowed": True,
|
||||
"choices": None,
|
||||
}
|
||||
}
|
||||
},
|
||||
data_processing=True,
|
||||
),
|
||||
)
|
||||
|
||||
@exception_handler
|
||||
@validate
|
||||
def bill_text_urls(
|
||||
self,
|
||||
bill_url: Annotated[str, OpenBBField(description="")],
|
||||
is_workspace: Annotated[bool, OpenBBField(description="")] = False,
|
||||
provider: Annotated[
|
||||
Optional[str], OpenBBField(description="")
|
||||
] = "congress_gov",
|
||||
**kwargs: Any
|
||||
) -> list:
|
||||
"""Helper function to populate document choices for a specific bill.
|
||||
|
||||
This function is used by the Congressional Bills Viewer widget, in OpenBB Workspace,
|
||||
to populate PDF document choices for the selected bill.
|
||||
|
||||
When 'is_workspace' is False (default), it returns a list of the available text versions
|
||||
of the specified bill and their download links for the different formats.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bill_url : str
|
||||
The base URL of the bill (e.g., "https://api.congress.gov/v3/bill/119/s/1947?format=json").
|
||||
This can also be a shortened version like "119/s/1947".
|
||||
provider : str
|
||||
The provider name, always "congress_gov". This is a dummy parameter.
|
||||
is_workspace : bool
|
||||
Whether the request is coming from the OpenBB Workspace.
|
||||
This alters the output format to conform to the Workspace's expectations.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[dict]
|
||||
Returns a list of dictionaries with 'label' and 'value' keys, when `is_workspace` is True.
|
||||
Otherwise, returns the 'text' object from the Congress.gov API response.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb import obb
|
||||
>>> obb.uscongress.bill_text_urls(provider='congress_gov', bill_url='https://api.congress.gov/v3/bill/119/s/1947?')
|
||||
>>> obb.uscongress.bill_text_urls(provider='congress_gov', bill_url='119/s/1947')
|
||||
""" # noqa: E501
|
||||
|
||||
return self._run(
|
||||
"/uscongress/bill_text_urls",
|
||||
**filter_inputs(
|
||||
bill_url=bill_url,
|
||||
provider=provider,
|
||||
is_workspace=is_workspace,
|
||||
**kwargs,
|
||||
),
|
||||
)
|
||||
|
||||
@exception_handler
|
||||
@validate
|
||||
def bills(
|
||||
self,
|
||||
provider: Annotated[
|
||||
Optional[Literal["congress_gov"]],
|
||||
OpenBBField(
|
||||
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: congress_gov."
|
||||
),
|
||||
] = None,
|
||||
**kwargs
|
||||
) -> OBBject:
|
||||
"""Get and filter lists of Congressional Bills.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
provider : str
|
||||
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: congress_gov.
|
||||
congress : Optional[int]
|
||||
Congress number (e.g., 118 for the 118th Congress). The 103rd Congress started in 1993, which is the earliest date supporting full text versions. Each Congress spans two years, starting in odd-numbered years. (provider: congress_gov)
|
||||
bill_type : Optional[str]
|
||||
Bill type (e.g., "hr" for House bills).
|
||||
|
||||
Must be one of: hr, s, hjres, sjres, hconres, sconres, hres, sres.
|
||||
|
||||
Bills
|
||||
-----
|
||||
|
||||
A bill is the form used for most legislation, whether permanent or temporary, general or special, public or private.
|
||||
|
||||
A bill originating in the House of Representatives is designated by the letters “H.R.”,
|
||||
signifying “House of Representatives”, followed by a number that it retains throughout all its parliamentary stages.
|
||||
|
||||
Bills are presented to the President for action when approved in identical form
|
||||
by both the House of Representatives and the Senate.
|
||||
|
||||
Joint Resolutions
|
||||
-----------------
|
||||
|
||||
Joint resolutions may originate either in the House of Representatives or in the Senate.
|
||||
|
||||
There is little practical difference between a bill and a joint resolution. Both are subject to the same procedure,
|
||||
except for a joint resolution proposing an amendment to the Constitution.
|
||||
|
||||
On approval of such a resolution by two-thirds of both the House and Senate,
|
||||
it is sent directly to the Administrator of General Services for submission to the individual states for ratification.
|
||||
|
||||
It is not presented to the President for approval.
|
||||
A joint resolution originating in the House of Representatives is designated “H.J.Res.” followed by its individual number.
|
||||
Joint resolutions become law in the same manner as bills.
|
||||
|
||||
Concurrent Resolutions
|
||||
----------------------
|
||||
|
||||
Matters affecting the operations of both the House of Representatives and Senate
|
||||
are usually initiated by means of concurrent resolutions.
|
||||
|
||||
A concurrent resolution originating in the House of Representatives is designated “H.Con.Res.”
|
||||
followed by its individual number.
|
||||
|
||||
On approval by both the House of Representatives and Senate,
|
||||
they are signed by the Clerk of the House and the Secretary of the Senate.
|
||||
|
||||
They are not presented to the President for action.
|
||||
|
||||
Simple Resolutions
|
||||
------------------
|
||||
|
||||
A matter concerning the operation of either the House of Representatives or Senate
|
||||
alone is initiated by a simple resolution.
|
||||
|
||||
A resolution affecting the House of Representatives is designated “H.Res.” followed by its number.
|
||||
|
||||
They are not presented to the President for action.
|
||||
|
||||
(provider: congress_gov)
|
||||
start_date : Optional[date]
|
||||
Start date of the data, in YYYY-MM-DD format. Filters bills by the last updated date. (provider: congress_gov)
|
||||
end_date : Optional[date]
|
||||
End date of the data, in YYYY-MM-DD format. Filters bills by the last updated date. (provider: congress_gov)
|
||||
limit : Optional[int]
|
||||
The number of data entries to return. When None, default sets to 100 (max 250). Set to 0 for no limit (must be used with 'bill_type' and 'congress'). (provider: congress_gov)
|
||||
offset : Optional[int]
|
||||
The starting record returned. 0 is the first record. (provider: congress_gov)
|
||||
sort_by : Literal['asc', 'desc']
|
||||
Sort by update date. Default is latest first. (provider: congress_gov)
|
||||
|
||||
Returns
|
||||
-------
|
||||
OBBject
|
||||
results : list[CongressBills]
|
||||
Serializable results.
|
||||
provider : Optional[str]
|
||||
Provider name.
|
||||
warnings : Optional[list[Warning_]]
|
||||
list of warnings.
|
||||
chart : Optional[Chart]
|
||||
Chart object.
|
||||
extra : Dict[str, Any]
|
||||
Extra info.
|
||||
|
||||
CongressBills
|
||||
-------------
|
||||
update_date : Optional[date]
|
||||
The date the bill was last updated. (provider: congress_gov)
|
||||
latest_action_date : Optional[date]
|
||||
The date of the latest action on the bill. (provider: congress_gov)
|
||||
bill_url : Optional[str]
|
||||
Base URL to the bill for the congress.gov API. (provider: congress_gov)
|
||||
congress : Optional[int]
|
||||
The congress session number. (provider: congress_gov)
|
||||
bill_number : Optional[int]
|
||||
The bill number. (provider: congress_gov)
|
||||
origin_chamber : Optional[str]
|
||||
The chamber where the bill originated. (provider: congress_gov)
|
||||
origin_chamber_code : Optional[str]
|
||||
The chamber code where the bill originated. (provider: congress_gov)
|
||||
bill_type : Optional[str]
|
||||
The type of bill (e.g., HR, S). (provider: congress_gov)
|
||||
title : Optional[str]
|
||||
The title of the bill. (provider: congress_gov)
|
||||
latest_action : Optional[str]
|
||||
Latest action information for the bill. (provider: congress_gov)
|
||||
update_date_including_text : Optional[datetime]
|
||||
The date and time the bill text was last updated. (provider: congress_gov)
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb import obb
|
||||
>>> obb.uscongress.bills(provider='congress_gov')
|
||||
>>> obb.uscongress.bills(start_date='2025-01-01', end_date='2025-01-31', provider='congress_gov')
|
||||
>>> # Get all bills of type 's' (Senate) for the 118th Congress.
|
||||
>>> obb.uscongress.bills(bill_type='s', congress=118, limit=0, provider='congress_gov')
|
||||
""" # noqa: E501
|
||||
|
||||
return self._run(
|
||||
"/uscongress/bills",
|
||||
**filter_inputs(
|
||||
provider_choices={
|
||||
"provider": self._get_provider(
|
||||
provider,
|
||||
"uscongress.bills",
|
||||
("congress_gov",),
|
||||
)
|
||||
},
|
||||
standard_params={},
|
||||
extra_params=kwargs,
|
||||
info={
|
||||
"congress": {
|
||||
"congress_gov": {"x-widget_config": {"type": "number"}}
|
||||
},
|
||||
"bill_type": {
|
||||
"congress_gov": {
|
||||
"x-widget_config": {
|
||||
"options": [
|
||||
{"label": "House Bill", "value": "hr"},
|
||||
{"label": "Senate Bill", "value": "s"},
|
||||
{
|
||||
"label": "House Joint Resolution",
|
||||
"value": "hjres",
|
||||
},
|
||||
{
|
||||
"label": "Senate Joint Resolution",
|
||||
"value": "sjres",
|
||||
},
|
||||
{
|
||||
"label": "House Concurrent Resolution",
|
||||
"value": "hconres",
|
||||
},
|
||||
{
|
||||
"label": "Senate Concurrent Resolution",
|
||||
"value": "sconres",
|
||||
},
|
||||
{
|
||||
"label": "House Simple Resolution",
|
||||
"value": "hres",
|
||||
},
|
||||
{
|
||||
"label": "Senate Simple Resolution",
|
||||
"value": "sres",
|
||||
},
|
||||
],
|
||||
"value": None,
|
||||
"style": {"popupWidth": 300},
|
||||
"paramName": "bill_type",
|
||||
"label": "Bill Type",
|
||||
}
|
||||
}
|
||||
},
|
||||
"offset": {"congress_gov": {"x-widget_config": {"type": "number"}}},
|
||||
},
|
||||
),
|
||||
)
|
||||
132
openbb_platform/providers/congress_gov/README.md
vendored
Normal file
132
openbb_platform/providers/congress_gov/README.md
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
# Congress.gov Provider
|
||||
|
||||
This provider integrates with the Congress.gov API to provide access to U.S. legislative data and text.
|
||||
|
||||
## Features
|
||||
|
||||
### Congress Bills
|
||||
|
||||
- Fetch lists of bills from the U.S. Congress.
|
||||
- Filter by congress session, bill type, date range.
|
||||
|
||||
### Bill Summaries & Metadata
|
||||
|
||||
- Get summaries of, and metadata for, a specific bill.
|
||||
- Lists all actions, sponsors, committees, related bills, and titles.
|
||||
- Returned as both a raw JSON object and formatted Markdown text.
|
||||
|
||||
### Bill Text URLs and Downloads
|
||||
|
||||
- Get URLs for different versions and file formats.
|
||||
- Download full bill text as a base64-encoded string.
|
||||
|
||||
### OpenBB Workspace Application
|
||||
|
||||
With this extension installed, along with `openbb-platform-api`,
|
||||
an OpenBB Workspace App is added to your backend.
|
||||
|
||||
The application provides a PDF viewer, bill summaries and metadata as rendered Markdown,
|
||||
and a linked query tool for finding and reading legislation.
|
||||
|
||||
## Installation
|
||||
|
||||
This provider is part of the OpenBB Platform. Install it using:
|
||||
|
||||
```bash
|
||||
pip install openbb-congress-gov
|
||||
```
|
||||
|
||||
The Workspace Application can be launched as a standalone, with only `openbb-congress-gov` and `openbb-platform-api` installed. Launch it from the terminal command line with:
|
||||
|
||||
```sh
|
||||
openbb-api
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Congress.gov API Key
|
||||
|
||||
To use the Congress Bills and Bill Summaries endpoints, you need a Congress.gov API key:
|
||||
|
||||
1. Go to https://api.congress.gov/sign-up/
|
||||
2. Fill out the registration form
|
||||
3. Agree to the terms of service
|
||||
4. You will receive an API key via email
|
||||
|
||||
The API key is free and provides access to all Congress.gov data.
|
||||
|
||||
### Entering Credentials
|
||||
|
||||
Add the credential into OpenBB Platform from any of:
|
||||
|
||||
- Entry in `user_settings.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"credentials" : {
|
||||
"congress_gov_api_key": "YOUR KEY"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Set environment variable
|
||||
|
||||
```env
|
||||
CONGRESS_GOV_API_KEY = "YOUR KEY"
|
||||
```
|
||||
|
||||
- Add to the current session only
|
||||
|
||||
```python
|
||||
from openbb import obb
|
||||
|
||||
obb.user.credentials.congress_gov_api_key = "YOUR KEY"
|
||||
```
|
||||
|
||||
## Coverage
|
||||
|
||||
All endpoints are under the `obb.uscongress` path:
|
||||
|
||||
```python
|
||||
In [1]: from openbb import obb
|
||||
In [2]: obb.uscongress
|
||||
Out[2]:
|
||||
/uscongress
|
||||
bill_info
|
||||
bill_text
|
||||
bill_text_urls
|
||||
bills
|
||||
```
|
||||
|
||||
### Bill Text
|
||||
|
||||
The `bill_text` endpoint is a POST request from the API, and expects a dictionary in the body of the request.
|
||||
|
||||
```json
|
||||
{
|
||||
"urls": ["https://url-to-PDF-document"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Fetching Recent Bills
|
||||
|
||||
```python
|
||||
from openbb import obb
|
||||
|
||||
# Get the 10 most recently updated bills
|
||||
bills = obb.uscongress.bills(limit=10)
|
||||
```
|
||||
|
||||
### Getting Bill Summaries
|
||||
|
||||
Reference individual bills by either their base URL (returned in the `obb.uscongress.bills` response),
|
||||
or by the concatenated bill number.
|
||||
|
||||
```python
|
||||
bill_info = obb.uscongress.bill_info(bill_url="119/hr/1")
|
||||
```
|
||||
|
||||
See the function signatures and docstrings for parameters and detailed descriptions.
|
||||
1
openbb_platform/providers/congress_gov/__init__.py
Normal file
1
openbb_platform/providers/congress_gov/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""The Congress.gov provider."""
|
||||
@@ -0,0 +1,29 @@
|
||||
"""Congress.gov Provider Module."""
|
||||
|
||||
from openbb_congress_gov.models.bill_info import CongressBillInfoFetcher
|
||||
from openbb_congress_gov.models.bill_text import CongressBillTextFetcher
|
||||
from openbb_congress_gov.models.congress_bills import CongressBillsFetcher
|
||||
from openbb_core.provider.abstract.provider import Provider
|
||||
|
||||
congress_gov_provider = Provider(
|
||||
name="congress_gov",
|
||||
website="https://api.congress.gov",
|
||||
description="""The Congress.gov API provides legislative data from the U.S.
|
||||
Congress, including bills, summaries, and related information. The Federal
|
||||
Register API provides access to presidential documents and regulations.""",
|
||||
credentials=["api_key"],
|
||||
fetcher_dict={
|
||||
"CongressBills": CongressBillsFetcher,
|
||||
"CongressBillInfo": CongressBillInfoFetcher,
|
||||
"CongressBillText": CongressBillTextFetcher,
|
||||
},
|
||||
repr_name="Congress.gov",
|
||||
instructions="""To get a Congress.gov API key:
|
||||
|
||||
1. Go to https://api.congress.gov/sign-up/
|
||||
2. Fill out the registration form with your information
|
||||
3. Agree to the terms of service
|
||||
4. You will receive an API key via email
|
||||
|
||||
The API key is free and provides access to all Congress.gov data.""",
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
"""Congress.gov Models."""
|
||||
@@ -0,0 +1,386 @@
|
||||
"""Congress Gov Bills Text Model."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
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 pydantic import ConfigDict, Field
|
||||
|
||||
|
||||
class CongressBillInfoQueryParams(QueryParams):
|
||||
"""Congress Gov Bills Info Query."""
|
||||
|
||||
__json_schema_extra__ = {
|
||||
"bill_url": {
|
||||
"x-widget_config": {
|
||||
"label": "Bill URL",
|
||||
"description": "Enter a base URL of a bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?')."
|
||||
+ " Alternatively, you can enter a bill number (e.g., '119/s/1947')."
|
||||
+ " Create a group on the 'Bill URL' field of the 'Congressional Bills' widget"
|
||||
+ " and click on the cell to view summary and metadata.",
|
||||
"value": "119/hr/1",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
bill_url: str = Field(
|
||||
description="Enter a base URL of a bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?format=json')."
|
||||
+ " Alternatively, you can enter a bill number (e.g., '119/s/1947')."
|
||||
)
|
||||
|
||||
|
||||
class CongressBillInfoData(Data):
|
||||
"""Congress Gov Bills Info Data."""
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"x-widget_config": {
|
||||
"$.type": "markdown",
|
||||
"$.name": "Congressional Bill Info",
|
||||
"$.description": "Metadata and summary info for a U.S. Congressional Bill.",
|
||||
"$.category": "Government",
|
||||
"$.subCategory": "Congress",
|
||||
"$.searchCategory": "Government",
|
||||
"$.data": {
|
||||
"dataKey": "results.markdown_content",
|
||||
},
|
||||
"$.refetchInterval": False,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
markdown_content: str = Field(
|
||||
description="Aggregated metadata for the bill in Markdown format."
|
||||
)
|
||||
raw_data: dict[str, Any] = Field(
|
||||
description="Raw JSON data from the collected bill information.",
|
||||
json_schema_extra={
|
||||
"x-widget_config": {
|
||||
"exclude": True,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class CongressBillInfoFetcher(
|
||||
Fetcher[CongressBillInfoQueryParams, CongressBillInfoData]
|
||||
):
|
||||
"""Congress Gov Bills Info Fetcher."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: dict[str, Any]) -> CongressBillInfoQueryParams:
|
||||
"""Transform the query parameters into a CongressBillInfoQueryParams object."""
|
||||
return CongressBillInfoQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
async def aextract_data(
|
||||
query: CongressBillInfoQueryParams,
|
||||
credentials: Optional[dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> dict:
|
||||
"""Extract data from the query."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_core.provider.utils.helpers import amake_request
|
||||
|
||||
api_key = credentials.get("congress_gov_api_key", "") if credentials else ""
|
||||
bill_url = query.bill_url
|
||||
if bill_url[0].isnumeric() or (bill_url[0] == "/" and bill_url[1].isnumeric()):
|
||||
# If the bill URL starts with a number, assume it's a congress number and construct the URL
|
||||
bill_url = (
|
||||
"https://api.congress.gov/v3/bill/"
|
||||
+ f"{bill_url[1:] if bill_url[0] == '/' else bill_url}?format=json"
|
||||
)
|
||||
|
||||
url = bill_url + "&api_key=" + api_key
|
||||
base_info: dict = await amake_request(url) # type: ignore
|
||||
base_info = base_info.get("bill", {})
|
||||
cosponsors = base_info.get("cosponsors", {})
|
||||
|
||||
if cosponsors.get("count", 0) > 0:
|
||||
cosponsors_url = (
|
||||
base_info.get("cosponsors", {}).get("url", "") + "&api_key=" + api_key
|
||||
)
|
||||
cosponsors_response: dict = await amake_request(cosponsors_url) # type: ignore
|
||||
cosponsors_list = cosponsors_response.get("cosponsors", [])
|
||||
base_info["cosponsors"] = cosponsors_list
|
||||
|
||||
subjects = base_info.get("subjects", {})
|
||||
|
||||
if subjects.get("count", 0) > 0:
|
||||
subjects_url = (
|
||||
base_info.get("subjects", {}).get("url", "") + "&api_key=" + api_key
|
||||
)
|
||||
subjects_response: dict = await amake_request(subjects_url) # type: ignore
|
||||
subjects_list = subjects_response.get("subjects", {}).get(
|
||||
"legislativeSubjects", []
|
||||
)
|
||||
base_info["subjects"] = subjects_list
|
||||
|
||||
summaries = base_info.get("summaries", {})
|
||||
|
||||
if summaries.get("count", 0) > 0:
|
||||
summaries_url = (
|
||||
base_info.get("summaries", {}).get("url", "") + "&api_key=" + api_key
|
||||
)
|
||||
summaries_response: dict = await amake_request(summaries_url) # type: ignore
|
||||
summaries_list = summaries_response.get("summaries", [])
|
||||
|
||||
if summaries_list:
|
||||
base_info["summaries"] = summaries_list
|
||||
|
||||
committees = base_info.get("committees", {})
|
||||
|
||||
if committees.get("count", 0) > 0:
|
||||
committees_url = (
|
||||
base_info.get("committees", {}).get("url", "") + "&api_key=" + api_key
|
||||
)
|
||||
committees_response: dict = await amake_request(committees_url) # type: ignore
|
||||
committees_list = committees_response.get("committees", [])
|
||||
|
||||
if committees_list:
|
||||
base_info["committees"] = committees_list
|
||||
|
||||
actions = base_info.get("actions", {})
|
||||
|
||||
if actions.get("count", 0) > 0:
|
||||
actions_url = (
|
||||
base_info.get("actions", {}).get("url", "") + "&api_key=" + api_key
|
||||
)
|
||||
actions_response: dict = await amake_request(actions_url) # type: ignore
|
||||
actions_list = actions_response.get("actions", [])
|
||||
|
||||
if actions_list:
|
||||
base_info["actions"] = actions_list
|
||||
|
||||
titles = base_info.get("titles", {})
|
||||
|
||||
if titles.get("count", 0) > 0:
|
||||
titles_url = (
|
||||
base_info.get("titles", {}).get("url", "") + "&api_key=" + api_key
|
||||
)
|
||||
titles_response: dict = await amake_request(titles_url) # type: ignore
|
||||
titles_list = titles_response.get("titles", [])
|
||||
|
||||
if titles_list:
|
||||
base_info["titles"] = titles_list
|
||||
|
||||
related_bills = base_info.get("relatedBills", {})
|
||||
|
||||
if related_bills.get("count", 0) > 0:
|
||||
related_bills_url = (
|
||||
base_info.get("relatedBills", {}).get("url", "") + "&api_key=" + api_key
|
||||
)
|
||||
related_bills_response: dict = await amake_request(related_bills_url) # type: ignore
|
||||
related_bills_list = related_bills_response.get("relatedBills", [])
|
||||
|
||||
if related_bills_list:
|
||||
base_info["relatedBills"] = related_bills_list
|
||||
|
||||
return base_info
|
||||
|
||||
@staticmethod
|
||||
def transform_data( # pylint: disable=R0912,R0914 # noqa: PLR0912,PLR0914
|
||||
query: CongressBillInfoQueryParams,
|
||||
data: dict,
|
||||
**kwargs: Any,
|
||||
) -> CongressBillInfoData:
|
||||
"""Transform the data into the model."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
import re
|
||||
|
||||
# Regex to strip HTML tags
|
||||
html_tag_regex = re.compile(r"<[^>]+>")
|
||||
|
||||
# Regex to match HTML list items
|
||||
li_regex = re.compile(r"<li[^>]*>(.*?)</li>", re.DOTALL | re.IGNORECASE)
|
||||
ul_regex = re.compile(r"<ul[^>]*>(.*?)</ul>", re.DOTALL | re.IGNORECASE)
|
||||
ol_regex = re.compile(r"<ol[^>]*>(.*?)</ol>", re.DOTALL | re.IGNORECASE)
|
||||
strong_tag_regex = re.compile(
|
||||
r"<strong>(.*?)</strong>", re.DOTALL | re.IGNORECASE
|
||||
)
|
||||
p_tag_regex = re.compile(r"<p[^>]*>(.*?)</p>", re.DOTALL | re.IGNORECASE)
|
||||
|
||||
def html_to_markdown(text: str) -> str:
|
||||
"""Convert HTML content to Markdown format."""
|
||||
# Extract the first <strong> tag inside a <p> as the title, if present
|
||||
title = ""
|
||||
paragraphs = p_tag_regex.findall(text)
|
||||
if paragraphs:
|
||||
first_p = paragraphs[0]
|
||||
strong_match = strong_tag_regex.search(first_p)
|
||||
if strong_match:
|
||||
title = strong_match.group(1).strip()
|
||||
# Remove the first <p><strong>...</strong></p> from text
|
||||
text = text.replace(f"<p><strong>{title}</strong></p>", "", 1)
|
||||
text = text.lstrip()
|
||||
if text.startswith(title):
|
||||
text = text[len(title) :].lstrip()
|
||||
|
||||
# Convert unordered lists
|
||||
def ul_replacer(match):
|
||||
"""Replace <ul> with Markdown format."""
|
||||
items = li_regex.findall(match.group(1))
|
||||
return "\n" + "\n".join(
|
||||
f"- {html_tag_regex.sub('', item).strip()}" for item in items
|
||||
)
|
||||
|
||||
# Convert ordered lists
|
||||
def ol_replacer(match):
|
||||
"""Replace <ol> with Markdown format."""
|
||||
items = li_regex.findall(match.group(1))
|
||||
return "\n" + "\n".join(
|
||||
f"1. {html_tag_regex.sub('', item).strip()}" for item in items
|
||||
)
|
||||
|
||||
text = ul_regex.sub(ul_replacer, text)
|
||||
text = ol_regex.sub(ol_replacer, text)
|
||||
text = html_tag_regex.sub("", text)
|
||||
text = text.strip()
|
||||
|
||||
if title:
|
||||
return f"**{title}**\n\n{text.replace(title.strip(), '').strip()}"
|
||||
|
||||
return text
|
||||
|
||||
markdown_content = f"""# {data.get('title')}
|
||||
|
||||
- **Congress**: {data.get('congress')}
|
||||
- **Bill Number**: {data.get('number')}
|
||||
- **Type**: {data.get('type')}
|
||||
- **Chamber**: {data.get('originChamber')}
|
||||
- **Introduced**: {data.get('introducedDate')}
|
||||
- **Last Updated**: {data.get('updateDate', {})}
|
||||
- **Last Action**: {data.get('latestAction', {}).get('actionDate')} - {data.get('latestAction', {}).get('text', '')}
|
||||
"""
|
||||
policy_area = data.get("policyArea", {}).get("name", "")
|
||||
if policy_area:
|
||||
markdown_content += f"\n- **Policy Area**: {policy_area}"
|
||||
|
||||
related_bills = data.get("relatedBills", [])
|
||||
if related_bills:
|
||||
markdown_content += "\n\n### Related Bills\n\n"
|
||||
for bill in related_bills:
|
||||
bill_number = bill.get("number", "")
|
||||
bill_type = bill.get("type", "")
|
||||
bill_congress = bill.get("congress", "")
|
||||
bill_title = bill.get("title", "")
|
||||
latest_action = bill.get("latestAction", {})
|
||||
markdown_content += (
|
||||
f"\n- **{bill_congress} {bill_type} {bill_number}: {bill_title}**\n"
|
||||
)
|
||||
if latest_action:
|
||||
action_date = latest_action.get("actionDate", "")
|
||||
action_text = latest_action.get("text", "")
|
||||
markdown_content += (
|
||||
f" - **Last Action**: {action_date} - {action_text}\n"
|
||||
)
|
||||
|
||||
relationship = bill.get("relationshipDetails", [])
|
||||
|
||||
if relationship:
|
||||
for rel in relationship:
|
||||
rel_type = rel.get("type", "")
|
||||
rel_description = rel.get("identifiedBy", "")
|
||||
markdown_content += f"\n - **Relationship**: {rel_type}\n"
|
||||
markdown_content += (
|
||||
f" - **Identified By**: {rel_description}\n"
|
||||
)
|
||||
|
||||
summaries = data.get("summaries", [])
|
||||
if summaries:
|
||||
markdown_content += "\n\n### Summaries\n\n"
|
||||
for summary in summaries:
|
||||
summary_text = html_to_markdown(summary.get("text", ""))
|
||||
markdown_content += f"\n{summary_text}\n\n"
|
||||
|
||||
subjects = data.get("subjects", [])
|
||||
if subjects:
|
||||
markdown_content += "\n\n### Subjects\n\n"
|
||||
for subject in subjects:
|
||||
markdown_content += f"\n - **{subject.get('name', '')}** ({subject.get('updateDate', '')})"
|
||||
|
||||
sponsors = data.get("sponsors", [])
|
||||
if sponsors:
|
||||
markdown_content += "\n\n### Sponsors\n\n"
|
||||
for sponsor in sponsors:
|
||||
markdown_content += f"\n - **{sponsor.get('fullName', '')}**"
|
||||
|
||||
cosponsors = data.get("cosponsors", [])
|
||||
if cosponsors:
|
||||
markdown_content += "\n\n### Cosponsors\n\n"
|
||||
for cosponsor in cosponsors:
|
||||
cosponsor_name = cosponsor.get("fullName", "")
|
||||
is_original = cosponsor.get("isOriginalCosponsor", False)
|
||||
if is_original:
|
||||
cosponsor_name += " (Original Cosponsor)"
|
||||
markdown_content += f"\n - **{cosponsor_name}** ({cosponsor.get('sponsorshipDate', '')})"
|
||||
|
||||
titles = data.get("titles", [])
|
||||
if titles:
|
||||
markdown_content += "\n\n### Titles\n\n"
|
||||
for title in titles:
|
||||
title_text = title.get("title", "")
|
||||
markdown_content += f"\n- **{title_text}**\n"
|
||||
title_type = title.get("type", "")
|
||||
|
||||
if title_type:
|
||||
markdown_content += f" - **Type**: {title_type}\n"
|
||||
|
||||
chamber = title.get("chamberName", "")
|
||||
|
||||
if chamber:
|
||||
markdown_content += f" - **Chamber**: {chamber}\n"
|
||||
|
||||
bill_text_version_name = title.get("billTextVersionName", "")
|
||||
|
||||
if bill_text_version_name:
|
||||
markdown_content += (
|
||||
f" - **Bill Text Version**: {bill_text_version_name}\n"
|
||||
)
|
||||
|
||||
markdown_content += (
|
||||
f" - **Last Updated**: {title.get('updateDate', '')}\n"
|
||||
)
|
||||
|
||||
committees = data.get("committees", [])
|
||||
if committees:
|
||||
markdown_content += "\n\n### Committees\n\n"
|
||||
for committee in committees:
|
||||
committee_name = committee.get("name", "")
|
||||
committee_chamber = committee.get("chamber", "")
|
||||
|
||||
if committee_chamber:
|
||||
markdown_content += f"- **{committee_name} - {committee_chamber} ({committee.get('type')}) **\n"
|
||||
else:
|
||||
markdown_content += f"- **{committee_name}**\n"
|
||||
|
||||
activities = committee.get("activities", [])
|
||||
if activities:
|
||||
for activity in activities:
|
||||
markdown_content += f" - {activity.get('name', '')} ({activity.get('date', '')})\n"
|
||||
|
||||
subcommittees = committee.get("subcommittees", [])
|
||||
if subcommittees:
|
||||
markdown_content += " - **Subcommittees**:\n"
|
||||
for subcommittee in subcommittees:
|
||||
subcommittee_name = subcommittee.get("name", "")
|
||||
markdown_content += f" - **{subcommittee_name}**\n"
|
||||
activities = subcommittee.get("activities", [])
|
||||
if activities:
|
||||
for activity in activities:
|
||||
markdown_content += f" - {activity.get('name', '')} ({activity.get('date', '')})\n"
|
||||
|
||||
actions = data.get("actions", [])
|
||||
if actions:
|
||||
markdown_content += "\n\n### Actions\n\n"
|
||||
for action in actions:
|
||||
action_date = action.get("actionDate", "")
|
||||
action_text = action.get("text", "")
|
||||
action_type = action.get("type", "")
|
||||
markdown_content += f"\n- **{action_date}**: ({action_type})"
|
||||
markdown_content += f"\n - {action_text}"
|
||||
|
||||
return CongressBillInfoData(markdown_content=markdown_content, raw_data=data)
|
||||
@@ -0,0 +1,144 @@
|
||||
"""Congress Gov Bills Text Model."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
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 pydantic import Field
|
||||
|
||||
|
||||
class CongressBillTextQueryParams(QueryParams):
|
||||
"""Congress Gov Bills Text Query."""
|
||||
|
||||
__json_schema_extra__ = {
|
||||
"urls": {
|
||||
"multiple_items_allowed": True,
|
||||
}
|
||||
}
|
||||
# This field is typed this way to allow the Python interface and API
|
||||
# to easily accept the parameter.
|
||||
# In the API, the body can be a string, a list of URLs or a dictionary with a "urls" key.
|
||||
# Workspace will send the body as a dictionary with a "urls" key.
|
||||
urls: Union[str, list[str], dict[str, list[str]]] = Field(
|
||||
description="List of direct bill URLs to download.",
|
||||
kw_only=True,
|
||||
)
|
||||
|
||||
|
||||
class CongressBillTextData(Data):
|
||||
"""Congress Gov Bills Text Data."""
|
||||
|
||||
error_type: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Error type if any error occurs during the download.",
|
||||
)
|
||||
content: str = Field(
|
||||
description="Base64-encoded PDF document.",
|
||||
)
|
||||
filename: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The filename of the downloaded PDF.",
|
||||
)
|
||||
data_format: Optional[dict[str, str]] = Field(
|
||||
default=None,
|
||||
description="Data format information, including data type and filename.",
|
||||
)
|
||||
|
||||
|
||||
class CongressBillTextFetcher(
|
||||
Fetcher[CongressBillTextQueryParams, list[CongressBillTextData]]
|
||||
):
|
||||
"""Congress Gov Bills Text Fetcher."""
|
||||
|
||||
require_credentials = False
|
||||
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
params: dict[str, Any],
|
||||
) -> CongressBillTextQueryParams:
|
||||
"""Transform the query parameters."""
|
||||
|
||||
return CongressBillTextQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
async def aextract_data(
|
||||
query: CongressBillTextQueryParams,
|
||||
credentials: Optional[dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> list:
|
||||
"""Extract data from the query."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
import base64 # noqa
|
||||
from io import BytesIO
|
||||
from openbb_core.provider.utils.helpers import make_request
|
||||
|
||||
urls = (
|
||||
query.urls.get("urls", [])
|
||||
if isinstance(query.urls, dict)
|
||||
else (query.urls if isinstance(query.urls, list) else query.urls.split(","))
|
||||
)
|
||||
results: list = []
|
||||
|
||||
for url in urls:
|
||||
filename = url.split("/")[-1]
|
||||
|
||||
if "congress.gov" not in url.strip():
|
||||
results.append(
|
||||
{
|
||||
"error_type": "invalid_url",
|
||||
"content": f"Invalid URL: {url}. Must be a valid Congress.gov API URL.",
|
||||
"filename": filename,
|
||||
}
|
||||
)
|
||||
continue
|
||||
try:
|
||||
response = make_request(url)
|
||||
response.raise_for_status()
|
||||
datatype = filename.split(".")[-1].lower()
|
||||
|
||||
if datatype == "pdf":
|
||||
pdf_content = base64.b64encode(
|
||||
BytesIO(response.content).read()
|
||||
).decode("utf-8")
|
||||
results.append(
|
||||
{
|
||||
"content": pdf_content,
|
||||
"data_format": {
|
||||
"data_type": "pdf",
|
||||
"filename": url.split("/")[-1],
|
||||
},
|
||||
}
|
||||
)
|
||||
else:
|
||||
results.append(
|
||||
{
|
||||
"content": response.text,
|
||||
"data_format": {
|
||||
"data_type": "text",
|
||||
"filename": filename,
|
||||
},
|
||||
}
|
||||
)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
results.append(
|
||||
{
|
||||
"error_type": "download_error",
|
||||
"content": f"{exc.__class__.__name__}: {exc.args[0]}",
|
||||
"filename": url.split("/")[-1],
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: CongressBillTextQueryParams,
|
||||
data: list,
|
||||
**kwargs: Any,
|
||||
) -> list[CongressBillTextData]:
|
||||
"""Transform the extracted data into the desired format."""
|
||||
return [CongressBillTextData(**item) for item in data]
|
||||
@@ -0,0 +1,326 @@
|
||||
"""Congress Bills Model."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Any, Literal, Optional
|
||||
|
||||
from openbb_congress_gov.utils.constants import (
|
||||
BillTypes,
|
||||
base_url,
|
||||
bill_type_docstring,
|
||||
bill_type_options,
|
||||
)
|
||||
from openbb_congress_gov.utils.helpers import year_to_congress
|
||||
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 pydantic import ConfigDict, Field, model_validator
|
||||
|
||||
|
||||
class CongressBillsQueryParams(QueryParams):
|
||||
"""Congress Bills Query Parameters."""
|
||||
|
||||
__json_schema_extra__ = {
|
||||
"bill_type": {
|
||||
"x-widget_config": {
|
||||
"options": bill_type_options,
|
||||
"value": None,
|
||||
"style": {"popupWidth": 300},
|
||||
"paramName": "bill_type",
|
||||
"label": "Bill Type",
|
||||
},
|
||||
},
|
||||
"offset": {
|
||||
"x-widget_config": {
|
||||
"type": "number",
|
||||
}
|
||||
},
|
||||
"congress": {
|
||||
"x-widget_config": {
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
}
|
||||
congress: Optional[int] = Field(
|
||||
default=None,
|
||||
description="Congress number (e.g., 118 for the 118th Congress)."
|
||||
+ " The 103rd Congress started in 1993,"
|
||||
+ " which is the earliest date supporting full text versions."
|
||||
+ " Each Congress spans two years,"
|
||||
+ " starting in odd-numbered years.",
|
||||
)
|
||||
bill_type: Optional[str] = Field(
|
||||
default=None,
|
||||
description=bill_type_docstring,
|
||||
examples=["hr", "s", "hjres", "sjres", "hconres", "sconres", "hres", "sres"],
|
||||
)
|
||||
start_date: Optional[dateType] = Field(
|
||||
default=None,
|
||||
description=QUERY_DESCRIPTIONS.get("start_date", "")
|
||||
+ " Filters bills by the last updated date.",
|
||||
)
|
||||
end_date: Optional[dateType] = Field(
|
||||
default=None,
|
||||
description=QUERY_DESCRIPTIONS.get("end_date", "")
|
||||
+ " Filters bills by the last updated date.",
|
||||
)
|
||||
limit: Optional[int] = Field(
|
||||
default=None,
|
||||
description=QUERY_DESCRIPTIONS.get("limit", "")
|
||||
+ " When None, default sets to 100 (max 250)."
|
||||
+ " Set to 0 for no limit (must be used with 'bill_type' and 'congress')."
|
||||
+ " Setting to 0 will nullify the start_date, end_date, and offset parameters.",
|
||||
)
|
||||
offset: Optional[int] = Field(
|
||||
default=None, description="The starting record returned. 0 is the first record."
|
||||
)
|
||||
sort_by: Literal["asc", "desc"] = Field(
|
||||
default="desc", description="Sort by update date. Default is latest first."
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
@classmethod
|
||||
def validate_query(cls, values):
|
||||
"""Validate the query parameters."""
|
||||
if values.bill_type is not None and values.bill_type not in BillTypes:
|
||||
raise OpenBBError(
|
||||
ValueError(
|
||||
f"Invalid bill_type: {values.bill_type}. Must be one of: {', '.join(BillTypes)}."
|
||||
)
|
||||
)
|
||||
if values.limit == 0 and values.bill_type is None:
|
||||
raise OpenBBError(
|
||||
ValueError(
|
||||
"'limit' cannot be set to 0 without 'bill_type' and 'congress'."
|
||||
)
|
||||
)
|
||||
return values
|
||||
|
||||
|
||||
class CongressBillsData(Data):
|
||||
"""Congress Bills Data."""
|
||||
|
||||
__alias_dict__ = {
|
||||
"bill_type": "type",
|
||||
"bill_number": "number",
|
||||
"bill_url": "url",
|
||||
}
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"x-widget_config": {
|
||||
"$.name": "Congressional Bills",
|
||||
"$.category": "Government",
|
||||
"$.subCategory": "Congress",
|
||||
"$.searchCategory": "Government",
|
||||
"$.description": "Current and historical U.S. Congressional Bills.",
|
||||
"$.params": [
|
||||
{
|
||||
"paramName": "bill_url",
|
||||
"label": "Bill URL",
|
||||
"description": "Ghost parameter to group by the bill URL."
|
||||
+ " Create a group and use the 'Congressional Bill Viewer' widget to view the bill."
|
||||
+ " The 'Congressional Bill Info' widget can also be grouped by this field to provide"
|
||||
+ " a comprehensive overview of the bill.",
|
||||
"type": "text",
|
||||
"value": None,
|
||||
"show": True,
|
||||
},
|
||||
],
|
||||
"$.refetchInterval": False,
|
||||
},
|
||||
}
|
||||
)
|
||||
update_date: dateType = Field(description="The date the bill was last updated.")
|
||||
latest_action_date: Optional[dateType] = Field(
|
||||
default=None, description="The date of the latest action on the bill."
|
||||
)
|
||||
bill_url: str = Field(
|
||||
description="Base URL to the bill for the congress.gov API.",
|
||||
json_schema_extra={
|
||||
"x-widget_config": {
|
||||
"headerTooltip": "Create a group for the 'bill_url' parameter and then"
|
||||
+ " click in the cell to change the documents in the 'Congressional Bill Viewer'"
|
||||
+ " or 'Congression Bill Info widgets.",
|
||||
"renderFn": "cellOnClick",
|
||||
"renderFnParams": {
|
||||
"actionType": "groupBy",
|
||||
"groupByParamName": "bill_url",
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
congress: int = Field(
|
||||
description="The congress session number.",
|
||||
json_schema_extra={
|
||||
"x-widget_config": {"formatterFn": "none"},
|
||||
},
|
||||
)
|
||||
bill_number: int = Field(
|
||||
description="The bill number.",
|
||||
json_schema_extra={
|
||||
"x-widget_config": {"formatterFn": "none"},
|
||||
},
|
||||
)
|
||||
origin_chamber: str = Field(description="The chamber where the bill originated.")
|
||||
origin_chamber_code: str = Field(
|
||||
description="The chamber code where the bill originated.",
|
||||
json_schema_extra={
|
||||
"x-widget_config": {
|
||||
"hide": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
bill_type: str = Field(
|
||||
description="The type of bill (e.g., HR, S).",
|
||||
)
|
||||
title: str = Field(description="The title of the bill.")
|
||||
latest_action: Optional[str] = Field(
|
||||
default=None, description="Latest action information for the bill."
|
||||
)
|
||||
update_date_including_text: Optional[datetime] = Field(
|
||||
default=None,
|
||||
description="The date and time the bill text was last updated.",
|
||||
json_schema_extra={"x-widget_config": {"label": "Text Update Date"}},
|
||||
)
|
||||
|
||||
|
||||
class CongressBillsFetcher(
|
||||
Fetcher[
|
||||
CongressBillsQueryParams,
|
||||
list[CongressBillsData],
|
||||
]
|
||||
):
|
||||
"""Transform the query, extract and transform the data from the Congress API."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: dict[str, Any]) -> CongressBillsQueryParams:
|
||||
"""Transform the query params."""
|
||||
return CongressBillsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
async def aextract_data(
|
||||
query: CongressBillsQueryParams,
|
||||
credentials: Optional[dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> list:
|
||||
"""Extract data from the Congress API."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_core.provider.utils.helpers import amake_request # noqa
|
||||
from openbb_congress_gov.utils.helpers import (
|
||||
get_all_bills_by_type,
|
||||
)
|
||||
|
||||
api_key = credentials.get("congress_gov_api_key") if credentials else ""
|
||||
|
||||
# Add congress number and bill type to the path parameters where required.
|
||||
# If a bill_type is provided, we need to give the path a congress number.
|
||||
# If no congress number is provided, we will use the current congress number
|
||||
# or the congress number derived from the start or end date, when supplied.
|
||||
|
||||
if (
|
||||
query.bill_type is not None
|
||||
and query.start_date is None
|
||||
and query.end_date is None
|
||||
and query.congress is None
|
||||
):
|
||||
congress = year_to_congress(datetime.now().year)
|
||||
elif (
|
||||
query.bill_type is not None
|
||||
and query.congress is None
|
||||
and query.start_date is not None
|
||||
):
|
||||
congress = year_to_congress(query.start_date.year)
|
||||
elif (
|
||||
query.bill_type is not None
|
||||
and query.congress is None
|
||||
and query.end_date is not None
|
||||
and query.start_date is None
|
||||
):
|
||||
congress = year_to_congress(query.end_date.year)
|
||||
elif (
|
||||
query.bill_type is not None
|
||||
and query.start_date is not None
|
||||
and query.end_date is not None
|
||||
and query.congress is None
|
||||
):
|
||||
congress_start = year_to_congress(query.start_date.year)
|
||||
congress = congress_start
|
||||
elif query.bill_type is not None and query.congress is None:
|
||||
congress = year_to_congress(datetime.now().year)
|
||||
else:
|
||||
congress = query.congress
|
||||
|
||||
if query.limit == 0 and query.bill_type is not None and congress is not None:
|
||||
# If limit is 0, we fetch all bills of the specified type for the congress
|
||||
return await get_all_bills_by_type(
|
||||
bill_type=query.bill_type,
|
||||
congress=congress,
|
||||
start_date=None,
|
||||
end_date=None,
|
||||
)
|
||||
url = (
|
||||
(
|
||||
f"{base_url}bill/{congress}/{query.bill_type}"
|
||||
if congress is not None and query.bill_type is not None
|
||||
else (
|
||||
f"{base_url}bill/{congress}"
|
||||
if congress is not None
|
||||
else f"{base_url}bill"
|
||||
)
|
||||
)
|
||||
+ (
|
||||
f"?fromDateTime={query.start_date.strftime('%Y-%m-%d') + 'T00:00:00Z'}"
|
||||
if query.start_date
|
||||
else ""
|
||||
)
|
||||
+ (
|
||||
f"&toDateTime={query.end_date.strftime('%Y-%m-%d') + 'T23:59:59Z'}"
|
||||
if query.end_date
|
||||
else ""
|
||||
)
|
||||
)
|
||||
url += (
|
||||
f"{'?' if '?' not in url else '&'}"
|
||||
+ f"limit={query.limit if query.limit is not None else '100'}"
|
||||
+ (f"&offset={query.offset if query.offset else '0'}")
|
||||
+ f"&sort=updateDate+{query.sort_by}"
|
||||
+ f"&format=json&api_key={api_key}"
|
||||
)
|
||||
|
||||
try:
|
||||
response = await amake_request(url=url)
|
||||
except Exception as e:
|
||||
# Handle exceptions
|
||||
raise OpenBBError(e) from e
|
||||
|
||||
return response.get("bills", []) # type: ignore
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: CongressBillsQueryParams, data: list, **kwargs: Any
|
||||
) -> list[CongressBillsData]:
|
||||
"""Transform raw data into CongressBillsData models."""
|
||||
transformed_data: list[CongressBillsData] = []
|
||||
|
||||
for bill in sorted(
|
||||
data,
|
||||
key=lambda x: x.get("latestAction", {}).get("actionDate")
|
||||
or x.get("updateDate"),
|
||||
reverse=query.sort_by == "desc",
|
||||
):
|
||||
latest_action = bill.pop("latestAction", {})
|
||||
|
||||
if latest_action:
|
||||
bill["latest_action_date"] = latest_action.get("actionDate")
|
||||
bill["latest_action"] = latest_action.get("text")
|
||||
|
||||
transformed_data.append(CongressBillsData(**bill))
|
||||
|
||||
return transformed_data
|
||||
0
openbb_platform/providers/congress_gov/openbb_congress_gov/py.typed
vendored
Normal file
0
openbb_platform/providers/congress_gov/openbb_congress_gov/py.typed
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"""US Congress Router."""
|
||||
@@ -0,0 +1,252 @@
|
||||
# pylint: disable=import-outside-toplevel,unused-argument
|
||||
"""US Congress Router."""
|
||||
|
||||
from fastapi.exceptions import HTTPException
|
||||
from openbb_core.app.model.command_context import CommandContext
|
||||
from openbb_core.app.model.example import APIEx
|
||||
from openbb_core.app.model.obbject import OBBject
|
||||
from openbb_core.app.provider_interface import (
|
||||
ExtraParams,
|
||||
ProviderChoices,
|
||||
StandardParams,
|
||||
)
|
||||
from openbb_core.app.query import Query as OpenBBQuery
|
||||
from openbb_core.app.router import Router
|
||||
from openbb_core.app.service.system_service import SystemService
|
||||
|
||||
router = Router(prefix="", description="Data connector to Congress.gov API.")
|
||||
api_prefix = SystemService().system_settings.api_settings.prefix
|
||||
|
||||
|
||||
@router.command(
|
||||
model="CongressBills",
|
||||
examples=[
|
||||
APIEx(parameters={"provider": "congress_gov"}),
|
||||
APIEx(
|
||||
parameters={
|
||||
"start_date": "2025-01-01",
|
||||
"end_date": "2025-01-31",
|
||||
"provider": "congress_gov",
|
||||
}
|
||||
),
|
||||
APIEx(
|
||||
description="Get all bills of type 's' (Senate) for the 118th Congress.",
|
||||
parameters={
|
||||
"bill_type": "s",
|
||||
"congress": 118,
|
||||
"limit": 0,
|
||||
"provider": "congress_gov",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
async def bills(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> OBBject:
|
||||
"""Get and filter lists of Congressional Bills."""
|
||||
return await OBBject.from_query(OpenBBQuery(**locals()))
|
||||
|
||||
|
||||
# pylint: disable=W0212
|
||||
@router.command(
|
||||
methods=["GET"],
|
||||
examples=[
|
||||
APIEx(
|
||||
parameters={
|
||||
"provider": "congress_gov",
|
||||
"bill_url": "https://api.congress.gov/v3/bill/119/s/1947?",
|
||||
},
|
||||
),
|
||||
APIEx(
|
||||
parameters={
|
||||
"provider": "congress_gov",
|
||||
"bill_url": "119/s/1947",
|
||||
},
|
||||
),
|
||||
],
|
||||
openapi_extra={
|
||||
"widget_config": {
|
||||
"name": "Congressional Bill Viewer",
|
||||
"description": "View current and historical U.S. Congressional Bills.",
|
||||
"category": "Government",
|
||||
"subCategory": "Congress",
|
||||
"type": "multi_file_viewer",
|
||||
"searchCategory": "Congress",
|
||||
"widgetId": "uscongress_bill_text_congress_gov_obb",
|
||||
"endpoint": f"{api_prefix}/uscongress/bill_text",
|
||||
"params": [
|
||||
{
|
||||
"paramName": "urls",
|
||||
"type": "endpoint",
|
||||
"optionsEndpoint": f"{api_prefix}/uscongress/bill_text_urls",
|
||||
"optionsParams": {
|
||||
"bill_url": "$bill_url",
|
||||
"is_workspace": True,
|
||||
},
|
||||
"show": False,
|
||||
"multiSelect": True,
|
||||
"roles": ["fileSelector"],
|
||||
},
|
||||
{
|
||||
"paramName": "is_workspace",
|
||||
"value": True,
|
||||
"show": False,
|
||||
},
|
||||
{
|
||||
"label": "Bill URL",
|
||||
"description": "Enter a base URL of a bill (e.g., 'https://api.congress.gov/v3/bill/119/s/1947?format=json')."
|
||||
+ " Alternatively, you can enter a bill number (e.g., '119/s/1947')."
|
||||
+ " Create a group on the 'Bill URL' field of the 'Congressional Bills' widget"
|
||||
+ " and click on the cell to view the available documents.",
|
||||
"show": True,
|
||||
"paramName": "bill_url",
|
||||
"value": "119/hr/1",
|
||||
},
|
||||
],
|
||||
"refetchInterval": False,
|
||||
}
|
||||
},
|
||||
)
|
||||
async def bill_text_urls(
|
||||
bill_url: str,
|
||||
provider: str = "congress_gov",
|
||||
is_workspace: bool = False,
|
||||
) -> list:
|
||||
"""Get document choices for a specific bill.
|
||||
|
||||
This function is used by the Congressional Bills Viewer widget, in OpenBB Workspace,
|
||||
to populate PDF document choices for the selected bill.
|
||||
|
||||
When 'is_workspace' is False (default), it returns a list of the available text versions
|
||||
of the specified bill and their download links for the different formats.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bill_url : str
|
||||
The base URL of the bill (e.g., "https://api.congress.gov/v3/bill/119/s/1947?format=json").
|
||||
This can also be a shortened version like "119/s/1947".
|
||||
provider : str
|
||||
The provider name, always "congress_gov". This is a dummy parameter.
|
||||
is_workspace : bool
|
||||
Whether the request is coming from the OpenBB Workspace.
|
||||
This alters the output format to conform to the Workspace's expectations.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[dict]
|
||||
Returns a list of dictionaries with 'label' and 'value' keys, when `is_workspace` is True.
|
||||
Otherwise, returns the 'text' object from the Congress.gov API response.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_congress_gov.utils.helpers import get_bill_text_choices
|
||||
|
||||
if not bill_url and is_workspace is True:
|
||||
return [
|
||||
{
|
||||
"label": "Enter a valid bill URL to view available documents.",
|
||||
"value": "",
|
||||
}
|
||||
]
|
||||
|
||||
if not bill_url:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Bill URL is required. Please provide a valid bill URL or number.",
|
||||
)
|
||||
|
||||
if (bill_url.startswith("/") and bill_url[1].isdigit()) or bill_url[0].isdigit():
|
||||
# If the bill_url is a number, assume it is a congress number and append the base URL
|
||||
base_url = "https://api.congress.gov/v3/bill"
|
||||
bill_url = (
|
||||
base_url + bill_url
|
||||
if bill_url.startswith("/")
|
||||
else (base_url + "/" + bill_url if bill_url[0].isdigit() else bill_url)
|
||||
) + "?format=json"
|
||||
|
||||
return await get_bill_text_choices(bill_url=bill_url, is_workspace=is_workspace)
|
||||
|
||||
|
||||
@router.command(
|
||||
model="CongressBillInfo",
|
||||
examples=[
|
||||
APIEx(
|
||||
parameters={
|
||||
"provider": "congress_gov",
|
||||
"bill_url": "https://api.congress.gov/v3/bill/119/s/1947?",
|
||||
}
|
||||
),
|
||||
APIEx(
|
||||
description="The bill URL can be shortened to just the bill number (e.g., '119/s/1947').",
|
||||
parameters={
|
||||
"bill_url": "119/s/1947",
|
||||
"provider": "congress_gov",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
async def bill_info(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> OBBject:
|
||||
"""Get summary, status, and other metadata for a specific bill.
|
||||
|
||||
Enter the URL of the bill as: https://api.congress.gov/v3/bill/119/hr/131?
|
||||
|
||||
URLs for bills can be found from the `uscongress.bills` endpoint.
|
||||
|
||||
The raw JSON response from the API will be returned along with a formatted
|
||||
text version of the key information from the raw response.
|
||||
|
||||
In OpenBB Workspace, this command returns as a Markdown widget.
|
||||
"""
|
||||
return await OBBject.from_query(OpenBBQuery(**locals()))
|
||||
|
||||
|
||||
@router.command(
|
||||
model="CongressBillText",
|
||||
response_model=list,
|
||||
methods=["POST"],
|
||||
examples=[
|
||||
APIEx(
|
||||
parameters={
|
||||
"provider": "congress_gov",
|
||||
"urls": ["https://www.congress.gov/119/bills/hr1/BILLS-119hr1eh.pdf"],
|
||||
}
|
||||
),
|
||||
],
|
||||
openapi_extra={
|
||||
"widget_config": {
|
||||
"exclude": True,
|
||||
}
|
||||
},
|
||||
)
|
||||
async def bill_text(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> OBBject:
|
||||
"""Download the content of bill(s) from a Congress.gov file.
|
||||
|
||||
Note: This endpoint returns only the results array of the OBBject.
|
||||
|
||||
Enter a list of URLs to download the bill text.
|
||||
|
||||
For the API, the body of the request will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"urls": [
|
||||
"https://www.congress.gov/119/bills/hr1/BILLS-119hr1eh.pdf"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In OpenBB Workspace, this command returns as a multi-file viewer widget.
|
||||
"""
|
||||
return (await OBBject.from_query(OpenBBQuery(**locals()))).results # type: ignore[return-value]
|
||||
@@ -0,0 +1 @@
|
||||
"""Congress.gov utils module."""
|
||||
@@ -0,0 +1,72 @@
|
||||
"""US Congress Constants."""
|
||||
|
||||
base_url = "https://api.congress.gov/v3/"
|
||||
|
||||
BillTypes: list = ["hr", "s", "hjres", "sjres", "hconres", "sconres", "hres", "sres"]
|
||||
|
||||
bill_type_options: list[dict[str, str]] = [
|
||||
{"label": "House Bill", "value": "hr"},
|
||||
{"label": "Senate Bill", "value": "s"},
|
||||
{"label": "House Joint Resolution", "value": "hjres"},
|
||||
{"label": "Senate Joint Resolution", "value": "sjres"},
|
||||
{"label": "House Concurrent Resolution", "value": "hconres"},
|
||||
{"label": "Senate Concurrent Resolution", "value": "sconres"},
|
||||
{"label": "House Simple Resolution", "value": "hres"},
|
||||
{"label": "Senate Simple Resolution", "value": "sres"},
|
||||
]
|
||||
|
||||
bill_type_docstring = """Bill type (e.g., "hr" for House bills).
|
||||
|
||||
Must be one of: hr, s, hjres, sjres, hconres, sconres, hres, sres.
|
||||
|
||||
Bills
|
||||
-----
|
||||
|
||||
A bill is the form used for most legislation, whether permanent or temporary, general or special, public or private.
|
||||
|
||||
A bill originating in the House of Representatives is designated by the letters “H.R.”,
|
||||
signifying “House of Representatives”, followed by a number that it retains throughout all its parliamentary stages.
|
||||
|
||||
Bills are presented to the President for action when approved in identical form
|
||||
by both the House of Representatives and the Senate.
|
||||
|
||||
Joint Resolutions
|
||||
-----------------
|
||||
|
||||
Joint resolutions may originate either in the House of Representatives or in the Senate.
|
||||
|
||||
There is little practical difference between a bill and a joint resolution. Both are subject to the same procedure,
|
||||
except for a joint resolution proposing an amendment to the Constitution.
|
||||
|
||||
On approval of such a resolution by two-thirds of both the House and Senate,
|
||||
it is sent directly to the Administrator of General Services for submission to the individual states for ratification.
|
||||
|
||||
It is not presented to the President for approval.
|
||||
A joint resolution originating in the House of Representatives is designated “H.J.Res.” followed by its individual number.
|
||||
Joint resolutions become law in the same manner as bills.
|
||||
|
||||
Concurrent Resolutions
|
||||
----------------------
|
||||
|
||||
Matters affecting the operations of both the House of Representatives and Senate
|
||||
are usually initiated by means of concurrent resolutions.
|
||||
|
||||
A concurrent resolution originating in the House of Representatives is designated “H.Con.Res.”
|
||||
followed by its individual number.
|
||||
|
||||
On approval by both the House of Representatives and Senate,
|
||||
they are signed by the Clerk of the House and the Secretary of the Senate.
|
||||
|
||||
They are not presented to the President for action.
|
||||
|
||||
Simple Resolutions
|
||||
------------------
|
||||
|
||||
A matter concerning the operation of either the House of Representatives or Senate
|
||||
alone is initiated by a simple resolution.
|
||||
|
||||
A resolution affecting the House of Representatives is designated “H.Res.” followed by its number.
|
||||
|
||||
They are not presented to the President for action.
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,488 @@
|
||||
"""Congress.gov helpers."""
|
||||
|
||||
from typing import Literal, Optional, Union
|
||||
|
||||
from fastapi.exceptions import HTTPException
|
||||
from openbb_congress_gov.utils.constants import BillTypes, base_url, bill_type_options
|
||||
from openbb_core.app.model.abstract.singleton import SingletonMeta
|
||||
from openbb_core.provider.utils.errors import UnauthorizedError
|
||||
|
||||
|
||||
# pylint: disable=R0903
|
||||
class BillsState(metaclass=SingletonMeta):
|
||||
"""Singleton class to manage application cache."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the BillsState."""
|
||||
if not hasattr(self, "bills"):
|
||||
self.bills = {}
|
||||
|
||||
|
||||
def year_to_congress(year: int) -> int:
|
||||
"""
|
||||
Map a year (1935-present) to the corresponding U.S. Congress number.
|
||||
|
||||
Raises ValueError if the year is before 1935.
|
||||
"""
|
||||
if year < 1935:
|
||||
raise ValueError("Year must be 1935 or later.")
|
||||
# 74th Congress started in 1935
|
||||
congress_number = 74 + ((year - 1935) // 2)
|
||||
return congress_number
|
||||
|
||||
|
||||
def check_api_key() -> str:
|
||||
"""Check if the Congress.gov API key is set in user settings.
|
||||
|
||||
Raises UnauthorizedError if the API key is not set.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_core.app.service.user_service import UserSettings
|
||||
from pydantic import SecretStr
|
||||
|
||||
credentials = UserSettings().credentials
|
||||
api_key = getattr(
|
||||
credentials, "congress_gov_api_key", SecretStr("")
|
||||
).get_secret_value()
|
||||
|
||||
if not api_key:
|
||||
raise UnauthorizedError("Missing credentials: congress_gov_api_key")
|
||||
|
||||
return api_key
|
||||
|
||||
|
||||
def download_bills(urls: list[str]) -> list:
|
||||
"""Download a bill's text in PDF format.
|
||||
|
||||
This helper is not intended to be used directly.
|
||||
|
||||
OpenBB Workspace uses this, as a POST endpoint, to download
|
||||
the selected bill(s) in PDF format. Results are returned as base64-encoded PDF content.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
urls: list[str]
|
||||
A list of URLs to download. Each URL must be a valid Congress.gov URL.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
A list of dictionaries containing the base64-encoded PDF content.
|
||||
The dictionaries have the following structure:
|
||||
[
|
||||
{
|
||||
"content": str, # Base64-encoded PDF content
|
||||
"data_format": {
|
||||
"data_type": "pdf",
|
||||
"filename": str, # The filename of the downloaded PDF
|
||||
},
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
If an error occurs during the download, the dictionary will contain:
|
||||
[
|
||||
{
|
||||
"error_type": str, # Type of error (e.g., "download_error")
|
||||
"content": str, # Error content
|
||||
"filename": str, # The filename of the attempted download
|
||||
},
|
||||
...
|
||||
]
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
import base64 # noqa
|
||||
from io import BytesIO
|
||||
from openbb_core.provider.utils.helpers import make_request
|
||||
|
||||
results: list = []
|
||||
|
||||
for url in urls:
|
||||
if "congress.gov" not in url:
|
||||
results.append(
|
||||
{
|
||||
"error_type": "invalid_url",
|
||||
"content": f"Invalid URL: {url}. Must be a valid Congress.gov API URL.",
|
||||
"filename": url.split("/")[-1],
|
||||
}
|
||||
)
|
||||
continue
|
||||
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",
|
||||
"filename": url.split("/")[-1],
|
||||
},
|
||||
}
|
||||
)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
results.append(
|
||||
{
|
||||
"error_type": "download_error",
|
||||
"content": f"{exc.__class__.__name__}: {exc.args[0]}",
|
||||
"filename": url.split("/")[-1],
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
return results
|
||||
|
||||
|
||||
# pylint: disable=R0917
|
||||
async def get_bills_by_type(
|
||||
congress: Optional[int] = None,
|
||||
bill_type: str = "hr",
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
limit: Optional[int] = None,
|
||||
offset: Optional[int] = 0,
|
||||
sort_by: Literal["asc", "desc"] = "desc",
|
||||
) -> Union[dict, list]:
|
||||
"""Fetch bills of a specific type for a given Congress number.
|
||||
|
||||
Results are sorted by date of the latest action on the bill.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
congress : Optional[int]
|
||||
The Congress number (e.g., 118 for the 118th Congress).
|
||||
If None, defaults to the current Congress based on the current year.
|
||||
bill_type : str
|
||||
The type of bill to fetch (e.g., "hr" for House bills).
|
||||
start_date : Optional[str]
|
||||
The start date in ISO format (YYYY-MM-DD) for filtering bills.
|
||||
If None, no start date filter is applied.
|
||||
end_date : Optional[str]
|
||||
The end date in ISO format (YYYY-MM-DD) for filtering bills.
|
||||
If None, no end date filter is applied.
|
||||
limit : Optional[int]
|
||||
The maximum number of bills to return. Defaults to 10 if None.
|
||||
To fetch all bills, use `get_all_bills_by_type()` instead.
|
||||
offset : Optional[int]
|
||||
The number of results to skip before starting to collect the result set.
|
||||
Defaults to 0 if None.
|
||||
sort_by : Literal["asc", "desc"]
|
||||
The sort order for the results. Defaults to "desc".
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
A dictionary of the raw JSON response from the API.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from datetime import ( # noqa
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from openbb_core.provider.utils.helpers import amake_request
|
||||
|
||||
if bill_type and bill_type not in BillTypes:
|
||||
raise ValueError(
|
||||
f"Invalid bill type: {bill_type}. Must be one of {', '.join(BillTypes)}."
|
||||
)
|
||||
|
||||
api_key = check_api_key()
|
||||
|
||||
if start_date is None and end_date is None and congress is None:
|
||||
congress = year_to_congress(datetime.now().year)
|
||||
elif congress is None and start_date is not None:
|
||||
congress = year_to_congress(dateType.fromisoformat(start_date).year)
|
||||
elif congress is None and end_date is not None and start_date is None:
|
||||
congress = year_to_congress(dateType.fromisoformat(end_date).year)
|
||||
elif start_date is not None and end_date is not None:
|
||||
start_year = dateType.fromisoformat(start_date).year
|
||||
end_year = dateType.fromisoformat(end_date).year
|
||||
congress_start = year_to_congress(start_year)
|
||||
congress_end = year_to_congress(end_year)
|
||||
if congress_start != congress_end:
|
||||
raise ValueError(
|
||||
"Start and end dates must be in the same Congress session."
|
||||
)
|
||||
congress = congress_start
|
||||
|
||||
if congress is None:
|
||||
congress = year_to_congress(datetime.now().year)
|
||||
|
||||
url = (
|
||||
f"{base_url}bill/{congress}/{bill_type}"
|
||||
+ (f"?fromDateTime={start_date + 'T00:00:00Z'}" if start_date else "")
|
||||
+ (f"&toDateTime={end_date + 'T23:59:59Z'}" if end_date else "")
|
||||
+ f"?limit={limit if limit is not None else 10}"
|
||||
+ (f"&offset={offset}" if offset else "")
|
||||
+ f"&sort=updateDate+{sort_by}"
|
||||
+ f"&format=json&api_key={api_key}"
|
||||
)
|
||||
|
||||
return await amake_request(url)
|
||||
|
||||
|
||||
async def get_all_bills_by_type(
|
||||
congress: Optional[int] = None,
|
||||
bill_type: Optional[str] = None,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
):
|
||||
"""Fetch all bills of a specific type for a given Congress number.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
congress : Optional[int]
|
||||
The Congress number (e.g., 118 for the 118th Congress).
|
||||
If None, defaults to the current Congress based on the current year.
|
||||
bill_type : Optional[str]
|
||||
The type of bill to fetch (e.g., "hr" for House bills).
|
||||
Must be one of: "hr", "s", "hjres", "sjres", "hconres", "sconres", "hres", "sres"
|
||||
If None, defaults to "hr".
|
||||
start_date : Optional[str]
|
||||
The start date in ISO format (YYYY-MM-DD) for filtering bills.
|
||||
If None, no start date filter is applied.
|
||||
end_date : Optional[str]
|
||||
The end date in ISO format (YYYY-MM-DD) for filtering bills.
|
||||
If None, no end date filter is applied.
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
A list of dictionaries containing all bills of the specified type for the given Congress.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
import math # noqa
|
||||
from openbb_core.provider.utils.helpers import amake_requests
|
||||
|
||||
bill_type = "hr" if bill_type is None else bill_type.lower()
|
||||
|
||||
if bill_type not in BillTypes:
|
||||
raise ValueError(
|
||||
f"Invalid bill type: {bill_type}. Must be one of {', '.join(BillTypes)}."
|
||||
)
|
||||
|
||||
api_key = check_api_key()
|
||||
results: list = []
|
||||
limit = 250
|
||||
offset = 0
|
||||
res = await get_bills_by_type(
|
||||
congress=congress,
|
||||
bill_type=bill_type,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
)
|
||||
results.extend(res.get("bills", [])) # type: ignore
|
||||
total_bills = res.get("pagination", {}).get("count", 0) # type: ignore
|
||||
next_url = res.get("pagination", {}).get("next", None) # type: ignore
|
||||
urls: list = []
|
||||
|
||||
# Generate the list of URLs instead of paginating in a loop.
|
||||
for i in range(1, math.ceil(total_bills / limit)):
|
||||
offset = i * limit
|
||||
url = (
|
||||
next_url.replace(f"offset={limit}", f"offset={offset}").replace(
|
||||
"updateDate ", "updateDate+"
|
||||
)
|
||||
+ f"&api_key={api_key}"
|
||||
)
|
||||
urls.append(url)
|
||||
|
||||
async def response_callback(response, _):
|
||||
"""Process the response from the API and append the results."""
|
||||
result = await response.json()
|
||||
if result and "bills" in result and (bills := result.get("bills", [])):
|
||||
results.extend(bills)
|
||||
|
||||
_ = await amake_requests(urls, response_callback=response_callback) # type: ignore
|
||||
|
||||
return sorted(results, key=lambda x: x["updateDate"], reverse=True)
|
||||
|
||||
|
||||
async def get_bill_choices(
|
||||
congress: Optional[int] = None,
|
||||
bill_type: Optional[str] = None,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
bill_url: Optional[str] = None,
|
||||
is_document_choices: Optional[bool] = None,
|
||||
) -> list:
|
||||
"""Fetch a list of bills of a specific type for a given Congress number.
|
||||
|
||||
This function is not intended to be used directly.
|
||||
|
||||
It is used by the OpenBB Workspace Congressional Bills Viewer widget
|
||||
to populate dynamic parameter choices based on the widget's state.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from datetime import datetime
|
||||
|
||||
bills_state = BillsState()
|
||||
|
||||
if bill_type and bill_type not in [option["value"] for option in bill_type_options]:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Invalid bill type: {bill_type}."
|
||||
+ f" Must be one of {', '.join([option['value'] for option in bill_type_options])}.",
|
||||
)
|
||||
|
||||
if bill_url:
|
||||
return await get_bill_text_choices(bill_url=bill_url)
|
||||
|
||||
if is_document_choices is True and not bill_url:
|
||||
return [
|
||||
{
|
||||
"label": "Select a bill to view associated text.",
|
||||
"value": "",
|
||||
}
|
||||
]
|
||||
|
||||
if not bill_type:
|
||||
bill_type = "hr"
|
||||
|
||||
if not congress:
|
||||
congress = year_to_congress(datetime.now().year)
|
||||
|
||||
cached_bills = bills_state.bills.get(f"{congress}_{bill_type}")
|
||||
|
||||
if not cached_bills:
|
||||
bills = await get_all_bills_by_type(
|
||||
congress=congress,
|
||||
bill_type=bill_type, # type: ignore
|
||||
)
|
||||
bills_state.bills[f"{congress}_{bill_type}"] = bills
|
||||
else:
|
||||
bills = cached_bills
|
||||
|
||||
if start_date:
|
||||
bills = (
|
||||
[bill for bill in bills if bill["latestAction"]["actionDate"] >= start_date]
|
||||
if not end_date
|
||||
else [
|
||||
bill
|
||||
for bill in bills
|
||||
if bill["latestAction"]["actionDate"] >= start_date
|
||||
and bill["latestAction"]["actionDate"] <= end_date
|
||||
]
|
||||
)
|
||||
elif end_date and not start_date:
|
||||
bills = [
|
||||
bill for bill in bills if bill["latestAction"]["actionDate"] <= end_date
|
||||
]
|
||||
|
||||
results: list = []
|
||||
|
||||
for bill in sorted(
|
||||
bills, key=lambda x: x["latestAction"]["actionDate"], reverse=True
|
||||
):
|
||||
bill_title = bill.get("title", "")
|
||||
|
||||
if not bill_title:
|
||||
continue
|
||||
|
||||
bill_url = bill.get("url", "")
|
||||
label = (
|
||||
bill_title
|
||||
+ f" ({bill.get('number', '')} - {bill['latestAction']['actionDate']})"
|
||||
)
|
||||
results.append(
|
||||
{
|
||||
"label": label,
|
||||
"value": bill_url,
|
||||
}
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
async def get_bill_text_choices(bill_url: str, is_workspace: bool = False) -> list:
|
||||
"""Fetch the direct download links for the available text versions of the specified bill.
|
||||
|
||||
This function is used by the Congressional Bills Viewer widget,
|
||||
in OpenBB Workspace, to populate the document choices
|
||||
for the selected bill. When `is_workspace` is True,
|
||||
it returns a list of dictionaries with 'label' and 'value' keys.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bill_url : str
|
||||
The base URL of the bill (e.g., "https://api.congress.gov/v3/bill/119/s/1947?format=json").
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[dict]
|
||||
List of dictionaries with the results.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_core.provider.utils.helpers import amake_request
|
||||
|
||||
api_key = check_api_key()
|
||||
results: list = []
|
||||
url = bill_url.replace("?", "/text?") + f"&api_key={api_key}"
|
||||
response = await amake_request(url)
|
||||
bill_text = response.get("textVersions", []) # type: ignore
|
||||
|
||||
# Return the results for non-Workspace queries
|
||||
if is_workspace is False:
|
||||
|
||||
if not bill_text:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="No text available for this bill currently.",
|
||||
)
|
||||
|
||||
text_output: list = []
|
||||
|
||||
for version in bill_text:
|
||||
bill_version: dict = {}
|
||||
formats = version.get("formats", [])
|
||||
bill_type = version.get("type", "")
|
||||
version_date = version.get("date", "")
|
||||
if not formats or not version_date:
|
||||
continue
|
||||
bill_version["version_type"] = bill_type
|
||||
bill_version["version_date"] = version_date
|
||||
for fmt in formats:
|
||||
doc_url = fmt.get("url")
|
||||
doc_type = fmt.get("type", "").replace("Formatted ", "").lower()
|
||||
bill_version[doc_type] = doc_url
|
||||
|
||||
if bill_version:
|
||||
text_output.append(bill_version)
|
||||
|
||||
return text_output
|
||||
|
||||
if not bill_text:
|
||||
return [
|
||||
{
|
||||
"label": "No text available for this bill currently.",
|
||||
"value": "",
|
||||
}
|
||||
]
|
||||
|
||||
for version in bill_text:
|
||||
version_date = version.get("date")
|
||||
formats = version.get("formats", [])
|
||||
version_type = version.get("type", "")
|
||||
for fmt in formats:
|
||||
if (doc_type := fmt.get("type")) and doc_type == "PDF":
|
||||
doc_url = fmt.get("url")
|
||||
doc_name = doc_url.split("/")[-1]
|
||||
filename = (
|
||||
f"{version_type} - {version_date} - {doc_name}"
|
||||
if version_date
|
||||
else doc_name
|
||||
)
|
||||
results.append(
|
||||
{
|
||||
"label": filename,
|
||||
"value": doc_url,
|
||||
}
|
||||
)
|
||||
break
|
||||
|
||||
return results
|
||||
1677
openbb_platform/providers/congress_gov/poetry.lock
generated
vendored
Normal file
1677
openbb_platform/providers/congress_gov/poetry.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
openbb_platform/providers/congress_gov/pyproject.toml
vendored
Normal file
21
openbb_platform/providers/congress_gov/pyproject.toml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
[tool.poetry]
|
||||
name = "openbb-congress-gov"
|
||||
version = "1.0.0"
|
||||
description = "Congress.gov Provider Extension for the OpenBB Platform"
|
||||
authors = ["OpenBB Team <hello@openbb.co>"]
|
||||
readme = "README.md"
|
||||
packages = [{ include = "openbb_congress_gov" }]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9.21,<3.13"
|
||||
openbb-core = "^1.4.8"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."openbb_provider_extension"]
|
||||
congress_gov = "openbb_congress_gov:congress_gov_provider"
|
||||
|
||||
[tool.poetry.plugins."openbb_core_extension"]
|
||||
uscongress = "openbb_congress_gov.router.congress_gov_router:router"
|
||||
@@ -0,0 +1,460 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA7VVTW8aMRC98yusPQf2ozQUpKpKyQWpIhHQIjXKwdgD68jYW3ucFEX898pmgSVs
|
||||
CFXT29rzZt6bmZ3xc4MQQqKZkDLqkedwCjeUodDKHlwGA9NOYdQj2cXhvTM+QpQjFrYXx7QQLabV
|
||||
woC1rYV+jB8/xJ4lTtNubOO02+7EJceXuTZLip8frFbRLuh6Hz9ierkUiAAn9KT/rmdPc46kTSzP
|
||||
nHYPDLbQymrzF7UL9wPFpONCLaYCc27ok+pXQ2Xvkd823tv5CYVGc8eAX1MEz5Ql2cdmctlM2lEF
|
||||
JymCxavQyeOENx0+GSHgEH77ukQjoJzgk2BAqOLEwByMAU5QE8yB9LcNIlqFAxgGF2TMBCj/4X0m
|
||||
hipbaIPUU7fqs1NuOQPjGX1hqvloIxZC9XO6BYxBefmvQfqah9zGVUShpWCrKwP0uCSKLoPDrZtJ
|
||||
wcg3qrgNwocUnaGSjMBqZxjYeumVX+LuIPIhTznWeuEEhwH3jNMkST4l2YvaB+BcGIvDUtk4B8m1
|
||||
qsU5KXcwUC0yzQVCrp31bdj4kbvr5mhwX+cu7NfVCH45sKHbwzqMpHsl++h1yIIaXHnYdZ3VYvnX
|
||||
jQZ15jPGZwm+wXFZtvqRCd3Zne6rfXKzB2D4fzfWluTtefYT9gOMPb3U30GSJzpDjkAZunPTn9zc
|
||||
fh+TK4ZEz4lfEdFL3AnB7XcQHCjOkLwqjifdFZwiHC64TjNrT7Kkl3V62eXPevRu2U/KzVfr2qho
|
||||
iMxucCrPtE9m+Ooy89ZJKdtG9a9XlKbdFyYEhVs3WhRSsLBL41CbCnRTMo/aV23dWP8BvNiwAFQI
|
||||
AAA=
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '0'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- EXPIRED
|
||||
Cf-Ray:
|
||||
- 9667a7d86a9aff0d-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 22:01:32 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 22:16:32 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 22:01:32 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=lRCAtfyRd3BucvCK2W3DQVTmsZFE4rnG3gnUUlqNd5c-1753740092-1.0.1.1-S4cCnSHfl01q_NBIxwcQ1_Z8PJZl47kdo8z1QCXMo8kI9ACp2OMOdGrNbL89w8S0S4NAkOLSCS1efWAN6cDSFO8fcidieJA9QX.hY2k8lfU;
|
||||
path=/; expires=Mon, 28-Jul-25 22:31:32 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- coac726fopfdg1lfad4g
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4871'
|
||||
X-Vcap-Request-Id:
|
||||
- 126412b5-6b7a-4345-44a2-7639e17419e5
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/cosponsors?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA6WTW0/CMBzF3/kUTZ83unGVJcYYeUFEEtT4QHwooxuV0tZeNMTw3U03riUIxj01
|
||||
Paen/55f9l0BAACYCi0F10JpmIBxsee+7+2qcE2oyC2dkt4UJgAOoiiOm3UYHJoyqrR5xAviPA9U
|
||||
4yODZWyjPxFeBQOr5uJLz2kAnB+MR+Ft/80/RvVQ0ZxyzO42w8IEGGWJZ2R4d/822k+TWJmlc4x8
|
||||
ZVPEjMouNkVKLao1w6gVRo0js1lbbvu+ZBVzwswYqROEsKTVVPBcEa2rufhEn3W0IIsJUWhd5E0m
|
||||
1AKb63ctONxmrYI/0Gi3fqVxT7LsPA2i5owsA+DcYNwNh6MLWWSY6V9hlMknUXQvRtEOo6uTKIaj
|
||||
f6Jot06gKFZvZTiU2BVgqOAw2UMDU2G5gQmoBd5ej6fMTinPX6mZTRX+4nf7f12tsocbKvJhiTaH
|
||||
0RPK2KN1g7rnxJ1Ge++lhfq8lEUH2hdezlfgbCiOO0gjF33QwcFbymPFCHHHkwzhZjMElpLRtKgI
|
||||
+SlluHPtOl5VVj86D0dOjwQAAA==
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '0'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- EXPIRED
|
||||
Cf-Ray:
|
||||
- 9667a7db79e78b90-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 22:01:32 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 22:16:32 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 22:01:32 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/cosponsors>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=eX1P8hklyib6T8ukIOIIlWTVbpJvx.W9mw1s5T5SnsI-1753740092-1.0.1.1-LY_0Zun1r2l32RLRDjVKfFX0hGVZLUPe6Ne0Xju3oMQMnrhXeNaiJ2y7Mn26dTpveGHu7QgWJnLoPGXORL7Cmad3BEYIk8K5XcQ_p1KCSB0;
|
||||
path=/; expires=Mon, 28-Jul-25 22:31:32 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- coac72aaobbi0dj664u0
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4870'
|
||||
X-Vcap-Request-Id:
|
||||
- 588eacdd-8235-4a5b-4614-b4d48d505f59
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/subjects?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA12QUUvDMBSF3/crQp63Za3TsoKI4KMM0fmi+HCb3dWMNInJTWGM/ndpyrTd6/nO
|
||||
OdxzzzPGGOMOamWAlDW8ZOekJV3aaIiXLEtSNx/cHn8iBppaK6X1NjYVel4ynm3WBZ9P6e7ksGfh
|
||||
Grx73evfRC6UQoBTS2lN7TGEZW1b0d6I3iaybCOC6KsfDtY3QPfHYM247RJLJ2SbK0Ro6HIEOKeV
|
||||
TJPFdctQ3rsSmWwPsTqipDAdr7FWQQOpFt/+DZ9fo1JntZKnR48wiSZmoElHvcRKK8mewewDA7Nn
|
||||
W6DoQbNXDDZ6iePXpWR0eyB8Akr5fJXfLlbFIl/v8lWZF2V+98H/At0wZNb9AkCvkHv1AQAA
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '0'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- EXPIRED
|
||||
Cf-Ray:
|
||||
- 9667a7dd8effef3f-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 22:01:33 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 22:16:33 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 22:01:33 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/subjects>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=QfGVvN0qQdxtXnf.rVntfKz4GgAQRCIs15KcehiyqnA-1753740093-1.0.1.1-K1u914Za6dm_G71OGZkHR_Q3HBD2gmNKfCJ5gocmqFEDSzjwode11Mz8Z.It4yRFWyLTTg8tuVWs_NhDWVsAR6kDVD7Rs6tjbX4NVyZT4_U;
|
||||
path=/; expires=Mon, 28-Jul-25 22:31:33 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- coac72ctrlhbbvkufgjg
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4869'
|
||||
X-Vcap-Request-Id:
|
||||
- bfb54c2d-e855-401f-5067-0198a938e8f9
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/committees?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA4VRsW7CMBDd+QrLM+Ak0FZEqjqwdyjp0qqDcY7gKrZT+4KEUP69skOAuEj1dLr3
|
||||
7t2959OEEEKoMEpJRABHc/IZev6dLlVgcYHyIFFGrPvsy1TJEWhOaJZkD7PkcZYsiyzNs2WeLD7o
|
||||
9P6M5irMvMEOrIWSFIb+YXajztdYioo9V1uwXmUD2t8QEYYda6MUWAFTshEStC+4LklhuXaNschR
|
||||
Gk3WQ0KxjDs6BLU2ZRBzTqgkiTl4bAK6Qa5LqasYb23t4T1i43LGeCPnwujKgnPzyhzYYcEuP8Rc
|
||||
cMP6TS87YxXH529n9DWhPplzIrThldTBBc1vPokK02qkOUlDqzuzLfy04HBM3cq6fm2HPNPV8unG
|
||||
QkCLs0UXA+//e/M0lqYr5piXHnma3t7bj4UT0lUEIWgcjuBNU0sRLLNYpRf3rGtm3aT7BVyDgr0J
|
||||
AwAA
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '0'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- EXPIRED
|
||||
Cf-Ray:
|
||||
- 9667a7df6c25d82e-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 22:01:33 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 22:16:33 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 22:01:33 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/committees>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=nHKUtWJbOTmqLWdxe_Aq2Zce371jaF_pz80zD3xDyh8-1753740093-1.0.1.1-isb60hSq4f5NaFaJ_ZMtF1Bsubaqi16SgHSMbFQmOh7nSRdrV5hL9lpQ0tJtyOlGY.YiMGw97Xpw35bYdvNdmJNdrDNnqgUsQnHt4WKl740;
|
||||
path=/; expires=Mon, 28-Jul-25 22:31:33 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- coac72f9agh4194l3ia0
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4868'
|
||||
X-Vcap-Request-Id:
|
||||
- 0718865c-a8ab-470b-6cb9-7f48e9f5ac18
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/actions?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA5WTP2/CMBDFdz7FyTPFgf4TSFUHulSqOkA7VR2Mc1BXsZ3al7YI8d0rmxCSAIJm
|
||||
suKXd+9+d1l1AACYkKSs8WwEb/FFeFbVqSZ5EIRsBGyQDK4vkpuL5Ip1mzpptVZEiE23w67VV0bo
|
||||
6Du2WqOT2IWpVGjCQZgUXpwwPreORAgB422NVvHKzi89oR7bNJp6L3WSHNMWLguiD6LcjzgXuepJ
|
||||
axYOve8t7Df/vuRVT9yjEYR843g/t04Luvv01rA983XjzXsLk7eFkziNOdnoAJYKyTSWbPqvW26E
|
||||
vxS0ExQp0I+SGLE5nKNzmAJZoA/ccYMS4knUvfZ4aZnHVI+GnJ1Ef5HtwtWCHdyf7Uj6SbI3kbNX
|
||||
7DQ7uSkz7B7H+qRmTrgl2DmMy3Gfxzh2nhYSU1AGyun8k1KnthIsFwtlIu1GM0zawoSKg04tDnP4
|
||||
VaCnpnSmsuy50DN0Ee7w6raWKN6+lIl8++L19PoHGe/3h9zzYN1Y+249b4kxROgPW1eEhrYhRJ5n
|
||||
SsaWedtlYx5Uu99q3Vn/AbYTTJ2pBAAA
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '1'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- EXPIRED
|
||||
Cf-Ray:
|
||||
- 9667a7e23a91c895-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 22:01:34 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 22:16:33 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 22:01:33 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/actions>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=zCcob6_JyGGJacyKVdQAN9nu.89OlDM2vUwKzewrOJo-1753740094-1.0.1.1-YF4VyfjpweSLbdUN3KH1InXhhJcqTvepr9D70uoiUMGBBEQug19_2ONnCG_bhfTN.u3LI0PLABh_2JdElPdBQiolpZOrSYpukcR2WzfZMy4;
|
||||
path=/; expires=Mon, 28-Jul-25 22:31:34 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- coac72iopk02c3asbd5g
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4867'
|
||||
X-Vcap-Request-Id:
|
||||
- ead26c6a-a28e-4734-6289-13e35f371850
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/titles?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA+2STW/bMAyG7/0VhE8bkNRxPtrFwDAU6aWXpoCTHTbsoMhMrMEWVYnKmhb974OU
|
||||
5qMeurXADjvsZpCPXr5+yYcTAIDEiJXSghXpJIeHWIt1SV5zksMwlh47W9rirUfHz9GFqutr3yzQ
|
||||
Jjkk2Xh4nnSed2cbg6Hn2o25rUO9YjYuT1Nh1KkkvbLo3OmK1ul6kAYszbJx6tIg/WlJthH88bsj
|
||||
fay2exYtZONWi1HzzoQwplYy/nLaVtmKByp2nv07K64x6H/d84cQDkR4PJ3MpjfzAi4kAy2h3+uP
|
||||
jqYc2J2lS+VMLTYwiwIvkRMqAz0ctQBvSsF4KThqhWHd3nm3N55lWd4b5Nn4S7J/8Nh5yXzcE97x
|
||||
Z7ROkX4allwVbT8t8Fo0W1CzpdJLLEFpKFAHP52/FFBRkeVtPO/cexAODuP+lFfWy14R2Fk36896
|
||||
w3w0yLPRPxiYMeSUXgFXCBNfs1rHCwahS5hZUWLIcSqZjHdwsxPmypJfVTDXyJWSooaCrWBcKXT/
|
||||
w39t+BcQVIAJjKVKLRTHNRQoLbKwm5BiKFxpRqvIxqX8QkyoadBKhKWlBoTniqy6DzuV244SNdDT
|
||||
BsWtF9LX7C0CGbRx2S54DbpzrRhLKFgwuk4s4Z2svVNrBJSkqVES7kljZ+/lh2C0bme1pRCgJVkg
|
||||
rtCC8daQQ3f627OYLpcqeo6X8bazOHvDUQw/5P3+8VHEr28njz8BfyDqPsIGAAA=
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '0'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- EXPIRED
|
||||
Cf-Ray:
|
||||
- 9667a7e54e47da91-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 22:01:34 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 22:16:34 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 22:01:34 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/titles>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=ypMMDm8JRU.Zxf.9xEpvb7uQsWPMay6qnUYSGnX2DKU-1753740094-1.0.1.1-Wu5WE6LQFHz41JZGjeCfsTVwJ1NTEkWi8aNdGT5tuD6stLvsH4zTT1rESywGYEAwHsNCkM3cQ3.yQwtUNdNaG3lfXAYnv7FYu27Qc6h9qRQ;
|
||||
path=/; expires=Mon, 28-Jul-25 22:31:34 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- coac72mjqd9n66ga5gsg
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4866'
|
||||
X-Vcap-Request-Id:
|
||||
- fe6b1a80-4a0d-4562-4d1a-7a9c1ce09314
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -0,0 +1,460 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA7VVTW8aMRC98yusPQf2ozQUpKpKyQWpIhHQIjXKwdgD68jYW3ucFEX898pmgSVs
|
||||
CFXT29rzZt6bmZ3xc4MQQqKZkDLqkedwCjeUodDKHlwGA9NOYdQj2cXhvTM+QpQjFrYXx7QQLabV
|
||||
woC1rYV+jB8/xJ4lTtNubOO02+7EJceXuTZLip8frFbRLuh6Hz9ierkUiAAn9KT/rmdPc46kTSzP
|
||||
nHYPDLbQymrzF7UL9wPFpONCLaYCc27ok+pXQ2Xvkd823tv5CYVGc8eAX1MEz5Ql2cdmctlM2lEF
|
||||
JymCxavQyeOENx0+GSHgEH77ukQjoJzgk2BAqOLEwByMAU5QE8yB9LcNIlqFAxgGF2TMBCj/4X0m
|
||||
hipbaIPUU7fqs1NuOQPjGX1hqvloIxZC9XO6BYxBefmvQfqah9zGVUShpWCrKwP0uCSKLoPDrZtJ
|
||||
wcg3qrgNwocUnaGSjMBqZxjYeumVX+LuIPIhTznWeuEEhwH3jNMkST4l2YvaB+BcGIvDUtk4B8m1
|
||||
qsU5KXcwUC0yzQVCrp31bdj4kbvr5mhwX+cu7NfVCH45sKHbwzqMpHsl++h1yIIaXHnYdZ3VYvnX
|
||||
jQZ15jPGZwm+wXFZtvqRCd3Zne6rfXKzB2D4fzfWluTtefYT9gOMPb3U30GSJzpDjkAZunPTn9zc
|
||||
fh+TK4ZEz4lfEdFL3AnB7XcQHCjOkLwqjifdFZwiHC64TjNrT7Kkl3V62eXPevRu2U/KzVfr2qho
|
||||
iMxucCrPtE9m+Ooy89ZJKdtG9a9XlKbdFyYEhVs3WhRSsLBL41CbCnRTMo/aV23dWP8BvNiwAFQI
|
||||
AAA=
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '313'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- HIT
|
||||
Cf-Ray:
|
||||
- 9660e2f54a5068f1-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 02:18:33 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 01:55:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 01:40:00 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=TBGhU8lMQjWBTkLKv76iFRRFdo.NAJ3q3E1fzjyUvYY-1753669113-1.0.1.1-o7aSPIa3UcT.ZZcJAOCZBEBLZwipxlfJuwE3VrC6.gfLJ8wZR.JRrDR5zQLxjZQmM6TCLWX_o1kdQOvpzsNZdJY1KhUHUvK_EQH1uRSfFT0;
|
||||
path=/; expires=Mon, 28-Jul-25 02:48:33 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- co9r9hajf18ebu5d15dg
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4852'
|
||||
X-Vcap-Request-Id:
|
||||
- 2b32c694-8298-42c0-4fa9-1a19f3ea003f
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/cosponsors?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA6WTW0/CMBzF3/kUTZ83unGVJcYYeUFEEtT4QHwooxuV0tZeNMTw3U03riUIxj01
|
||||
Paen/55f9l0BAACYCi0F10JpmIBxsee+7+2qcE2oyC2dkt4UJgAOoiiOm3UYHJoyqrR5xAviPA9U
|
||||
4yODZWyjPxFeBQOr5uJLz2kAnB+MR+Ft/80/RvVQ0ZxyzO42w8IEGGWJZ2R4d/822k+TWJmlc4x8
|
||||
ZVPEjMouNkVKLao1w6gVRo0js1lbbvu+ZBVzwswYqROEsKTVVPBcEa2rufhEn3W0IIsJUWhd5E0m
|
||||
1AKb63ctONxmrYI/0Gi3fqVxT7LsPA2i5owsA+DcYNwNh6MLWWSY6V9hlMknUXQvRtEOo6uTKIaj
|
||||
f6Jot06gKFZvZTiU2BVgqOAw2UMDU2G5gQmoBd5ej6fMTinPX6mZTRX+4nf7f12tsocbKvJhiTaH
|
||||
0RPK2KN1g7rnxJ1Ge++lhfq8lEUH2hdezlfgbCiOO0gjF33QwcFbymPFCHHHkwzhZjMElpLRtKgI
|
||||
+SlluHPtOl5VVj86D0dOjwQAAA==
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '208'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- HIT
|
||||
Cf-Ray:
|
||||
- 9660e2f66f22ff07-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 02:18:33 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 02:30:05 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 02:15:05 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/cosponsors>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=N1bfaXGTYL8YuQBi3rLH9APzZ1KZJBYTvoioeFJJIGs-1753669113-1.0.1.1-DOQYJMsZqfTB_QOG5T4xlgYwSSdjfVcJLVN8e3bQYWp1nhq5ptpnAChKV0IB3i3HsaiNPErpStaReot0pSeSqMxhJWdRVH7DY5h7rT4HtaU;
|
||||
path=/; expires=Mon, 28-Jul-25 02:48:33 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- co9r9hc1f26qa1a7pm20
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4852'
|
||||
X-Vcap-Request-Id:
|
||||
- a0fbf597-a1a3-4f53-65a3-e3fca74bcd1e
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/subjects?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA12QUUvDMBSF3/crQp63Za3TsoKI4KMM0fmi+HCb3dWMNInJTWGM/ndpyrTd6/nO
|
||||
OdxzzzPGGOMOamWAlDW8ZOekJV3aaIiXLEtSNx/cHn8iBppaK6X1NjYVel4ynm3WBZ9P6e7ksGfh
|
||||
Grx73evfRC6UQoBTS2lN7TGEZW1b0d6I3iaybCOC6KsfDtY3QPfHYM247RJLJ2SbK0Ro6HIEOKeV
|
||||
TJPFdctQ3rsSmWwPsTqipDAdr7FWQQOpFt/+DZ9fo1JntZKnR48wiSZmoElHvcRKK8mewewDA7Nn
|
||||
W6DoQbNXDDZ6iePXpWR0eyB8Akr5fJXfLlbFIl/v8lWZF2V+98H/At0wZNb9AkCvkHv1AQAA
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '207'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- HIT
|
||||
Cf-Ray:
|
||||
- 9660e2f878e65ece-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 02:18:33 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 02:30:06 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 02:15:06 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/subjects>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=8yaTujhg33OJyCWQxIc8uLwTkG..YDTbFQWYoPxhsvs-1753669113-1.0.1.1-.rl6LsoFVw9_4z7joYt__Ss.1sswi77nnBstoSKjBueG.lOTFFpJ0x9ReoDupIuiu0uerddqDVeZd3RrHG.oNV4L5De79eOvNXI6i7Kj8oc;
|
||||
path=/; expires=Mon, 28-Jul-25 02:48:33 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- co9r9hejod050uoth270
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4850'
|
||||
X-Vcap-Request-Id:
|
||||
- aef7c66c-3c78-49e4-7cc3-e918378c24f0
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/committees?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA4VRsW7CMBDd+QrLM+Ak0FZEqjqwdyjp0qqDcY7gKrZT+4KEUP69skOAuEj1dLr3
|
||||
7t2959OEEEKoMEpJRABHc/IZev6dLlVgcYHyIFFGrPvsy1TJEWhOaJZkD7PkcZYsiyzNs2WeLD7o
|
||||
9P6M5irMvMEOrIWSFIb+YXajztdYioo9V1uwXmUD2t8QEYYda6MUWAFTshEStC+4LklhuXaNschR
|
||||
Gk3WQ0KxjDs6BLU2ZRBzTqgkiTl4bAK6Qa5LqasYb23t4T1i43LGeCPnwujKgnPzyhzYYcEuP8Rc
|
||||
cMP6TS87YxXH529n9DWhPplzIrThldTBBc1vPokK02qkOUlDqzuzLfy04HBM3cq6fm2HPNPV8unG
|
||||
QkCLs0UXA+//e/M0lqYr5piXHnma3t7bj4UT0lUEIWgcjuBNU0sRLLNYpRf3rGtm3aT7BVyDgr0J
|
||||
AwAA
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '207'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- HIT
|
||||
Cf-Ray:
|
||||
- 9660e2f9be80dabf-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 02:18:33 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 02:30:06 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 02:15:06 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/committees>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=iXYp6XrZc4tWxhyzJ9jjH5hcq2OO4L6UKBLVOAN5UH8-1753669113-1.0.1.1-_UazqDcJESlil6C98HktC2frFv3hqT2Y3FeFC5uLqHb_RJB8jb6bKDKHoTPnBqsZW7KqP5Q1rpx9kITiNNdsmDIpCouENp87bwQ1zMTlJTw;
|
||||
path=/; expires=Mon, 28-Jul-25 02:48:33 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- co9r9hg58n5afbt8pemg
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4849'
|
||||
X-Vcap-Request-Id:
|
||||
- 4c44554a-06e0-4cc5-7274-c7f75b3781b9
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/actions?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA5WTP2/CMBDFdz7FyTPFgf4TSFUHulSqOkA7VR2Mc1BXsZ3al7YI8d0rmxCSAIJm
|
||||
suKXd+9+d1l1AACYkKSs8WwEb/FFeFbVqSZ5EIRsBGyQDK4vkpuL5Ip1mzpptVZEiE23w67VV0bo
|
||||
6Du2WqOT2IWpVGjCQZgUXpwwPreORAgB422NVvHKzi89oR7bNJp6L3WSHNMWLguiD6LcjzgXuepJ
|
||||
axYOve8t7Df/vuRVT9yjEYR843g/t04Luvv01rA983XjzXsLk7eFkziNOdnoAJYKyTSWbPqvW26E
|
||||
vxS0ExQp0I+SGLE5nKNzmAJZoA/ccYMS4knUvfZ4aZnHVI+GnJ1Ef5HtwtWCHdyf7Uj6SbI3kbNX
|
||||
7DQ7uSkz7B7H+qRmTrgl2DmMy3Gfxzh2nhYSU1AGyun8k1KnthIsFwtlIu1GM0zawoSKg04tDnP4
|
||||
VaCnpnSmsuy50DN0Ee7w6raWKN6+lIl8++L19PoHGe/3h9zzYN1Y+249b4kxROgPW1eEhrYhRJ5n
|
||||
SsaWedtlYx5Uu99q3Vn/AbYTTJ2pBAAA
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '207'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- HIT
|
||||
Cf-Ray:
|
||||
- 9660e2fbb9b10384-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 02:18:34 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 02:30:06 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 02:15:07 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/actions>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=Gi2hMaZMVryZijNXh_PVd7xmlZi_yaD2BgU7McX1.Bc-1753669114-1.0.1.1-vGMObrPq8uZD66pKifiL_m2ISkT4yqS.Tfie8TSJK2RxWvLUCeqG2T6i.j4hlJyhvXkhJDulKKfi4LIEzxOpLyrbrmG2PDGxCjkMkYPNH7Y;
|
||||
path=/; expires=Mon, 28-Jul-25 02:48:34 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- co9r9hil8fnu0l5o29r0
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4849'
|
||||
X-Vcap-Request-Id:
|
||||
- a75c8f78-eac1-4bef-7236-e6e9c25a3686
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill/119/s/1947/titles?api_key=MOCK_API_KEY&format=json
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA+2STW/bMAyG7/0VhE8bkNRxPtrFwDAU6aWXpoCTHTbsoMhMrMEWVYnKmhb974OU
|
||||
5qMeurXADjvsZpCPXr5+yYcTAIDEiJXSghXpJIeHWIt1SV5zksMwlh47W9rirUfHz9GFqutr3yzQ
|
||||
Jjkk2Xh4nnSed2cbg6Hn2o25rUO9YjYuT1Nh1KkkvbLo3OmK1ul6kAYszbJx6tIg/WlJthH88bsj
|
||||
fay2exYtZONWi1HzzoQwplYy/nLaVtmKByp2nv07K64x6H/d84cQDkR4PJ3MpjfzAi4kAy2h3+uP
|
||||
jqYc2J2lS+VMLTYwiwIvkRMqAz0ctQBvSsF4KThqhWHd3nm3N55lWd4b5Nn4S7J/8Nh5yXzcE97x
|
||||
Z7ROkX4allwVbT8t8Fo0W1CzpdJLLEFpKFAHP52/FFBRkeVtPO/cexAODuP+lFfWy14R2Fk36896
|
||||
w3w0yLPRPxiYMeSUXgFXCBNfs1rHCwahS5hZUWLIcSqZjHdwsxPmypJfVTDXyJWSooaCrWBcKXT/
|
||||
w39t+BcQVIAJjKVKLRTHNRQoLbKwm5BiKFxpRqvIxqX8QkyoadBKhKWlBoTniqy6DzuV244SNdDT
|
||||
BsWtF9LX7C0CGbRx2S54DbpzrRhLKFgwuk4s4Z2svVNrBJSkqVES7kljZ+/lh2C0bme1pRCgJVkg
|
||||
rtCC8daQQ3f627OYLpcqeo6X8bazOHvDUQw/5P3+8VHEr28njz8BfyDqPsIGAAA=
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '207'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- HIT
|
||||
Cf-Ray:
|
||||
- 9660e2fd1fe69935-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 02:18:34 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 02:30:07 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 02:15:07 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill/119/s/1947/titles>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=21673RN5hnexjUTFRQK3NDYYTyLm30gOKR6zEnm3Py0-1753669114-1.0.1.1-MR9cLfSXTFBlFwCxWMFsUZLRil6MjovdzDtMeRSHI9DMHcsiIkA6nSLQyvNSB7U9RZ.nCdg7.4WmUDoKrbfwoJArVIRUX7LiIyve.461zTo;
|
||||
path=/; expires=Mon, 28-Jul-25 02:48:34 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- co9r9hkbrcticqrq6jcg
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4847'
|
||||
X-Vcap-Request-Id:
|
||||
- 6b3d2d01-307f-42bc-49d8-16718c71a26e
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,79 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill?api_key=MOCK_API_KEY&format=json&limit=1&offset=0&sort=updateDate+desc
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA4WS0W/aMBDG3/tXnPzQJyCEwZoioaoCTd3LmArrS7sHJ7kk3hxfZl/QUMX/XtnQ
|
||||
QYPa5cW27ufP35e75wsAAJEqrZ2YwmM4+u/53y4AGZnSovNMHCe9t0UtGR3fZqzIiGnnaiBkqC0k
|
||||
o5iCGA1H4/7wuh8nonfOMv5lTy1tjhZzYIIU4R4bsow5pFt4IJUhPBDjQLy5v+sYM22dovViyST+
|
||||
3HlMkFWlMvNKvkJ31Dr8kJpTHhLcdSlWrENlTZCjU6WRjMAVQiEzpRVvgYpw/mGUj7Fi/9PgOzmW
|
||||
GlZoNz6Tpkz6qmRIxkP4YskwrNgiMigDc+kcaibTg29kuYKF/E0seyBd0H4Sc6praXK0sECdomW4
|
||||
bR0rA0vtyITnYFkUKsMnMTgLsW326e67lbbJJeNJ/yb94VV/lLzPfTWZbnNlyvWhnR9cstoDFXPj
|
||||
plEkGzV4HbdBSZto8yny8xnFcRJVNvKtvCnI1pJnvxyZ4wjswu7nXl40slRGns2kyKg13tE4vp5M
|
||||
ro5ehDk4/Z+RG0eWZ8eovuHZJRWFQ57Fl1rVyq9nFg/TKSz+adFx15VhNLw+tEA2jVZZcB8FhROf
|
||||
e2FPnWhf7F4AZUIs38sDAAA=
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '2'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- EXPIRED
|
||||
Cf-Ray:
|
||||
- 9667a7c5fb972d7c-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 22:01:31 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 22:16:31 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 22:01:31 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=msfrzcgCucD2ZVRWXzewfc500khJNQeYgKlkFlYxpf0-1753740091-1.0.1.1-krI1yNcWYfZ5migq9wUvWUHgQvNwY_ezItJAIlg18M.kTupE4qTDnMDY91otQfxqIbAOE2B9D63OPUYgrzlagcGAA3xcviuuusq8JXE5eK0;
|
||||
path=/; expires=Mon, 28-Jul-25 22:31:31 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- coac71feq3f6sfr3i790
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4872'
|
||||
X-Vcap-Request-Id:
|
||||
- 7ac6de81-9ad1-4b2c-42e0-dcd0620e3242
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -0,0 +1,78 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.congress.gov/v3/bill?api_key=MOCK_API_KEY&format=json&limit=1&offset=0&sort=updateDate+desc
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAA4WSTU/jMBCG7/yKkQ+cQtNk6UatVKGqHNgLQsCeVnsYkmlq5IyNPUGLUP/7ym6h
|
||||
kGjZXDLWPH79zsfrCQCAetDGBLWAX+kYv9f3KAG15dZTiExRzLPPSYNCQVa1aMtqMbiaCEy5SxRS
|
||||
C1DltJydTauzcqayMSv0RyJ1Y7CmBiyDbAl+srYMazTEDfrsPYJrO4Giqibqk9JuYJH77oF8lD2v
|
||||
qvngWWW9bjWvt/gGXdk+0JfU2japlqshJVpMylxjrBkN3FHdey0vGVySQy8dsYDdwJ2gUAbIDdxS
|
||||
7GEDN962HrsAK+e8dV4njQCrWjIop+X30Wsvbm/jdpjpXYNCo5ZX/+Z+cG36RnN7f5jAF5e8icBW
|
||||
xIVFnqPTk7cNmbT2OX/+lseVyotinm99Hnt+sbG+Q1k+BsvHWe1S9Hsvrxy2mnG0Rqq2PUdH58V8
|
||||
NquOXhQfnP7PyEWwXpbHUqGhUJ/azSaQLItTozsd/yOLhzVSnp56CjJ0xUIs94cRoHNG18l9nhQ+
|
||||
+NwLR+qD9snuL+w4hXt+AwAA
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Age:
|
||||
- '3'
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Cf-Cache-Status:
|
||||
- MISS
|
||||
Cf-Ray:
|
||||
- 9660d2d4af481d89-PDX
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 28 Jul 2025 02:07:35 GMT
|
||||
Expires:
|
||||
- Mon, 28 Jul 2025 02:22:35 GMT
|
||||
Last-Modified:
|
||||
- Mon, 28 Jul 2025 02:07:35 GMT
|
||||
Link:
|
||||
- <https://api.congress.gov/v3/bill>; rel="canonical"
|
||||
Set-Cookie:
|
||||
- __cf_bm=LaVXOz4dBFrer3UHGhEwgOmuqh7Jf6XJxF0mGFvLnIk-1753668455-1.0.1.1-adVejehMaJvJd67c8eCTQ.tDNrqZg03wdVHxjc7TH5PcM2NUI9GT1CPksg_g9WRsui6QN26xS.D5zX4JodgT50yDEZJAQH_.i1G4OTlmu2E;
|
||||
path=/; expires=Mon, 28-Jul-25 02:37:35 GMT; domain=.congress.gov; HttpOnly
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
- Accept, Accept-Encoding
|
||||
Via:
|
||||
- https/1.1 api-umbrella (ApacheTrafficServer [cMsSf ])
|
||||
X-Api-Umbrella-Request-Id:
|
||||
- co9r4g1qb43fmk2fivjg
|
||||
X-Cache:
|
||||
- MISS
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Ratelimit-Limit:
|
||||
- '5000'
|
||||
X-Ratelimit-Remaining:
|
||||
- '4849'
|
||||
X-Vcap-Request-Id:
|
||||
- 1aca8aa0-7a74-4478-6607-51d081233558
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -0,0 +1,79 @@
|
||||
"""Congress.gov Fetchers tests."""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from openbb_congress_gov.models.bill_info import CongressBillInfoFetcher
|
||||
from openbb_congress_gov.models.bill_text import CongressBillTextFetcher
|
||||
from openbb_congress_gov.models.congress_bills import CongressBillsFetcher
|
||||
from openbb_congress_gov.utils.helpers import year_to_congress
|
||||
from openbb_core.app.service.user_service import UserService
|
||||
|
||||
test_credentials = UserService().default_user_settings.credentials.model_dump(
|
||||
mode="json"
|
||||
)
|
||||
test_credentials = (
|
||||
test_credentials
|
||||
if test_credentials and test_credentials.get("congress_gov_api_key")
|
||||
else {"congress_gov_api_key": "MOCK_API_KEY"}
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vcr_config():
|
||||
"""VCR configuration."""
|
||||
return {
|
||||
"filter_headers": [
|
||||
("User-Agent", None),
|
||||
("api_key", "MOCK_API_KEY"),
|
||||
],
|
||||
"filter_query_parameters": [
|
||||
("api_key", "MOCK_API_KEY"),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def test_year_to_congress():
|
||||
"""Test year to congress conversion."""
|
||||
current_year = datetime.now().year
|
||||
assert year_to_congress(current_year) >= 119
|
||||
assert year_to_congress(2000) == 106
|
||||
assert year_to_congress(1993) == 103
|
||||
with pytest.raises(ValueError):
|
||||
year_to_congress(1930)
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_congress_bills_fetcher(credentials=test_credentials):
|
||||
"""Test Congress Bills fetcher."""
|
||||
params = {
|
||||
"limit": 1,
|
||||
}
|
||||
|
||||
fetcher = CongressBillsFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_congress_bill_info_fetcher(credentials=test_credentials):
|
||||
"""Test Congress Bill Info fetcher."""
|
||||
params = {
|
||||
"bill_url": "119/s/1947",
|
||||
}
|
||||
|
||||
fetcher = CongressBillInfoFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_congress_bill_text_fetcher(credentials=test_credentials):
|
||||
"""Test Congress Bill Text fetcher."""
|
||||
params = {
|
||||
"urls": ["https://www.congress.gov/119/bills/s1947/BILLS-119s1947is.pdf"],
|
||||
}
|
||||
|
||||
fetcher = CongressBillTextFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
1
openbb_platform/pyproject.toml
vendored
1
openbb_platform/pyproject.toml
vendored
@@ -15,6 +15,7 @@ openbb-platform-api = "^1.1.11"
|
||||
openbb-benzinga = "^1.4.2"
|
||||
openbb-bls = "^1.1.3"
|
||||
openbb-cftc = "^1.1.2"
|
||||
openbb-congress-gov = "^1.0.0"
|
||||
openbb-econdb = "^1.3.2"
|
||||
openbb-federal-reserve = "^1.4.4"
|
||||
openbb-fmp = "^1.4.3"
|
||||
|
||||
@@ -49,11 +49,12 @@ def test_extension_map():
|
||||
)
|
||||
|
||||
for name, version in ext_map.items():
|
||||
assert name in req_ext, (
|
||||
f"'{name}' is not a required extension in pyproject.toml, uninstall it and"
|
||||
_name = "congress_gov" if name == "uscongress" else name
|
||||
assert _name in req_ext, (
|
||||
f"'{_name}' is not a required extension in pyproject.toml, uninstall it and"
|
||||
" rebuild, or add it to pyproject.toml"
|
||||
)
|
||||
assert req_ext[name].allows(version), (
|
||||
f"Version '{version}' of extension '{name}' is not compatible with the"
|
||||
f" version '{req_ext[name]}' constraint in pyproject.toml"
|
||||
assert req_ext[_name].allows(version), (
|
||||
f"Version '{version}' of extension '{_name}' is not compatible with the"
|
||||
f" version '{req_ext[_name]}' constraint in pyproject.toml"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user