refactor: rename update command to upgrade

- Align CLI verb with pipx/pip terminology (`pipx upgrade`).
- Rename internal `self_update` to `self_upgrade` for consistency.
- Update README and tests accordingly.
- Bump version to 2.0.4.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 18:50:14 +08:00
parent cdc90a9be1
commit b857ea33f3
5 changed files with 13 additions and 13 deletions

View File

@@ -91,11 +91,11 @@ coinhunter opportunity portfolio
coinhunter opportunity scan coinhunter opportunity scan
coinhunter opportunity scan --symbols BTCUSDT ETHUSDT SOLUSDT coinhunter opportunity scan --symbols BTCUSDT ETHUSDT SOLUSDT
# Self-update # Self-upgrade
coinhunter update coinhunter upgrade
``` ```
`update` will try `pipx upgrade coinhunter` first, and fall back to `pip install --upgrade coinhunter` if pipx is not available. `upgrade` will try `pipx upgrade coinhunter` first, and fall back to `pip install --upgrade coinhunter` if pipx is not available.
## Architecture ## Architecture

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "coinhunter" name = "coinhunter"
version = "2.0.3" version = "2.0.4"
description = "Binance-first trading CLI for balances, market data, opportunity scanning, and execution." description = "Binance-first trading CLI for balances, market data, opportunity scanning, and execution."
readme = "README.md" readme = "README.md"
license = {text = "MIT"} license = {text = "MIT"}

View File

@@ -10,7 +10,7 @@ from . import __version__
from .binance.spot_client import SpotBinanceClient from .binance.spot_client import SpotBinanceClient
from .binance.um_futures_client import UMFuturesClient from .binance.um_futures_client import UMFuturesClient
from .config import ensure_init_files, get_binance_credentials, load_config from .config import ensure_init_files, get_binance_credentials, load_config
from .runtime import get_runtime_paths, print_output, self_update from .runtime import get_runtime_paths, print_output, self_upgrade
from .services import account_service, market_service, opportunity_service, trade_service from .services import account_service, market_service, opportunity_service, trade_service
EPILOG = """\ EPILOG = """\
@@ -22,7 +22,7 @@ examples:
coinhunter trade spot buy BTCUSDT -q 100 -d coinhunter trade spot buy BTCUSDT -q 100 -d
coinhunter trade futures sell BTCUSDT -q 0.01 -r coinhunter trade futures sell BTCUSDT -q 0.01 -r
coinhunter opportunity scan -s BTCUSDT ETHUSDT coinhunter opportunity scan -s BTCUSDT ETHUSDT
coinhunter update coinhunter upgrade
""" """
@@ -120,7 +120,7 @@ def build_parser() -> argparse.ArgumentParser:
scan_parser = opportunity_subparsers.add_parser("scan", help="Scan market for opportunities") scan_parser = opportunity_subparsers.add_parser("scan", help="Scan market for opportunities")
scan_parser.add_argument("-s", "--symbols", nargs="*", metavar="SYM", help="Restrict scan to specific symbols") scan_parser.add_argument("-s", "--symbols", nargs="*", metavar="SYM", help="Restrict scan to specific symbols")
subparsers.add_parser("update", help="Upgrade coinhunter to the latest version") subparsers.add_parser("upgrade", help="Upgrade coinhunter to the latest version")
return parser return parser
@@ -258,8 +258,8 @@ def main(argv: list[str] | None = None) -> int:
return 0 return 0
parser.error("opportunity requires `portfolio` or `scan`") parser.error("opportunity requires `portfolio` or `scan`")
if args.command == "update": if args.command == "upgrade":
print_output(self_update(), agent=args.agent) print_output(self_upgrade(), agent=args.agent)
return 0 return 0
parser.error(f"Unsupported command {args.command}") parser.error(f"Unsupported command {args.command}")

View File

@@ -58,7 +58,7 @@ def print_json(payload: Any) -> None:
print(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True, default=json_default)) print(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True, default=json_default))
def self_update() -> dict[str, Any]: def self_upgrade() -> dict[str, Any]:
if shutil.which("pipx"): if shutil.which("pipx"):
cmd = ["pipx", "upgrade", "coinhunter"] cmd = ["pipx", "upgrade", "coinhunter"]
else: else:

View File

@@ -37,11 +37,11 @@ class CLITestCase(unittest.TestCase):
self.assertEqual(result, 1) self.assertEqual(result, 1)
self.assertIn("error: boom", stderr.getvalue()) self.assertIn("error: boom", stderr.getvalue())
def test_update_dispatches(self): def test_upgrade_dispatches(self):
captured = {} captured = {}
with patch.object(cli, "self_update", return_value={"command": "pipx upgrade coinhunter", "returncode": 0}), patch.object( with patch.object(cli, "self_upgrade", return_value={"command": "pipx upgrade coinhunter", "returncode": 0}), patch.object(
cli, "print_output", side_effect=lambda payload, **kwargs: captured.setdefault("payload", payload) cli, "print_output", side_effect=lambda payload, **kwargs: captured.setdefault("payload", payload)
): ):
result = cli.main(["update"]) result = cli.main(["upgrade"])
self.assertEqual(result, 0) self.assertEqual(result, 0)
self.assertEqual(captured["payload"]["returncode"], 0) self.assertEqual(captured["payload"]["returncode"], 0)