Skip to content

Commit 48094bd

Browse files
dgunningclaude
andcommitted
Standardize parameter naming: replace standardize with standard=True
Fix issue #403 by removing the inconsistent 'standardize' parameter and using only 'standard=True' throughout the stitched statements API. Changes: - Replace standardize parameter with standard=True in all StitchedStatements methods - Update internal APIs (XBRLS.get_statement, StitchedFactsView.get_facts) to use standard parameter - Update documentation examples to use standard=True consistently - Add comprehensive regression and verification tests - Maintain same functionality while simplifying the API All statement methods now consistently accept: - statements.income_statement(standard=True/False) - statements.balance_sheet(standard=True/False) - statements.cashflow_statement(standard=True/False) - statements.statement_of_equity(standard=True/False) - statements.comprehensive_income(standard=True/False) Resolves the documentation inconsistency where docs showed standard=True but methods only accepted standardize parameter. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e56ec80 commit 48094bd

File tree

7 files changed

+422
-31
lines changed

7 files changed

+422
-31
lines changed

docs/guides/extract-statements.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,10 +398,10 @@ print(income_with_dates)
398398

399399
```python
400400
# Use standardized labels for cross-company comparison (default)
401-
standardized = statements.income_statement(standardize=True)
401+
standardized = statements.income_statement(standard=True)
402402

403403
# Use company-specific labels as reported in filing
404-
company_specific = statements.income_statement(standardize=False)
404+
company_specific = statements.income_statement(standard=False)
405405

406406
print("Standardized Labels:")
407407
print(standardized.to_dataframe()['label'].head(10))

edgar/xbrl/statements.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ class StitchedStatement:
925925
financial statement from multiple filings.
926926
"""
927927

928-
def __init__(self, xbrls, statement_type: str, max_periods: int = 8, standardize: bool = True,
928+
def __init__(self, xbrls, statement_type: str, max_periods: int = 8, standard: bool = True,
929929
use_optimal_periods: bool = True, include_dimensions: bool = False):
930930
"""
931931
Initialize with XBRLS object and statement parameters.
@@ -934,14 +934,14 @@ def __init__(self, xbrls, statement_type: str, max_periods: int = 8, standardize
934934
xbrls: XBRLS object containing stitched data
935935
statement_type: Type of statement ('BalanceSheet', 'IncomeStatement', etc.)
936936
max_periods: Maximum number of periods to include
937-
standardize: Whether to use standardized concept labels
937+
standard: Whether to use standardized concept labels
938938
use_optimal_periods: Whether to use entity info to determine optimal periods
939939
include_dimensions: Whether to include dimensional segment data (default: False for stitching)
940940
"""
941941
self.xbrls = xbrls
942942
self.statement_type = statement_type
943943
self.max_periods = max_periods
944-
self.standardize = standardize
944+
self.standard = standard
945945
self.use_optimal_periods = use_optimal_periods
946946
self.include_dimensions = include_dimensions
947947
self.show_date_range = False # Default to not showing date ranges
@@ -972,7 +972,7 @@ def statement_data(self):
972972
self._statement_data = self.xbrls.get_statement(
973973
self.statement_type,
974974
self.max_periods,
975-
self.standardize,
975+
self.standard,
976976
self.use_optimal_periods,
977977
self.include_dimensions
978978
)
@@ -1041,97 +1041,97 @@ def __init__(self, xbrls):
10411041
"""
10421042
self.xbrls = xbrls
10431043

1044-
def balance_sheet(self, max_periods: int = 8, standardize: bool = True,
1044+
def balance_sheet(self, max_periods: int = 8, standard: bool = True,
10451045
use_optimal_periods: bool = True, show_date_range: bool = False) -> Optional[StitchedStatement]:
10461046
"""
10471047
Get a stitched balance sheet across multiple time periods.
10481048
10491049
Args:
10501050
max_periods: Maximum number of periods to include
1051-
standardize: Whether to use standardized concept labels
1051+
standard: Whether to use standardized concept labels
10521052
use_optimal_periods: Whether to use entity info to determine optimal periods
10531053
show_date_range: Whether to show full date ranges for duration periods
10541054
10551055
Returns:
10561056
StitchedStatement for the balance sheet
10571057
"""
1058-
statement = StitchedStatement(self.xbrls, 'BalanceSheet', max_periods, standardize, use_optimal_periods)
1058+
statement = StitchedStatement(self.xbrls, 'BalanceSheet', max_periods, standard, use_optimal_periods)
10591059
if show_date_range:
10601060
statement.show_date_range = show_date_range
10611061
return statement
10621062

1063-
def income_statement(self, max_periods: int = 8, standardize: bool = True,
1063+
def income_statement(self, max_periods: int = 8, standard: bool = True,
10641064
use_optimal_periods: bool = True, show_date_range: bool = False) -> Optional[StitchedStatement]:
10651065
"""
10661066
Get a stitched income statement across multiple time periods.
10671067
10681068
Args:
10691069
max_periods: Maximum number of periods to include
1070-
standardize: Whether to use standardized concept labels
1070+
standard: Whether to use standardized concept labels
10711071
use_optimal_periods: Whether to use entity info to determine optimal periods
10721072
show_date_range: Whether to show full date ranges for duration periods
10731073
10741074
Returns:
10751075
StitchedStatement for the income statement
10761076
"""
1077-
statement = StitchedStatement(self.xbrls, 'IncomeStatement', max_periods, standardize, use_optimal_periods)
1077+
statement = StitchedStatement(self.xbrls, 'IncomeStatement', max_periods, standard, use_optimal_periods)
10781078
if show_date_range:
10791079
statement.show_date_range = show_date_range
10801080
return statement
10811081

1082-
def cashflow_statement(self, max_periods: int = 8, standardize: bool = True,
1082+
def cashflow_statement(self, max_periods: int = 8, standard: bool = True,
10831083
use_optimal_periods: bool = True, show_date_range: bool = False) -> Optional[StitchedStatement]:
10841084
"""
10851085
Get a stitched cash flow statement across multiple time periods.
10861086
10871087
Args:
10881088
max_periods: Maximum number of periods to include
1089-
standardize: Whether to use standardized concept labels
1089+
standard: Whether to use standardized concept labels
10901090
use_optimal_periods: Whether to use entity info to determine optimal periods
10911091
show_date_range: Whether to show full date ranges for duration periods
10921092
10931093
Returns:
10941094
StitchedStatement for the cash flow statement
10951095
"""
1096-
statement = StitchedStatement(self.xbrls, 'CashFlowStatement', max_periods, standardize, use_optimal_periods)
1096+
statement = StitchedStatement(self.xbrls, 'CashFlowStatement', max_periods, standard, use_optimal_periods)
10971097
if show_date_range:
10981098
statement.show_date_range = show_date_range
10991099
return statement
11001100

1101-
def statement_of_equity(self, max_periods: int = 8, standardize: bool = True,
1101+
def statement_of_equity(self, max_periods: int = 8, standard: bool = True,
11021102
use_optimal_periods: bool = True, show_date_range: bool = False) -> Optional[StitchedStatement]:
11031103
"""
11041104
Get a stitched statement of changes in equity across multiple time periods.
11051105
11061106
Args:
11071107
max_periods: Maximum number of periods to include
1108-
standardize: Whether to use standardized concept labels
1108+
standard: Whether to use standardized concept labels
11091109
use_optimal_periods: Whether to use entity info to determine optimal periods
11101110
show_date_range: Whether to show full date ranges for duration periods
11111111
11121112
Returns:
11131113
StitchedStatement for the statement of equity
11141114
"""
1115-
statement = StitchedStatement(self.xbrls, 'StatementOfEquity', max_periods, standardize, use_optimal_periods)
1115+
statement = StitchedStatement(self.xbrls, 'StatementOfEquity', max_periods, standard, use_optimal_periods)
11161116
if show_date_range:
11171117
statement.show_date_range = show_date_range
11181118
return statement
11191119

1120-
def comprehensive_income(self, max_periods: int = 8, standardize: bool = True,
1120+
def comprehensive_income(self, max_periods: int = 8, standard: bool = True,
11211121
use_optimal_periods: bool = True, show_date_range: bool = False) -> Optional[StitchedStatement]:
11221122
"""
11231123
Get a stitched statement of comprehensive income across multiple time periods.
11241124
11251125
Args:
11261126
max_periods: Maximum number of periods to include
1127-
standardize: Whether to use standardized concept labels
1127+
standard: Whether to use standardized concept labels
11281128
use_optimal_periods: Whether to use entity info to determine optimal periods
11291129
show_date_range: Whether to show full date ranges for duration periods
11301130
11311131
Returns:
11321132
StitchedStatement for the comprehensive income statement
11331133
"""
1134-
statement = StitchedStatement(self.xbrls, 'ComprehensiveIncome', max_periods, standardize, use_optimal_periods)
1134+
statement = StitchedStatement(self.xbrls, 'ComprehensiveIncome', max_periods, standard, use_optimal_periods)
11351135
if show_date_range:
11361136
statement.show_date_range = show_date_range
11371137
return statement

edgar/xbrl/stitching/query.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,21 @@ def document_type(self):
5454

5555
def get_facts(self,
5656
max_periods: int = 8,
57-
standardize: bool = True,
57+
standard: bool = True,
5858
statement_types: Optional[List[str]] = None) -> List[Dict[str, Any]]:
5959
"""
6060
Extract facts from stitched statements.
6161
6262
Args:
6363
max_periods: Maximum periods to include
64-
standardize: Whether to use standardized labels
64+
standard: Whether to use standardized labels
6565
statement_types: List of statement types to include
6666
6767
Returns:
6868
List of fact dictionaries with stitched/standardized data
6969
"""
7070
# Create cache key
71-
cache_key = (max_periods, standardize, tuple(statement_types or []))
71+
cache_key = (max_periods, standard, tuple(statement_types or []))
7272
if self._facts_cache and self._last_cache_key == cache_key:
7373
return self._facts_cache
7474

@@ -85,7 +85,7 @@ def get_facts(self,
8585
stitched_data = self.xbrls.get_statement(
8686
statement_type=statement_type,
8787
max_periods=max_periods,
88-
standardize=standardize
88+
standard=standard
8989
)
9090

9191
# Extract facts from stitched data
@@ -276,7 +276,7 @@ def __init__(self, stitched_facts_view: StitchedFactsView, **kwargs):
276276

277277
# Store query-specific parameters for get_facts
278278
self._max_periods = kwargs.get('max_periods', 8)
279-
self._standardize = kwargs.get('standardize', True)
279+
self._standard = kwargs.get('standard', True)
280280
self._statement_types = kwargs.get('statement_types', None)
281281

282282
def __str__(self):
@@ -400,7 +400,7 @@ def execute(self) -> List[Dict[str, Any]]:
400400
# Get base results from stitched facts with query parameters
401401
results = self._stitched_facts_view.get_facts(
402402
max_periods=self._max_periods,
403-
standardize=self._standardize,
403+
standard=self._standard,
404404
statement_types=self._statement_types
405405
)
406406

edgar/xbrl/stitching/xbrls.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def query(self,
135135

136136
def get_statement(self, statement_type: str,
137137
max_periods: int = 8,
138-
standardize: bool = True,
138+
standard: bool = True,
139139
use_optimal_periods: bool = True,
140140
include_dimensions: bool = False) -> Dict[str, Any]:
141141
"""
@@ -144,15 +144,15 @@ def get_statement(self, statement_type: str,
144144
Args:
145145
statement_type: Type of statement to stitch ('IncomeStatement', 'BalanceSheet', etc.)
146146
max_periods: Maximum number of periods to include
147-
standardize: Whether to use standardized concept labels
147+
standard: Whether to use standardized concept labels
148148
use_optimal_periods: Whether to use entity info to determine optimal periods
149149
include_dimensions: Whether to include dimensional segment data (default: False for stitching)
150150
151151
Returns:
152152
Dictionary with stitched statement data
153153
"""
154154
# Check cache first
155-
cache_key = f"{statement_type}_{max_periods}_{standardize}_{use_optimal_periods}_{include_dimensions}"
155+
cache_key = f"{statement_type}_{max_periods}_{standard}_{use_optimal_periods}_{include_dimensions}"
156156
if cache_key in self._statement_cache:
157157
return self._statement_cache[cache_key]
158158

@@ -162,7 +162,7 @@ def get_statement(self, statement_type: str,
162162
statement_type=statement_type,
163163
period_type=StatementStitcher.PeriodType.ALL_PERIODS,
164164
max_periods=max_periods,
165-
standard=standardize,
165+
standard=standard,
166166
use_optimal_periods=use_optimal_periods,
167167
include_dimensions=include_dimensions
168168
)
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
"""
2+
Regression test for GitHub issue #403: Support standard=True in stitched statements
3+
4+
This test ensures that the 'standard' parameter support in stitched statements
5+
doesn't regress in future changes.
6+
7+
Issue URL: https://github.com/dgunning/edgartools/issues/403
8+
"""
9+
10+
import pytest
11+
from unittest.mock import MagicMock
12+
from edgar.xbrl.statements import StitchedStatements
13+
from edgar.xbrl.stitching.xbrls import XBRLS
14+
15+
16+
class TestIssue403Regression:
17+
"""Regression test for standard parameter in stitched statements."""
18+
19+
def setup_method(self):
20+
"""Set up mock objects for testing."""
21+
self.mock_xbrls = MagicMock(spec=XBRLS)
22+
self.statements = StitchedStatements(self.mock_xbrls)
23+
24+
def test_all_statement_methods_accept_standard_parameter(self):
25+
"""
26+
Regression test: All statement methods must accept 'standard' parameter.
27+
28+
This prevents accidental removal of the standard parameter in future changes.
29+
"""
30+
# List of all statement methods that should accept 'standard' parameter
31+
statement_methods = [
32+
'income_statement',
33+
'balance_sheet',
34+
'cashflow_statement',
35+
'statement_of_equity',
36+
'comprehensive_income'
37+
]
38+
39+
# Test that each method accepts standard=True without raising TypeError
40+
for method_name in statement_methods:
41+
method = getattr(self.statements, method_name)
42+
43+
# This should not raise TypeError
44+
try:
45+
method(standard=True)
46+
method(standard=False)
47+
except TypeError as e:
48+
if "unexpected keyword argument 'standard'" in str(e):
49+
pytest.fail(f"Method {method_name} does not accept 'standard' parameter: {e}")
50+
# Other TypeErrors might be expected (e.g., from mocked dependencies)
51+
except Exception:
52+
# Other exceptions are fine - we're only testing parameter acceptance
53+
pass
54+
55+
def test_standard_parameter_works(self):
56+
"""
57+
Regression test: 'standard' parameter works correctly.
58+
59+
This ensures the standard parameter continues to work.
60+
"""
61+
from unittest.mock import patch
62+
63+
# Test with income_statement as representative
64+
with patch('edgar.xbrl.statements.StitchedStatement') as mock_stitched:
65+
# Test standard parameter works
66+
self.statements.income_statement(standard=True)
67+
68+
# Verify the call was made with standard=True
69+
args, kwargs = mock_stitched.call_args
70+
standard_value = args[3] # standard is 4th positional arg
71+
72+
assert standard_value == True, "standard parameter should work correctly"
73+
74+
def test_standard_false_works(self):
75+
"""
76+
Test: 'standard=False' parameter works correctly.
77+
78+
This ensures standard=False continues to work.
79+
"""
80+
from unittest.mock import patch
81+
82+
with patch('edgar.xbrl.statements.StitchedStatement') as mock_stitched:
83+
# Test standard=False
84+
self.statements.income_statement(standard=False)
85+
86+
# Verify the call was made correctly
87+
args, kwargs = mock_stitched.call_args
88+
standard_value = args[3] # standard is 4th positional arg
89+
90+
assert standard_value == False, "standard=False parameter should work correctly"
91+
92+
def test_parameter_defaults_regression(self):
93+
"""
94+
Regression test: Parameter defaults must be maintained.
95+
96+
This ensures default behavior doesn't change.
97+
"""
98+
import inspect
99+
100+
# Check parameter defaults for all methods
101+
statement_methods = [
102+
'income_statement',
103+
'balance_sheet',
104+
'cashflow_statement',
105+
'statement_of_equity',
106+
'comprehensive_income'
107+
]
108+
109+
for method_name in statement_methods:
110+
method = getattr(self.statements, method_name)
111+
sig = inspect.signature(method)
112+
113+
# Verify defaults
114+
assert sig.parameters['standard'].default == True, \
115+
f"{method_name}: standard default should be True"
116+
117+
118+
def test_issue_403_does_not_regress():
119+
"""
120+
Meta regression test: Ensure the original issue does not regress.
121+
122+
This test simulates the original user's problem and ensures it stays fixed.
123+
"""
124+
# Create a mock scenario like the original issue
125+
mock_xbrls = MagicMock(spec=XBRLS)
126+
statements = mock_xbrls.statements = StitchedStatements(mock_xbrls)
127+
128+
# The original issue: This should not raise TypeError
129+
try:
130+
stmt = statements.income_statement(standard=True)
131+
# Test passes if no exception is raised
132+
except TypeError as e:
133+
if "unexpected keyword argument 'standard'" in str(e):
134+
pytest.fail(f"Issue #403 has regressed: {e}")
135+
# Re-raise other TypeErrors that might be legitimate
136+
raise
137+
138+
139+
if __name__ == "__main__":
140+
print("Running regression tests for issue #403...")
141+
pytest.main([__file__, "-v"])

0 commit comments

Comments
 (0)