Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions crates/fmp-py/python/fmp/_native/congressional/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ class CongressionalMemberNetWorthAggregate:
typing.Literal["asset_backed_securities"],
typing.Literal["business_liabilities"],
typing.Literal["mutual_funds_and_etfs"],
typing.Literal["pension_and_retirement_assets"],
typing.Literal["other_amount"],
typing.Literal["other_assets"],
typing.Literal["salary_and_wages"],
typing.Literal["trusts"],
typing.Literal["government_securities"],
typing.Literal["additional_columns"],
]

@property
Expand All @@ -153,7 +160,7 @@ class CongressionalMemberNetWorthAggregate:
@property
def real_estate_liabilities(self) -> typing.Optional[builtins.float]: ...
@property
def cash_and_cash_equivalents(self) -> builtins.float: ...
def cash_and_cash_equivalents(self) -> typing.Optional[builtins.float]: ...
@property
def business_and_self_employment(self) -> typing.Optional[builtins.float]: ...
@property
Expand All @@ -171,7 +178,21 @@ class CongressionalMemberNetWorthAggregate:
@property
def business_liabilities(self) -> typing.Optional[builtins.float]: ...
@property
def mutual_funds_and_etfs(self) -> builtins.float: ...
def mutual_funds_and_etfs(self) -> typing.Optional[builtins.float]: ...
@property
def pension_and_retirement_assets(self) -> typing.Optional[builtins.float]: ...
@property
def other_amount(self) -> typing.Optional[builtins.float]: ...
@property
def other_assets(self) -> typing.Optional[builtins.float]: ...
@property
def salary_and_wages(self) -> typing.Optional[builtins.float]: ...
@property
def trusts(self) -> typing.Optional[builtins.float]: ...
@property
def government_securities(self) -> typing.Optional[builtins.float]: ...
@property
def additional_columns(self) -> typing.Any: ...
def __eq__(self, other: builtins.object, /) -> builtins.bool: ...
def __new__(
cls,
Expand All @@ -180,7 +201,7 @@ class CongressionalMemberNetWorthAggregate:
year: builtins.int,
total: builtins.float,
real_estate_liabilities: typing.Optional[builtins.float],
cash_and_cash_equivalents: builtins.float,
cash_and_cash_equivalents: typing.Optional[builtins.float],
business_and_self_employment: typing.Optional[builtins.float],
real_estate: typing.Optional[builtins.float],
ownership_interest: typing.Optional[builtins.float],
Expand All @@ -189,7 +210,14 @@ class CongressionalMemberNetWorthAggregate:
revolving_and_credit_lines: typing.Optional[builtins.float],
asset_backed_securities: typing.Optional[builtins.float],
business_liabilities: typing.Optional[builtins.float],
mutual_funds_and_etfs: builtins.float,
mutual_funds_and_etfs: typing.Optional[builtins.float],
pension_and_retirement_assets: typing.Optional[builtins.float],
other_amount: typing.Optional[builtins.float],
other_assets: typing.Optional[builtins.float],
salary_and_wages: typing.Optional[builtins.float],
trusts: typing.Optional[builtins.float],
government_securities: typing.Optional[builtins.float],
additional_columns: builtins.str,
) -> CongressionalMemberNetWorthAggregate: ...
def __getnewargs_ex__(self) -> tuple[tuple, dict]: ...
def __repr__(self) -> builtins.str: ...
Expand Down
154 changes: 145 additions & 9 deletions crates/fmp-py/src/models/congressional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ pub(crate) struct CongressionalMemberNetWorthAggregate {
#[pyo3(get)]
pub real_estate_liabilities: Option<f64>,
#[pyo3(get)]
pub cash_and_cash_equivalents: f64,
pub cash_and_cash_equivalents: Option<f64>,
#[pyo3(get)]
pub business_and_self_employment: Option<f64>,
#[pyo3(get)]
Expand All @@ -1241,7 +1241,20 @@ pub(crate) struct CongressionalMemberNetWorthAggregate {
#[pyo3(get)]
pub business_liabilities: Option<f64>,
#[pyo3(get)]
pub mutual_funds_and_etfs: f64,
pub mutual_funds_and_etfs: Option<f64>,
#[pyo3(get)]
pub pension_and_retirement_assets: Option<f64>,
#[pyo3(get)]
pub other_amount: Option<f64>,
#[pyo3(get)]
pub other_assets: Option<f64>,
#[pyo3(get)]
pub salary_and_wages: Option<f64>,
#[pyo3(get)]
pub trusts: Option<f64>,
#[pyo3(get)]
pub government_securities: Option<f64>,
additional_columns: ::serde_json::Map<String, ::serde_json::Value>,
}

#[gen_stub_pymethods]
Expand All @@ -1250,13 +1263,13 @@ impl CongressionalMemberNetWorthAggregate {
#[new]
#[allow(clippy::too_many_arguments)]
#[allow(clippy::fn_params_excessive_bools)]
#[pyo3(signature = (*, member_id, year, total, real_estate_liabilities, cash_and_cash_equivalents, business_and_self_employment, real_estate, ownership_interest, stock, options, revolving_and_credit_lines, asset_backed_securities, business_liabilities, mutual_funds_and_etfs))]
#[pyo3(signature = (*, member_id, year, total, real_estate_liabilities, cash_and_cash_equivalents, business_and_self_employment, real_estate, ownership_interest, stock, options, revolving_and_credit_lines, asset_backed_securities, business_liabilities, mutual_funds_and_etfs, pension_and_retirement_assets, other_amount, other_assets, salary_and_wages, trusts, government_securities, additional_columns))]
fn new(
member_id: String,
year: u32,
total: f64,
real_estate_liabilities: Option<f64>,
cash_and_cash_equivalents: f64,
cash_and_cash_equivalents: Option<f64>,
business_and_self_employment: Option<f64>,
real_estate: Option<f64>,
ownership_interest: Option<f64>,
Expand All @@ -1265,9 +1278,24 @@ impl CongressionalMemberNetWorthAggregate {
revolving_and_credit_lines: Option<f64>,
asset_backed_securities: Option<f64>,
business_liabilities: Option<f64>,
mutual_funds_and_etfs: f64,
) -> Self {
Self {
mutual_funds_and_etfs: Option<f64>,
pension_and_retirement_assets: Option<f64>,
other_amount: Option<f64>,
other_assets: Option<f64>,
salary_and_wages: Option<f64>,
trusts: Option<f64>,
government_securities: Option<f64>,
additional_columns: String,
) -> PyResult<Self> {
let additional_columns = ::serde_json::from_str::<
::serde_json::Map<String, ::serde_json::Value>,
>(&additional_columns)
.map_err(|error| {
::pyo3::exceptions::PyValueError::new_err(format!(
"invalid JSON for field `additional_columns`: {error}"
))
})?;
Ok(Self {
member_id,
year,
total,
Expand All @@ -1282,14 +1310,21 @@ impl CongressionalMemberNetWorthAggregate {
asset_backed_securities,
business_liabilities,
mutual_funds_and_etfs,
}
pension_and_retirement_assets,
other_amount,
other_assets,
salary_and_wages,
trusts,
government_securities,
additional_columns,
})
}

#[classattr]
const __hash__: Option<Py<PyAny>> = None;

#[classattr]
#[gen_stub(override_return_type(type_repr = "tuple[typing.Literal['member_id'], typing.Literal['year'], typing.Literal['total'], typing.Literal['real_estate_liabilities'], typing.Literal['cash_and_cash_equivalents'], typing.Literal['business_and_self_employment'], typing.Literal['real_estate'], typing.Literal['ownership_interest'], typing.Literal['stock'], typing.Literal['options'], typing.Literal['revolving_and_credit_lines'], typing.Literal['asset_backed_securities'], typing.Literal['business_liabilities'], typing.Literal['mutual_funds_and_etfs']]", imports = ("typing",)))]
#[gen_stub(override_return_type(type_repr = "tuple[typing.Literal['member_id'], typing.Literal['year'], typing.Literal['total'], typing.Literal['real_estate_liabilities'], typing.Literal['cash_and_cash_equivalents'], typing.Literal['business_and_self_employment'], typing.Literal['real_estate'], typing.Literal['ownership_interest'], typing.Literal['stock'], typing.Literal['options'], typing.Literal['revolving_and_credit_lines'], typing.Literal['asset_backed_securities'], typing.Literal['business_liabilities'], typing.Literal['mutual_funds_and_etfs'], typing.Literal['pension_and_retirement_assets'], typing.Literal['other_amount'], typing.Literal['other_assets'], typing.Literal['salary_and_wages'], typing.Literal['trusts'], typing.Literal['government_securities'], typing.Literal['additional_columns']]", imports = ("typing",)))]
fn __match_args__(py: Python<'_>) -> PyResult<Bound<'_, PyTuple>> {
PyTuple::new(
py,
Expand All @@ -1308,6 +1343,13 @@ impl CongressionalMemberNetWorthAggregate {
"asset_backed_securities",
"business_liabilities",
"mutual_funds_and_etfs",
"pension_and_retirement_assets",
"other_amount",
"other_assets",
"salary_and_wages",
"trusts",
"government_securities",
"additional_columns",
],
)
}
Expand Down Expand Up @@ -1365,6 +1407,39 @@ impl CongressionalMemberNetWorthAggregate {
"mutual_funds_and_etfs",
self.mutual_funds_and_etfs.clone().into_bound_py_any(py)?,
)?;
kwargs.set_item(
"pension_and_retirement_assets",
self.pension_and_retirement_assets
.clone()
.into_bound_py_any(py)?,
)?;
kwargs.set_item(
"other_amount",
self.other_amount.clone().into_bound_py_any(py)?,
)?;
kwargs.set_item(
"other_assets",
self.other_assets.clone().into_bound_py_any(py)?,
)?;
kwargs.set_item(
"salary_and_wages",
self.salary_and_wages.clone().into_bound_py_any(py)?,
)?;
kwargs.set_item("trusts", self.trusts.clone().into_bound_py_any(py)?)?;
kwargs.set_item(
"government_securities",
self.government_securities.clone().into_bound_py_any(py)?,
)?;
kwargs.set_item(
"additional_columns",
::serde_json::to_string(&self.additional_columns)
.map_err(|error| {
::pyo3::exceptions::PyValueError::new_err(format!(
"failed to serialize field `additional_columns`: {error}"
))
})?
.into_bound_py_any(py)?,
)?;
Ok((PyTuple::empty(py), kwargs))
}
#[allow(clippy::clone_on_copy)]
Expand Down Expand Up @@ -1419,6 +1494,30 @@ impl CongressionalMemberNetWorthAggregate {
"mutual_funds_and_etfs",
self.mutual_funds_and_etfs.clone().into_bound_py_any(py)?,
),
(
"pension_and_retirement_assets",
self.pension_and_retirement_assets
.clone()
.into_bound_py_any(py)?,
),
(
"other_amount",
self.other_amount.clone().into_bound_py_any(py)?,
),
(
"other_assets",
self.other_assets.clone().into_bound_py_any(py)?,
),
(
"salary_and_wages",
self.salary_and_wages.clone().into_bound_py_any(py)?,
),
("trusts", self.trusts.clone().into_bound_py_any(py)?),
(
"government_securities",
self.government_securities.clone().into_bound_py_any(py)?,
),
("additional_columns", self.additional_columns(py)?),
],
)
}
Expand Down Expand Up @@ -1484,8 +1583,38 @@ impl CongressionalMemberNetWorthAggregate {
"mutual_funds_and_etfs",
crate::models::convert::DictValue::dict_value(&self.mutual_funds_and_etfs, py)?,
)?;
dict.set_item(
"pension_and_retirement_assets",
crate::models::convert::DictValue::dict_value(&self.pension_and_retirement_assets, py)?,
)?;
dict.set_item(
"other_amount",
crate::models::convert::DictValue::dict_value(&self.other_amount, py)?,
)?;
dict.set_item(
"other_assets",
crate::models::convert::DictValue::dict_value(&self.other_assets, py)?,
)?;
dict.set_item(
"salary_and_wages",
crate::models::convert::DictValue::dict_value(&self.salary_and_wages, py)?,
)?;
dict.set_item(
"trusts",
crate::models::convert::DictValue::dict_value(&self.trusts, py)?,
)?;
dict.set_item(
"government_securities",
crate::models::convert::DictValue::dict_value(&self.government_securities, py)?,
)?;
dict.set_item("additional_columns", self.additional_columns(py)?)?;
Ok(dict)
}

#[getter]
fn additional_columns<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
crate::models::convert::object_to_py(py, &self.additional_columns)
}
}

impl From<libfmp::responses::congressional::CongressionalMemberNetWorthAggregate>
Expand All @@ -1507,6 +1636,13 @@ impl From<libfmp::responses::congressional::CongressionalMemberNetWorthAggregate
asset_backed_securities: value.asset_backed_securities,
business_liabilities: value.business_liabilities,
mutual_funds_and_etfs: value.mutual_funds_and_etfs,
pension_and_retirement_assets: value.pension_and_retirement_assets,
other_amount: value.other_amount,
other_assets: value.other_assets,
salary_and_wages: value.salary_and_wages,
trusts: value.trusts,
government_securities: value.government_securities,
additional_columns: value.additional_columns,
}
}
}
Expand Down
28 changes: 26 additions & 2 deletions crates/fmp-py/tests/test_congressional_b.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

import datetime
import pickle
from types import SimpleNamespace
from typing import Any

Expand Down Expand Up @@ -167,7 +168,7 @@ def test_net_worth_aggregated_with_member_id_only(client: Any, fixture_server: F
rows = client.congressional.net_worth_aggregated(MEMBER_ID)

assert fixture_server.requests[0].target == "/senate-net-worth-aggregated?senateID=P000197"
assert len(rows) == 1
assert len(rows) == 5
row = rows[0]
assert isinstance(row, CongressionalMemberNetWorthAggregate)
assert row.member_id == MEMBER_ID
Expand All @@ -178,6 +179,29 @@ def test_net_worth_aggregated_with_member_id_only(client: Any, fixture_server: F
assert row.business_and_self_employment == 0
assert row.mutual_funds_and_etfs == 32_501
assert row.revolving_and_credit_lines == 1_500_002
assert row.additional_columns == {}


def test_net_worth_aggregated_optional_typed_and_additional_columns(
client: Any, fixture_server: FixtureServer
) -> None:
"""Absent cash or mutual funds decode as ``None``; unmodeled columns land in ``additional_columns``."""
fixture_server.route("/senate-net-worth-aggregated", load_fixture("congress_senate_net_worth_aggregated.json"))
rows = client.congressional.net_worth_aggregated(MEMBER_ID)

assert rows[1].cash_and_cash_equivalents is None
assert rows[1].pension_and_retirement_assets == 250_001
assert rows[2].mutual_funds_and_etfs is None
assert rows[2].government_securities == 15_001
assert rows[3].salary_and_wages == 174_000
assert rows[3].additional_columns == {"pensionAndRetirementIncome": 5001, "spousalIncome": 201}
assert rows[4].other_amount == 1_001
assert rows[4].other_assets == 2_001
assert rows[4].trusts == 0
assert isinstance(rows[4].additional_columns, dict)
assert rows[4].additional_columns == {}
assert rows[3].to_dict()["additional_columns"] == {"pensionAndRetirementIncome": 5001, "spousalIncome": 201}
assert pickle.loads(pickle.dumps(rows[3])) == rows[3]


def test_net_worth_aggregated_with_totals_col(client: Any, fixture_server: FixtureServer) -> None:
Expand All @@ -186,7 +210,7 @@ def test_net_worth_aggregated_with_totals_col(client: Any, fixture_server: Fixtu
rows = client.congressional.net_worth_aggregated(MEMBER_ID, totals_col="stock")

assert fixture_server.requests[0].target == "/senate-net-worth-aggregated?senateID=P000197&totalsCol=stock"
assert len(rows) == 1
assert len(rows) == 5
assert rows[0].total == 225_219_551


Expand Down
4 changes: 3 additions & 1 deletion crates/fmp-py/tests/typecheck_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ def check_congressional_contract(client: FmpClient) -> None:
value: float | None = entries[0].value
total: float = totals[0].total
options: float | None = totals[0].options
_ = (disclosed, gains, born, years_active, value_range, value, total, options)
cash: float | None = totals[0].cash_and_cash_equivalents
other: float | None = totals[0].other_amount
_ = (disclosed, gains, born, years_active, value_range, value, total, options, cash, other)


def check_funds_contract(client: FmpClient) -> None:
Expand Down
Loading
Loading