Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

All notable changes to DeepTrade. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and SemVer.

## [v0.15.1] — 2026-05-27 — 上限 typer<0.26(vendored click 导致 CLI 整树构建失败)

修复一个安装期回归:`deeptrade` 任意命令启动即崩。**Typer 0.26.0 把 click 硬 fork 成自带的 vendored 副本**(`typer/_click/`),并从依赖里删掉了对独立 `click` 的声明。本仓库的 CLI 设计**同时**用了两边:`cli.py::_DeepTradeGroup` 继承 `typer.core.TyperGroup`(>=0.26 走 vendored click),而 `db_cmd(ctx: click.Context)`、插件 pass-through 的裸 `@click.command` 与 `@click.pass_context` 用的是独立 `click`。两个 click 是两个不同的类,Typer 构建命令树时用 `lenient_issubclass(param.annotation, typer._click.Context)` 识别 context 形参,独立的 `click.core.Context` 识别不出来 → 当成普通 CLI 参数 → `RuntimeError: Type not yet supported: <class 'click.core.Context'>`。这会让**整棵命令树**构建失败,任何子命令(用户实测 `plugin upgrade`)都进不去。

dev/CI 没暴露是因为 `uv.lock` 锁的是 typer **0.25.0**(最后一个未 vendor、仍 `click>=8.2.1` 的版本);只有 `pipx install` 这类按 `typer>=0.12` 重新解析的环境会拉到 0.26.2。

### Fixed

- **`pyproject.toml` 把 `typer>=0.12` 收紧为 `typer>=0.12,<0.26`。** 恢复"Typer 与本仓库共用同一个 click"的不变量。这同时堵住一个潜伏的运行期 bug:插件分发(`deeptrade <plugin_id> …`)从 Typer group 里返回的是独立 click 构造的命令,在 vendored-click Typer 下同样会行为异常。
- 已有 pipx 安装的临时自救(无需等发布):`pipx runpip deeptrade-quant install "typer<0.26"` 把 venv 内的 typer 降回 0.25.x 即可恢复。

## [v0.15.0] — 2026-05-25 — yaml cache_overrides 自动注入(消除"声明僵尸文本")

修复一个跨插件的契约 bug:插件在 `deeptrade_plugin.yaml::permissions.tushare_apis.cache_overrides` 里声明了某个 Tushare API 的 cache class(例如 `cyq_perf: trade_day_mutable`),但 yaml 只参与安装期校验,**运行时并不会被框架自动注入到 TushareClient**。需要插件作者在调用 `make_tushare_client(cache_overrides=...)` 时显式传一遍同样的 dict —— 一旦插件绕开 helper、直接 `TushareClient(...)`(出于自定义 transport / event_cb / rps 的需要),yaml 声明就完全变成"僵尸文本",运行时仍会打 `Tushare API 'cyq_perf' has no explicit cache class; defaulting to trade_day_immutable` 的 INFO 警告,且实际使用的也是默认 `trade_day_immutable` 而非声明值。已知 `limit-up-board / accumulation-probe-washout / checkmate` 三个插件都中招。
Expand Down
9 changes: 5 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@ CI (`.github/workflows/ci.yml`) runs ruff → mypy → pytest → `python -m bui

## Releasing

The package version lives in **two** places and they MUST be bumped together:
The package version lives in **three** places and they MUST be bumped together:

- `pyproject.toml::project.version` — what hatchling stamps onto the wheel filename and PyPI metadata. **This is the source of truth for the build.**
- `deeptrade/__init__.py::__version__` — runtime introspection only.
- `README.md` version badge (`version-X.Y.Z-blue` in the shields.io URL) — display only, but **`tests/test_version_consistency.py` fails CI if it drifts** from the other two, so a stale badge blocks the release.

Bumping only `__init__.py` will silently produce a wheel with the previous version in its filename and tank the release at PyPI upload (HTTP 400 "File already exists" — PyPI filenames are immutable, you cannot overwrite). Always grep both files before tagging:
Bumping only `__init__.py` will silently produce a wheel with the previous version in its filename and tank the release at PyPI upload (HTTP 400 "File already exists" — PyPI filenames are immutable, you cannot overwrite). Forgetting the badge fails the test suite before you ever tag. Always grep all three before tagging:

```bash
grep -n version pyproject.toml deeptrade/__init__.py
grep -n version pyproject.toml deeptrade/__init__.py README.md
```

Release sequence:
1. Bump both files + update `CHANGELOG.md` in the same commit (or two adjacent commits).
1. Bump all three version sources + update `CHANGELOG.md` in the same commit (or two adjacent commits).
2. Push to main and verify CI green.
3. `git tag -a vX.Y.Z -m "..."` then `git push origin vX.Y.Z` — the tag push is what triggers `release.yml`.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

> 📖 **在线文档**:[deeptrade.tiey.ai](https://deeptrade.tiey.ai) — 用户手册 + 开发者手册 + 官方插件目录

[![tests](https://img.shields.io/badge/tests-passing-brightgreen)](#) [![python](https://img.shields.io/badge/python-3.11+-blue)](#) [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE) [![version](https://img.shields.io/badge/version-0.14.0-blue)](CHANGELOG.md)
[![tests](https://img.shields.io/badge/tests-passing-brightgreen)](#) [![python](https://img.shields.io/badge/python-3.11+-blue)](#) [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE) [![version](https://img.shields.io/badge/version-0.15.1-blue)](CHANGELOG.md)

## ✨ 主要特性

Expand Down
2 changes: 1 addition & 1 deletion deeptrade/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

from __future__ import annotations

__version__ = "0.15.0"
__version__ = "0.15.1"
__all__ = ["__version__"]
11 changes: 9 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "deeptrade-quant"
version = "0.15.0"
version = "0.15.1"
description = "LLM-driven A-share (Shanghai/Shenzhen main board) stock screening CLI"
readme = "README.md"
requires-python = ">=3.11"
Expand All @@ -13,7 +13,14 @@ license = { text = "MIT" }
keywords = ["stock", "a-share", "llm", "tushare", "deepseek", "duckdb", "cli"]

dependencies = [
"typer>=0.12",
# Cap below 0.26: Typer 0.26.0 hard-forked its own vendored copy of click
# (typer/_click/) and dropped the standalone `click` dependency. This repo
# subclasses typer.core.TyperGroup *and* uses standalone click directly
# (raw @click.command plugin pass-through, @click.pass_context,
# click.Context). That design assumes Typer and the app share ONE click;
# under >=0.26 the two click copies diverge and the command tree fails to
# build ("Type not yet supported: <class 'click.core.Context'>").
"typer>=0.12,<0.26",
"questionary>=2.0",
"rich>=13.7",
"duckdb>=1.0",
Expand Down
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading