release: cut v1.0.0

Prepare the first public 1.0.0 release and finish the remaining CI hardening work.

Highlights:
- align Python, Rust, WASM, Conda, API, MCP, and docs version metadata to 1.0.0
- promote package metadata to Production/Stable and update stability/versioning docs for the stable series
- move the accumulated Unreleased notes into a dated 1.0.0 changelog section and keep a fresh top-level Unreleased block
- strengthen the changelog checker so it validates a single top-level Unreleased section
- fix the CI/package support mismatch by declaring Python >=3.10 consistently and gating pandas-ta extras to Python 3.12+
- restore Sphinx autodoc compatibility for documented ferro_ta.<module> imports by registering module aliases
- make the TA-Lib benchmark guardrail less flaky by checking median and tail-percentile speedups instead of failing on a single mild outlier
- switch PyPI publishing to OIDC-only trusted publishing and wire the changelog check into the required CI gate
- apply the Ruff-driven cleanup across the Python and test tree and refresh uv/cargo lockfiles

Validated locally:
- python3 scripts/check_changelog.py
- uv run --with ruff ruff check python tests
- uv run --with ruff ruff format --check python tests
- uv lock --check
- sphinx-build -b html docs docs/_build -W --keep-going
- build/install the ferro_ta 1.0.0 wheel successfully
This commit is contained in:
Pratik Bhadane
2026-03-23 23:57:30 +05:30
parent 7a5a220dfe
commit 307beeca02
47 changed files with 1822 additions and 573 deletions
+99 -64
View File
@@ -57,6 +57,17 @@ array([ nan, nan, 11. , 12. , 13. , 13.5, 13.33...])
from __future__ import annotations
import sys as _sys
# ---------------------------------------------------------------------------
# Exceptions — exported at the top level for convenient catching
# ---------------------------------------------------------------------------
from ferro_ta.core.exceptions import ( # noqa: F401
FerroTAError,
FerroTAInputError,
FerroTAValueError,
)
# ---------------------------------------------------------------------------
# Cycle Indicators
# ---------------------------------------------------------------------------
@@ -69,15 +80,6 @@ from ferro_ta.indicators.cycle import ( # noqa: F401
HT_TRENDMODE,
)
# ---------------------------------------------------------------------------
# Exceptions — exported at the top level for convenient catching
# ---------------------------------------------------------------------------
from ferro_ta.core.exceptions import ( # noqa: F401
FerroTAError,
FerroTAInputError,
FerroTAValueError,
)
# ---------------------------------------------------------------------------
# Math Operators & Math Transforms
# ---------------------------------------------------------------------------
@@ -476,21 +478,6 @@ __all__ = [
# ---------------------------------------------------------------------------
from ferro_ta._utils import pandas_wrap as _pandas_wrap # noqa: E402
from ferro_ta._utils import polars_wrap as _polars_wrap # noqa: E402
# ---------------------------------------------------------------------------
# Additional modules (not in __all__ — access via submodule)
# ---------------------------------------------------------------------------
from ferro_ta.tools.alerts import ( # noqa: F401, E402
AlertManager,
check_cross,
check_threshold,
collect_alert_bars,
)
# ---------------------------------------------------------------------------
# API discovery helpers — ferro_ta.indicators() and ferro_ta.info()
# ---------------------------------------------------------------------------
from ferro_ta.tools.api_info import indicators, info # noqa: F401, E402
from ferro_ta.analysis.attribution import ( # noqa: F401, E402
TradeStats,
attribution_by_month,
@@ -498,6 +485,36 @@ from ferro_ta.analysis.attribution import ( # noqa: F401, E402
from_backtest,
trade_stats,
)
from ferro_ta.analysis.crypto import ( # noqa: F401, E402
continuous_bar_labels,
funding_pnl,
resample_continuous,
session_boundaries,
)
from ferro_ta.analysis.regime import ( # noqa: F401, E402
detect_breaks_cusum,
regime,
regime_adx,
regime_combined,
rolling_variance_break,
structural_breaks,
)
from ferro_ta.core import exceptions as exceptions # noqa: F401, E402
# ---------------------------------------------------------------------------
# Logging utilities — ferro_ta.enable_debug() / ferro_ta.benchmark()
# ---------------------------------------------------------------------------
from ferro_ta.core.logging_utils import ( # noqa: F401, E402
benchmark,
debug_mode,
disable_debug,
enable_debug,
get_logger,
log_call,
traced,
)
from ferro_ta.data import batch as batch # noqa: F401, E402
from ferro_ta.data import streaming as streaming # noqa: F401, E402
# ---------------------------------------------------------------------------
# Batch API (not in __all__ — use directly from ferro_ta.batch)
@@ -515,45 +532,6 @@ from ferro_ta.data.chunked import ( # noqa: F401, E402
stitch_chunks,
trim_overlap,
)
from ferro_ta.analysis.crypto import ( # noqa: F401, E402
continuous_bar_labels,
funding_pnl,
resample_continuous,
session_boundaries,
)
from ferro_ta.indicators.extended import ( # noqa: F401, E402
CHANDELIER_EXIT,
CHOPPINESS_INDEX,
DONCHIAN,
HULL_MA,
ICHIMOKU,
KELTNER_CHANNELS,
PIVOT_POINTS,
SUPERTREND,
VWAP,
VWMA,
)
# ---------------------------------------------------------------------------
# Logging utilities — ferro_ta.enable_debug() / ferro_ta.benchmark()
# ---------------------------------------------------------------------------
from ferro_ta.core.logging_utils import ( # noqa: F401, E402
benchmark,
debug_mode,
disable_debug,
enable_debug,
get_logger,
log_call,
traced,
)
from ferro_ta.analysis.regime import ( # noqa: F401, E402
detect_breaks_cusum,
regime,
regime_adx,
regime_combined,
rolling_variance_break,
structural_breaks,
)
# ---------------------------------------------------------------------------
# Streaming / Incremental API (not in __all__ — these are classes, not funcs)
@@ -570,6 +548,63 @@ from ferro_ta.data.streaming import ( # noqa: F401, E402 # type: ignore[assign
StreamingSupertrend, # type: ignore[attr-defined]
StreamingVWAP, # type: ignore[attr-defined]
)
from ferro_ta.indicators import cycle as cycle # noqa: F401, E402
from ferro_ta.indicators import extended as extended # noqa: F401, E402
from ferro_ta.indicators import math_ops as math_ops # noqa: F401, E402
from ferro_ta.indicators import momentum as momentum # noqa: F401, E402
from ferro_ta.indicators import overlap as overlap # noqa: F401, E402
from ferro_ta.indicators import pattern as pattern # noqa: F401, E402
from ferro_ta.indicators import price_transform as price_transform # noqa: F401, E402
from ferro_ta.indicators import statistic as statistic # noqa: F401, E402
from ferro_ta.indicators import volatility as volatility # noqa: F401, E402
from ferro_ta.indicators import volume as volume # noqa: F401, E402
from ferro_ta.indicators.extended import ( # noqa: F401, E402
CHANDELIER_EXIT,
CHOPPINESS_INDEX,
DONCHIAN,
HULL_MA,
ICHIMOKU,
KELTNER_CHANNELS,
PIVOT_POINTS,
SUPERTREND,
VWAP,
VWMA,
)
# ---------------------------------------------------------------------------
# Additional modules (not in __all__ — access via submodule)
# ---------------------------------------------------------------------------
from ferro_ta.tools.alerts import ( # noqa: F401, E402
AlertManager,
check_cross,
check_threshold,
collect_alert_bars,
)
# ---------------------------------------------------------------------------
# API discovery helpers — ferro_ta.indicators() and ferro_ta.info()
# ---------------------------------------------------------------------------
from ferro_ta.tools.api_info import indicators, info # noqa: F401, E402
_ALIASED_SUBMODULES = {
"batch": batch,
"cycle": cycle,
"exceptions": exceptions,
"extended": extended,
"math_ops": math_ops,
"momentum": momentum,
"overlap": overlap,
"pattern": pattern,
"price_transform": price_transform,
"statistic": statistic,
"streaming": streaming,
"volatility": volatility,
"volume": volume,
}
for _module_name, _module in _ALIASED_SUBMODULES.items():
setattr(_sys.modules[__name__], _module_name, _module)
_sys.modules[f"{__name__}.{_module_name}"] = _module
_g = globals()
for _name in __all__:
@@ -579,4 +614,4 @@ for _name in __all__:
_fn = _g.get(_name)
if callable(_fn) and not getattr(_fn, "_polars_wrapped", False):
_g[_name] = _polars_wrap(_fn)
del _g, _name, _fn
del _ALIASED_SUBMODULES, _g, _module, _module_name, _name, _fn, _sys
+1 -1
View File
@@ -28,8 +28,8 @@ from collections.abc import Callable
from typing import Any, Optional
from ferro_ta._utils import _to_f64
from ferro_ta.core.exceptions import _normalize_rust_error
from ferro_ta.core.exceptions import (
_normalize_rust_error,
check_equal_length,
check_timeperiod,
)
+2
View File
@@ -1,5 +1,7 @@
"""Backward-compat stub — moved to ``ferro_ta.core.logging_utils``."""
from ferro_ta.core.logging_utils import * # noqa: F401, F403
try:
from ferro_ta.core.logging_utils import __all__ # noqa: F401
except ImportError:
+1 -1
View File
@@ -392,7 +392,7 @@ def _run_stdio_fallback() -> None: # pragma: no cover
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {"tools": {}},
"serverInfo": {"name": "ferro-ta", "version": "0.1.0"},
"serverInfo": {"name": "ferro-ta", "version": "1.0.0"},
},
}
elif method == "tools/list":
-1
View File
@@ -27,4 +27,3 @@ from ferro_ta.tools.tools import ( # noqa: F401
list_indicators,
run_backtest,
)
+1 -1
View File
@@ -40,10 +40,10 @@ True
from __future__ import annotations
import warnings
from typing import Any, Optional
import numpy as np
import warnings
from numpy.typing import ArrayLike, NDArray
__all__ = [