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
24 changes: 12 additions & 12 deletions crates/fmp-py/python/fmp/_native/analyst/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,17 @@ class FinancialEstimate:
@property
def revenue_avg(self) -> builtins.float: ...
@property
def ebitda_low(self) -> builtins.float: ...
def ebitda_low(self) -> typing.Optional[builtins.float]: ...
@property
def ebitda_high(self) -> builtins.float: ...
def ebitda_high(self) -> typing.Optional[builtins.float]: ...
@property
def ebitda_avg(self) -> builtins.float: ...
def ebitda_avg(self) -> typing.Optional[builtins.float]: ...
@property
def ebit_low(self) -> builtins.float: ...
def ebit_low(self) -> typing.Optional[builtins.float]: ...
@property
def ebit_high(self) -> builtins.float: ...
def ebit_high(self) -> typing.Optional[builtins.float]: ...
@property
def ebit_avg(self) -> builtins.float: ...
def ebit_avg(self) -> typing.Optional[builtins.float]: ...
@property
def net_income_low(self) -> builtins.float: ...
@property
Expand Down Expand Up @@ -162,12 +162,12 @@ class FinancialEstimate:
revenue_low: builtins.float,
revenue_high: builtins.float,
revenue_avg: builtins.float,
ebitda_low: builtins.float,
ebitda_high: builtins.float,
ebitda_avg: builtins.float,
ebit_low: builtins.float,
ebit_high: builtins.float,
ebit_avg: builtins.float,
ebitda_low: typing.Optional[builtins.float],
ebitda_high: typing.Optional[builtins.float],
ebitda_avg: typing.Optional[builtins.float],
ebit_low: typing.Optional[builtins.float],
ebit_high: typing.Optional[builtins.float],
ebit_avg: typing.Optional[builtins.float],
net_income_low: builtins.float,
net_income_high: builtins.float,
net_income_avg: builtins.float,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class AsReportedFinancialStatement:
@property
def fiscal_year(self) -> builtins.int: ...
@property
def reported_currency(self) -> builtins.str: ...
def reported_currency(self) -> typing.Optional[builtins.str]: ...
@property
def date(self) -> datetime.date: ...
@property
Expand All @@ -41,7 +41,7 @@ class AsReportedFinancialStatement:
symbol: builtins.str,
fiscal_year: builtins.int,
period: typing.Literal["Q1", "Q2", "Q3", "Q4", "FY"],
reported_currency: builtins.str,
reported_currency: typing.Optional[builtins.str],
date: datetime.date,
data: builtins.str,
) -> AsReportedFinancialStatement: ...
Expand Down
12 changes: 6 additions & 6 deletions crates/fmp-py/python/fmp/_native/statements/income/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ class IncomeStatement:
@property
def cik(self) -> builtins.str: ...
@property
def filing_date(self) -> datetime.date: ...
def filing_date(self) -> typing.Optional[datetime.date]: ...
@property
def accepted_date(self) -> datetime.datetime: ...
def accepted_date(self) -> typing.Optional[datetime.datetime]: ...
@property
def fiscal_year(self) -> builtins.str: ...
@property
Expand All @@ -92,7 +92,7 @@ class IncomeStatement:
@property
def net_interest_income(self) -> builtins.float: ...
@property
def interest_income(self) -> builtins.float: ...
def interest_income(self) -> typing.Optional[builtins.float]: ...
@property
def interest_expense(self) -> builtins.float: ...
@property
Expand Down Expand Up @@ -141,8 +141,8 @@ class IncomeStatement:
symbol: builtins.str,
reported_currency: builtins.str,
cik: builtins.str,
filing_date: datetime.date,
accepted_date: datetime.datetime,
filing_date: typing.Optional[datetime.date],
accepted_date: typing.Optional[datetime.datetime],
fiscal_year: builtins.str,
period: typing.Literal["Q1", "Q2", "Q3", "Q4", "FY"],
revenue: builtins.float,
Expand All @@ -156,7 +156,7 @@ class IncomeStatement:
operating_expenses: builtins.float,
cost_and_expenses: builtins.float,
net_interest_income: builtins.float,
interest_income: builtins.float,
interest_income: typing.Optional[builtins.float],
interest_expense: builtins.float,
depreciation_and_amortization: builtins.float,
ebitda: builtins.float,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class KeyMetrics:
@property
def income_quality(self) -> builtins.float: ...
@property
def graham_number(self) -> builtins.float: ...
def graham_number(self) -> typing.Optional[builtins.float]: ...
@property
def graham_net_net(self) -> builtins.float: ...
@property
Expand Down Expand Up @@ -176,7 +176,7 @@ class KeyMetrics:
net_debt_to_ebitda: builtins.float,
current_ratio: builtins.float,
income_quality: builtins.float,
graham_number: builtins.float,
graham_number: typing.Optional[builtins.float],
graham_net_net: builtins.float,
tax_burden: builtins.float,
interest_burden: builtins.float,
Expand Down Expand Up @@ -289,7 +289,7 @@ class KeyMetricsTtm:
@property
def income_quality_ttm(self) -> builtins.float: ...
@property
def graham_number_ttm(self) -> builtins.float: ...
def graham_number_ttm(self) -> typing.Optional[builtins.float]: ...
@property
def graham_net_net_ttm(self) -> builtins.float: ...
@property
Expand Down Expand Up @@ -368,7 +368,7 @@ class KeyMetricsTtm:
net_debt_to_ebitda_ttm: builtins.float,
current_ratio_ttm: builtins.float,
income_quality_ttm: builtins.float,
graham_number_ttm: builtins.float,
graham_number_ttm: typing.Optional[builtins.float],
graham_net_net_ttm: builtins.float,
tax_burden_ttm: builtins.float,
interest_burden_ttm: builtins.float,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class FinancialScore:
@property
def reported_currency(self) -> builtins.str: ...
@property
def altman_z_score(self) -> builtins.float: ...
def altman_z_score(self) -> typing.Optional[builtins.float]: ...
@property
def piotroski_score(self) -> builtins.int: ...
@property
Expand All @@ -110,7 +110,7 @@ class FinancialScore:
*,
symbol: builtins.str,
reported_currency: builtins.str,
altman_z_score: builtins.float,
altman_z_score: typing.Optional[builtins.float],
piotroski_score: builtins.int,
working_capital: builtins.float,
total_assets: builtins.float,
Expand Down
24 changes: 12 additions & 12 deletions crates/fmp-py/src/models/analyst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ pub(crate) struct FinancialEstimate {
#[pyo3(get)]
pub revenue_avg: f64,
#[pyo3(get)]
pub ebitda_low: f64,
pub ebitda_low: Option<f64>,
#[pyo3(get)]
pub ebitda_high: f64,
pub ebitda_high: Option<f64>,
#[pyo3(get)]
pub ebitda_avg: f64,
pub ebitda_avg: Option<f64>,
#[pyo3(get)]
pub ebit_low: f64,
pub ebit_low: Option<f64>,
#[pyo3(get)]
pub ebit_high: f64,
pub ebit_high: Option<f64>,
#[pyo3(get)]
pub ebit_avg: f64,
pub ebit_avg: Option<f64>,
#[pyo3(get)]
pub net_income_low: f64,
#[pyo3(get)]
Expand Down Expand Up @@ -68,12 +68,12 @@ impl FinancialEstimate {
revenue_low: f64,
revenue_high: f64,
revenue_avg: f64,
ebitda_low: f64,
ebitda_high: f64,
ebitda_avg: f64,
ebit_low: f64,
ebit_high: f64,
ebit_avg: f64,
ebitda_low: Option<f64>,
ebitda_high: Option<f64>,
ebitda_avg: Option<f64>,
ebit_low: Option<f64>,
ebit_high: Option<f64>,
ebit_avg: Option<f64>,
net_income_low: f64,
net_income_high: f64,
net_income_avg: f64,
Expand Down
6 changes: 3 additions & 3 deletions crates/fmp-py/src/models/statements/as_reported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub(crate) struct AsReportedFinancialStatement {
pub fiscal_year: u32,
pub period: String,
#[pyo3(get)]
pub reported_currency: String,
pub reported_currency: Option<String>,
#[pyo3(get)]
pub date: ::chrono::NaiveDate,
data: ::serde_json::Map<String, ::serde_json::Value>,
Expand All @@ -38,7 +38,7 @@ impl AsReportedFinancialStatement {
fiscal_year: u32,
#[gen_stub(override_type(type_repr = "typing.Literal[\"Q1\", \"Q2\", \"Q3\", \"Q4\", \"FY\"]", imports = ("builtins", "typing")))]
period: String,
reported_currency: String,
reported_currency: Option<String>,
date: ::chrono::NaiveDate,
data: String,
) -> PyResult<Self> {
Expand Down Expand Up @@ -178,7 +178,7 @@ impl From<libfmp::responses::statements::as_reported::AsReportedFinancialStateme
symbol: value.symbol.into_inner(),
fiscal_year: value.fiscal_year.get(),
period: value.period.to_string(),
reported_currency: value.reported_currency.into_inner(),
reported_currency: value.reported_currency.map(|value| value.into_inner()),
date: value.date.into_inner(),
data: value.data,
}
Expand Down
16 changes: 8 additions & 8 deletions crates/fmp-py/src/models/statements/income.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pub(crate) struct IncomeStatement {
#[pyo3(get)]
pub cik: String,
#[pyo3(get)]
pub filing_date: ::chrono::NaiveDate,
pub filing_date: Option<::chrono::NaiveDate>,
#[pyo3(get)]
pub accepted_date: ::chrono::NaiveDateTime,
pub accepted_date: Option<::chrono::NaiveDateTime>,
#[pyo3(get)]
pub fiscal_year: String,
pub period: String,
Expand All @@ -47,7 +47,7 @@ pub(crate) struct IncomeStatement {
#[pyo3(get)]
pub net_interest_income: f64,
#[pyo3(get)]
pub interest_income: f64,
pub interest_income: Option<f64>,
#[pyo3(get)]
pub interest_expense: f64,
#[pyo3(get)]
Expand Down Expand Up @@ -100,8 +100,8 @@ impl IncomeStatement {
symbol: String,
reported_currency: String,
cik: String,
filing_date: ::chrono::NaiveDate,
accepted_date: ::chrono::NaiveDateTime,
filing_date: Option<::chrono::NaiveDate>,
accepted_date: Option<::chrono::NaiveDateTime>,
fiscal_year: String,
#[gen_stub(override_type(type_repr = "typing.Literal[\"Q1\", \"Q2\", \"Q3\", \"Q4\", \"FY\"]", imports = ("builtins", "typing")))]
period: String,
Expand All @@ -116,7 +116,7 @@ impl IncomeStatement {
operating_expenses: f64,
cost_and_expenses: f64,
net_interest_income: f64,
interest_income: f64,
interest_income: Option<f64>,
interest_expense: f64,
depreciation_and_amortization: f64,
ebitda: f64,
Expand Down Expand Up @@ -760,8 +760,8 @@ impl From<libfmp::responses::statements::income::IncomeStatement> for IncomeStat
symbol: value.symbol.into_inner(),
reported_currency: value.reported_currency.into_inner(),
cik: value.cik.into_inner(),
filing_date: value.filing_date.into_inner(),
accepted_date: value.accepted_date.into_inner(),
filing_date: value.filing_date.map(|value| value.into_inner()),
accepted_date: value.accepted_date.map(|value| value.into_inner()),
fiscal_year: value.fiscal_year.as_str().to_owned(),
period: value.period.to_string(),
revenue: value.revenue,
Expand Down
8 changes: 4 additions & 4 deletions crates/fmp-py/src/models/statements/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub(crate) struct KeyMetrics {
#[pyo3(get)]
pub income_quality: f64,
#[pyo3(get)]
pub graham_number: f64,
pub graham_number: Option<f64>,
#[pyo3(get)]
pub graham_net_net: f64,
#[pyo3(get)]
Expand Down Expand Up @@ -127,7 +127,7 @@ impl KeyMetrics {
net_debt_to_ebitda: f64,
current_ratio: f64,
income_quality: f64,
graham_number: f64,
graham_number: Option<f64>,
graham_net_net: f64,
tax_burden: f64,
interest_burden: f64,
Expand Down Expand Up @@ -989,7 +989,7 @@ pub(crate) struct KeyMetricsTtm {
#[pyo3(get)]
pub income_quality_ttm: f64,
#[pyo3(get)]
pub graham_number_ttm: f64,
pub graham_number_ttm: Option<f64>,
#[pyo3(get)]
pub graham_net_net_ttm: f64,
#[pyo3(get)]
Expand Down Expand Up @@ -1074,7 +1074,7 @@ impl KeyMetricsTtm {
net_debt_to_ebitda_ttm: f64,
current_ratio_ttm: f64,
income_quality_ttm: f64,
graham_number_ttm: f64,
graham_number_ttm: Option<f64>,
graham_net_net_ttm: f64,
tax_burden_ttm: f64,
interest_burden_ttm: f64,
Expand Down
4 changes: 2 additions & 2 deletions crates/fmp-py/src/models/statements/summaries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub(crate) struct FinancialScore {
#[pyo3(get)]
pub reported_currency: String,
#[pyo3(get)]
pub altman_z_score: f64,
pub altman_z_score: Option<f64>,
#[pyo3(get)]
pub piotroski_score: u64,
#[pyo3(get)]
Expand Down Expand Up @@ -192,7 +192,7 @@ impl FinancialScore {
fn new(
symbol: String,
reported_currency: String,
altman_z_score: f64,
altman_z_score: Option<f64>,
piotroski_score: u64,
working_capital: f64,
total_assets: f64,
Expand Down
14 changes: 14 additions & 0 deletions crates/fmp-py/tests/test_analyst.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ def test_financial_estimates_annual_without_options(client: Any, fixture_server:
assert row.num_analysts_eps == 7


def test_null_ebit_estimates_decode_as_none(client: Any, fixture_server: FixtureServer) -> None:
"""Issue #368: null EBIT and EBITDA estimate members decode as ``None``."""
rows = load_fixture("financial_estimates.json")
members = ("ebitdaLow", "ebitdaHigh", "ebitdaAvg", "ebitLow", "ebitHigh", "ebitAvg")
for member in members:
rows[0][member] = None
fixture_server.route("/analyst-estimates", rows)

row = client.analyst.financial_estimates("AAPL", "annual")[0]
assert (row.ebitda_low, row.ebitda_high, row.ebitda_avg) == (None, None, None)
assert (row.ebit_low, row.ebit_high, row.ebit_avg) == (None, None, None)
assert row.revenue_high == 735_022_980_353


def test_financial_estimates_quarter_with_every_option(client: Any, fixture_server: FixtureServer) -> None:
"""Encoding order is ``symbol``, ``period``, ``page``, ``limit``; ``0`` and ``u32::MAX`` are sent verbatim."""
fixture_server.route("/analyst-estimates", load_fixture("financial_estimates.json"))
Expand Down
20 changes: 20 additions & 0 deletions crates/fmp-py/tests/test_statements_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,26 @@ def test_pre_ipo_stub_rows_decode_null_amounts_as_none(client: Any, fixture_serv
assert cash_row.net_income == 112_010_000_000


def test_nullable_income_and_metrics_members_decode_as_none(client: Any, fixture_server: FixtureServer) -> None:
"""Issue #368: null income dates, ``interestIncome`` and Graham numbers decode as ``None``."""
income = load_fixture("income_statement.json")
for member in ("interestIncome", "filingDate", "acceptedDate"):
income[0][member] = None
metrics = load_fixture("key_metrics.json")
metrics[0]["grahamNumber"] = None
metrics_ttm = load_fixture("key_metrics_ttm.json")
metrics_ttm[0]["grahamNumberTTM"] = None
fixture_server.route("/income-statement", income)
fixture_server.route("/key-metrics", metrics)
fixture_server.route("/key-metrics-ttm", metrics_ttm)

income_row = client.statements.income.statement("AAPL")[0]
assert (income_row.interest_income, income_row.filing_date, income_row.accepted_date) == (None, None, None)
assert income_row.revenue == 416_161_000_000
assert client.statements.metrics.key_metrics("AAPL")[0].graham_number is None
assert client.statements.metrics.key_metrics_ttm("AAPL")[0].graham_number_ttm is None


def test_key_metrics_with_fiscal_quarter(client: Any, fixture_server: FixtureServer) -> None:
"""``metrics.key_metrics`` accepts a ``Q3`` fiscal quarter as the period."""
fixture_server.route("/key-metrics", load_fixture("key_metrics.json"))
Expand Down
11 changes: 11 additions & 0 deletions crates/fmp-py/tests/test_statements_growth.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ def test_income_as_reported_with_annual_frequency(client: Any, fixture_server: F
_assert_as_reported(rows[0], "comprehensiveincomenetoftax", 113_611_000_000)


def test_null_as_reported_currency_decodes_as_none(client: Any, fixture_server: FixtureServer) -> None:
"""Issue #368: a null ``reportedCurrency`` on an as-reported row decodes as ``None``."""
rows = load_fixture("income_statement_as_reported.json")
rows[0]["reportedCurrency"] = None
fixture_server.route("/income-statement-as-reported", rows)

row = client.statements.as_reported.income("AAPL")[0]
assert row.reported_currency is None
assert row.symbol == "AAPL"


def test_balance_sheet_as_reported_with_quarter_frequency(client: Any, fixture_server: FixtureServer) -> None:
"""``as_reported.balance_sheet`` takes ``quarter``."""
fixture_server.route(
Expand Down
Loading
Loading