fix(helpers): fix type annotation bug: np.array → np.ndarray in helpers.py (TypeError on Python 3.11+) - #95
Conversation
`helpers.py` (TypeError on Python 3.11+)
|
I came from okama-mcp with the error. # python --version # Python 3.12.3
# uvx okama-mcp stdio # <-- my command
Installed 91 packages in 84ms
Traceback (most recent call last):
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/bin/okama-mcp", line 12, in <module>
sys.exit(main())
^^^^^^
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama_mcp/transport.py", line 57, in main
from okama_mcp.server import mcp
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama_mcp/server.py", line 37, in <module>
register_all(mcp)
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama_mcp/tools/__init__.py", line 14, in register_all
from okama_mcp.tools import (
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama_mcp/tools/asset.py", line 13, in <module>
import okama as ok
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama/__init__.py", line 27, in <module>
from okama.asset_list import AssetList # noqa: F401
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama/asset_list.py", line 7, in <module>
from okama.common.helpers.helpers import check_rolling_window
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama/common/helpers/helpers.py", line 225, in <module>
class Frame:
File "/tmp/.tmpshlVOC/archive-v0/dgrAM591ZcXkBhCg/lib/python3.12/site-packages/okama/common/helpers/helpers.py", line 258, in Frame
def get_portfolio_mean_return(cls, weights: list | np.array, ror: pd.DataFrame) -> float:
~~~~~^~~~~~~~~~
TypeError: unsupported operand type(s) for |: 'type' and 'builtin_function_or_method'A quick reproduction command with Docker: docker run --rm astral/uv:python3.12-bookworm-slim bash -c 'uvx okama-mcp stdio' |
chilango74
left a comment
There was a problem hiding this comment.
The code fix is correct: I reproduced the import-time TypeError on the current master with Python 3.11, verified that this branch imports successfully and resolves both weight annotations as list | np.ndarray, and ran the full suite (405 passed, 3 skipped) plus Ruff (All checks passed!).
One blocking item remains: CONTRIBUTING.md requires every contribution to be accompanied by unit tests, but this PR changes production code without a regression test. Please add a focused test, preferably in tests/test_helpers.py, that evaluates the weight annotations of both Frame.get_portfolio_mean_return and Frame.get_portfolio_risk (for example via typing.get_type_hints) and verifies list | np.ndarray. Such a test fails on the current master even under Python 3.14, where annotation evaluation is deferred, and protects this exact regression.
|
@nervgh, thank you for tracing this back to I reproduced the failure on the current Before merging, please add a focused regression test as required by Once the test is pushed, please ping me here and I will re-review and merge the PR. |
GH #95: ensure `weights` parameter annotations in `Frame.get_portfolio_mean_return` and `Frame.get_portfolio_risk` resolve to `list | np.ndarray` instead of the non-type `np.array`.
|
@chilango74 thank you for your feedback. I've made requested changes. |
chilango74
left a comment
There was a problem hiding this comment.
Thanks, the regression tests are exactly what was needed. Re-verified everything:
Bug reproduced from PyPI, import okama on Python 3.13:
| version | result |
|---|---|
| 2.2.0 | OK |
| 2.2.2 | OK |
| 2.2.3 | TypeError |
| 2.2.4 | TypeError |
| 2.3.0 | TypeError |
Fix verified: this branch imports cleanly on 3.13.
Regression tests verified RED→GREEN: with helpers.py restored from master, both new tests fail with the same TypeError under Python 3.14 (where PEP 649 makes the import itself succeed); on this branch they pass. Full suite 407 passed, 3 skipped; ruff check . and ruff format --check . clean.
One correction to the PR description for the record, since it will feed the release notes: the annotation was typing.Union[list, np.array] until commit a2b49bf ("refactor: adopt PEP 604/585 type syntax", 2026-07-01), and Union does not validate its arguments. So the crash is not present in v1.3.0–v2.2.2 — the first affected release is v2.2.3, and the affected range is v2.2.3, v2.2.4, v2.3.0. Downgrading to 2.2.2 is a valid workaround for anyone hitting this before the hotfix.
The README quotation-mark commit is unrelated to the fix; it is harmless and matches the ruff format style, so I am keeping it, but please keep unrelated changes in separate PRs in the future.
Merging now; a 2.3.1 hotfix will follow shortly. Thank you for the precise report and reproduction.
Adds .github/workflows/tests.yml with a 3.11-3.14 matrix on push and pull request. Until now the only automated checks were ruff and CodeQL, so no test ever ran in CI. This closes the gap that let #95 ship: annotations are evaluated eagerly before Python 3.14 (PEP 649), so an invalid type hint breaks `import okama` on 3.11-3.13 while passing on the 3.14 development env. Releases v2.2.3, v2.2.4 and v2.3.0 were unimportable on three of the four supported versions. The suite is fully offline (tests/conftest.py denies socket.socket), so CI needs no secrets and no network. Also adds a mandatory minimum-supported-Python run to the make-release workflow (phases 2d and 2e) and records the PEP 649 trap in AGENTS.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fY2bdqHJ5cFsxBwTw3tkz
Fix type annotation bug:
np.array→np.ndarrayinhelpers.py(TypeError on Python 3.11+)Description
Two methods in
okama/common/helpers/helpers.pyusenp.array(a function) in PEP 604 union type hints instead ofnp.ndarray(the actual type). On Python 3.11+ these annotations are evaluated eagerly at import time and crash withTypeError.Background
In
okama/common/helpers/helpers.py, classFramehas two methods annotated withlist | np.array:np.arrayis abuiltin_function_or_method, not atype. PEP 604's|operator requires both operands to be types. When Python evaluateslist | np.arrayit callslist.__or__(np.array), which receives a non-type and raises:The bug was introduced in v1.3.0 (May 2023) during a refactoring into
common/helpers/. At that time the code usedtyping.Union[list, np.array]—Unionaccepts any object and does not validate that it's a type, so the bug remained latent. When the codebase migrated to PEP 604 syntax in v1.5.0 (Python 3.10+) and then v2.0.0 (Python 3.11+), the bug became fatal —list | np.arrayis evaluated eagerly and crashes.The bug has persisted unreleased through 11 releases up to the current v2.3.0. It went unnoticed because no other module in okama directly triggers import of these
Framemethods. It manifests when external code (e.g.okama-mcpserver) callsget_portfolio_mean_returnorget_portfolio_risk.Scope
okama/common/helpers/helpers.py, replacingnp.arraywithnp.ndarray:get_portfolio_mean_return(line 258)get_portfolio_risk(line 386)np.array()calls inside the body are valid runtime invocations and must not be changed.Related
np.array— factory function →<class 'builtin_function_or_method'>np.ndarray— actual type →<class 'type'>Patch applied
File:
okama/okama/common/helpers/helpers.pyget_portfolio_mean_returnweights: list | np.arrayweights: list | np.ndarrayget_portfolio_riskweights: list | np.arrayweights: list | np.ndarrayValidation:
All checks passed!Summary by Sourcery
Enhancements: