Summary
src/jquantstats/_portfolio_cost.py and src/jquantstats/_portfolio_attribution.py each carry their own if TYPE_CHECKING: block of read-only @property stubs describing attributes that are actually defined on sibling mixins (so each mixin type-checks in isolation). The same names are declared in more than one place, which is duplicated boilerplate that can drift.
These stubs were introduced to satisfy mypy --strict (consistent read-only property declarations across the mixins that compose Portfolio).
Where
src/jquantstats/_portfolio_cost.py — TYPE_CHECKING block with @property stubs: data, returns, turnover, profit
src/jquantstats/_portfolio_attribution.py — overlapping TYPE_CHECKING stubs (e.g. returns, nav_accumulated, assets, data)
Proposed change
Hoist a single shared declaration — e.g. a PortfolioLike-style Protocol (matching the pattern already used in _reports/_protocol.py, _plots/_protocol.py, _utils/_protocol.py) or one shared TYPE_CHECKING base — that the cost/attribution mixins reference instead of each re-declaring the cross-mixin attributes.
Acceptance criteria
Context
Surfaced by a Rhiza quality assessment — the only locally-owned item below 10 (Code structure & readability, 9→10). Low effort, no runtime impact.
Summary
src/jquantstats/_portfolio_cost.pyandsrc/jquantstats/_portfolio_attribution.pyeach carry their ownif TYPE_CHECKING:block of read-only@propertystubs describing attributes that are actually defined on sibling mixins (so each mixin type-checks in isolation). The same names are declared in more than one place, which is duplicated boilerplate that can drift.These stubs were introduced to satisfy
mypy --strict(consistent read-only property declarations across the mixins that composePortfolio).Where
src/jquantstats/_portfolio_cost.py—TYPE_CHECKINGblock with@propertystubs:data,returns,turnover,profitsrc/jquantstats/_portfolio_attribution.py— overlappingTYPE_CHECKINGstubs (e.g.returns,nav_accumulated,assets,data)Proposed change
Hoist a single shared declaration — e.g. a
PortfolioLike-styleProtocol(matching the pattern already used in_reports/_protocol.py,_plots/_protocol.py,_utils/_protocol.py) or one sharedTYPE_CHECKINGbase — that the cost/attribution mixins reference instead of each re-declaring the cross-mixin attributes.Acceptance criteria
TYPE_CHECKINGstub blocks are replaced by one shared declaration.make typecheck(bothtyandmypy --strict) stays green.make teststays green at 100% coverage.Context
Surfaced by a Rhiza quality assessment — the only locally-owned item below 10 (Code structure & readability, 9→10). Low effort, no runtime impact.