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
+21 -5
View File
@@ -1,10 +1,17 @@
"""Unit tests for ferro_ta.indicators.statistic"""
import numpy as np
import pytest
from ferro_ta.indicators.statistic import (
STDDEV, VAR, BETA, CORREL,
LINEARREG, LINEARREG_ANGLE, LINEARREG_INTERCEPT, LINEARREG_SLOPE,
BETA,
CORREL,
LINEARREG,
LINEARREG_ANGLE,
LINEARREG_INTERCEPT,
LINEARREG_SLOPE,
STDDEV,
TSF,
VAR,
)
# ---------------------------------------------------------------------------
@@ -16,14 +23,15 @@ N = 100
_A = 100 + np.cumsum(RNG.normal(0, 0.5, N))
_B = 100 + np.cumsum(RNG.normal(0, 0.5, N))
LINDATA = np.arange(1.0, 6.0) # [1,2,3,4,5]
CONSTDATA = np.ones(10) # all 1.0
LINDATA = np.arange(1.0, 6.0) # [1,2,3,4,5]
CONSTDATA = np.ones(10) # all 1.0
# ---------------------------------------------------------------------------
# STDDEV
# ---------------------------------------------------------------------------
class TestSTDDEV:
def test_constant_is_zero(self):
result = STDDEV(CONSTDATA, timeperiod=5)
@@ -52,6 +60,7 @@ class TestSTDDEV:
# VAR
# ---------------------------------------------------------------------------
class TestVAR:
def test_constant_is_zero(self):
result = VAR(CONSTDATA, timeperiod=5)
@@ -77,6 +86,7 @@ class TestVAR:
# LINEARREG
# ---------------------------------------------------------------------------
class TestLINEARREG:
def test_perfect_line(self):
# For [1,2,3,4,5] over window 5, forecast = 5.0
@@ -95,6 +105,7 @@ class TestLINEARREG:
# LINEARREG_SLOPE
# ---------------------------------------------------------------------------
class TestLINEARREG_SLOPE:
def test_perfect_line_slope_one(self):
result = LINEARREG_SLOPE(LINDATA, timeperiod=5)
@@ -113,6 +124,7 @@ class TestLINEARREG_SLOPE:
# LINEARREG_INTERCEPT
# ---------------------------------------------------------------------------
class TestLINEARREG_INTERCEPT:
def test_perfect_line_intercept_one(self):
# y = [1,2,3,4,5] with x=[0,1,2,3,4] → y = 1 + 1*x → intercept = 1.0
@@ -127,6 +139,7 @@ class TestLINEARREG_INTERCEPT:
# LINEARREG_ANGLE
# ---------------------------------------------------------------------------
class TestLINEARREG_ANGLE:
def test_slope_one_gives_45_degrees(self):
result = LINEARREG_ANGLE(LINDATA, timeperiod=5)
@@ -146,6 +159,7 @@ class TestLINEARREG_ANGLE:
# BETA
# ---------------------------------------------------------------------------
class TestBETA:
def test_nan_warmup(self):
result = BETA(_A, _B, timeperiod=5)
@@ -170,6 +184,7 @@ class TestBETA:
# CORREL
# ---------------------------------------------------------------------------
class TestCOREL:
def test_self_correlation_is_one(self):
result = CORREL(_A, _A, timeperiod=10)
@@ -195,6 +210,7 @@ class TestCOREL:
# TSF
# ---------------------------------------------------------------------------
class TestTSF:
def test_perfect_line(self):
arr = np.arange(1.0, 10.0)