Skip to content

Hoist function-local imports in _portfolio_cost.py and document the accessor import cycle #891

Description

@tschm

Subcategory: Overall architecture

Current score: 8/10 → Target: 10/10

The architecture is otherwise clean (hub-and-spoke accessor design, private _-prefixed
module split, Protocol-based decoupling). Two concrete, low-risk items hold it back:

1. Avoidable function-local imports in _portfolio_cost.py

src/jquantstats/_portfolio_cost.py:184-186 imports inside a method body:

import numpy as np
from ._stats._core import _std_is_negligible
  • numpy is already a top-level runtime dependency (declared in pyproject.toml), so
    there is no lazy-loading benefit.
  • _std_is_negligible lives in src/jquantstats/_stats/_core.py, which does not
    import _portfolio_cost, so hoisting it creates no import cycle. _stats/_performance.py:13
    already imports it at module top the normal way.

These belong at module top with the existing import math / import polars as pl block
(lines 5-10). Function-local imports here just obscure the module's real dependency surface.

2. Document the accessor import cycle

data.py and the _stats / _plots / _reports subpackages form a genuine circular
dependency that is broken with lazy imports inside the .stats / .plots / .report /
.utils accessor properties (src/jquantstats/data.py:523-559) and TYPE_CHECKING
DataLike protocol imports. This is a legitimate pandas-style pattern, but it is currently
undocumented, so a future contributor may "helpfully" hoist one of these imports and
reintroduce a hard cycle. Add a short comment at each lazy-import site (or a note in
CLAUDE.md Architecture) stating the imports are intentionally deferred to break the
data <-> accessors cycle.

Done when

  • _portfolio_cost.py performs numpy and _std_is_negligible imports at module top and
    make typecheck + make test still pass.
  • Each remaining intentional lazy import in data.py accessors carries a one-line comment
    explaining the cycle it breaks (or the pattern is documented in CLAUDE.md).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions