fix: resolve merge conflicts and lint issues
- Merge origin/main changes (flattened buy/sell commands, --doc flag, aliases) - Fix spinner placement for buy/sell commands - Fix duplicate alias key 'p' in canonical subcommands - Remove unused mypy ignore comments in spot_client.py - Fix nested with statements in tests Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,10 @@ from __future__ import annotations
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
from requests.exceptions import RequestException, SSLError # type: ignore[import-untyped]
|
||||
from requests.exceptions import ( # type: ignore[import-untyped]
|
||||
RequestException,
|
||||
SSLError,
|
||||
)
|
||||
|
||||
|
||||
class SpotBinanceClient:
|
||||
@@ -56,7 +59,7 @@ class SpotBinanceClient:
|
||||
response = self._call("24h ticker", self._client.ticker_24hr, symbol=symbols[0])
|
||||
else:
|
||||
response = self._call("24h ticker", self._client.ticker_24hr, symbols=symbols)
|
||||
return response if isinstance(response, list) else [response] # type: ignore[no-any-return]
|
||||
return response if isinstance(response, list) else [response]
|
||||
|
||||
def ticker_price(self, symbols: list[str] | None = None) -> list[dict[str, Any]]:
|
||||
if not symbols:
|
||||
@@ -65,7 +68,7 @@ class SpotBinanceClient:
|
||||
response = self._call("ticker price", self._client.ticker_price, symbol=symbols[0])
|
||||
else:
|
||||
response = self._call("ticker price", self._client.ticker_price, symbols=symbols)
|
||||
return response if isinstance(response, list) else [response] # type: ignore[no-any-return]
|
||||
return response if isinstance(response, list) else [response]
|
||||
|
||||
def klines(self, symbol: str, interval: str, limit: int) -> list[list[Any]]:
|
||||
return self._call("klines", self._client.klines, symbol=symbol, interval=interval, limit=limit) # type: ignore[no-any-return]
|
||||
|
||||
@@ -10,8 +10,19 @@ from . import __version__
|
||||
from .audit import read_audit_log
|
||||
from .binance.spot_client import SpotBinanceClient
|
||||
from .config import ensure_init_files, get_binance_credentials, load_config
|
||||
from .runtime import get_runtime_paths, install_shell_completion, print_output, self_upgrade, with_spinner
|
||||
from .services import account_service, market_service, opportunity_service, trade_service
|
||||
from .runtime import (
|
||||
get_runtime_paths,
|
||||
install_shell_completion,
|
||||
print_output,
|
||||
self_upgrade,
|
||||
with_spinner,
|
||||
)
|
||||
from .services import (
|
||||
account_service,
|
||||
market_service,
|
||||
opportunity_service,
|
||||
trade_service,
|
||||
)
|
||||
|
||||
EPILOG = """\
|
||||
examples:
|
||||
@@ -294,7 +305,6 @@ _CANONICAL_SUBCOMMANDS = {
|
||||
"t": "tickers",
|
||||
"k": "klines",
|
||||
"pf": "portfolio",
|
||||
"p": "portfolio",
|
||||
}
|
||||
|
||||
_COMMANDS_WITH_SUBCOMMANDS = {"account", "market", "opportunity"}
|
||||
|
||||
@@ -8,7 +8,12 @@ import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from coinhunter.config import ensure_init_files, get_binance_credentials, load_config, load_env_file
|
||||
from coinhunter.config import (
|
||||
ensure_init_files,
|
||||
get_binance_credentials,
|
||||
load_config,
|
||||
load_env_file,
|
||||
)
|
||||
from coinhunter.runtime import get_runtime_paths
|
||||
|
||||
|
||||
@@ -89,6 +94,8 @@ class ConfigRuntimeTestCase(unittest.TestCase):
|
||||
),
|
||||
):
|
||||
paths = get_runtime_paths()
|
||||
with patch("coinhunter.config.ensure_runtime_dirs", side_effect=PermissionError("no write access")):
|
||||
with self.assertRaisesRegex(RuntimeError, "Set COINHUNTER_HOME to a writable directory"):
|
||||
ensure_init_files(paths)
|
||||
with (
|
||||
patch("coinhunter.config.ensure_runtime_dirs", side_effect=PermissionError("no write access")),
|
||||
self.assertRaisesRegex(RuntimeError, "Set COINHUNTER_HOME to a writable directory"),
|
||||
):
|
||||
ensure_init_files(paths)
|
||||
|
||||
@@ -57,9 +57,11 @@ class TradeServiceTestCase(unittest.TestCase):
|
||||
self.assertEqual(client.calls[0]["timeInForce"], "GTC")
|
||||
|
||||
def test_spot_market_buy_requires_quote(self):
|
||||
with patch.object(trade_service, "audit_event", return_value=None):
|
||||
with self.assertRaisesRegex(RuntimeError, "requires --quote"):
|
||||
trade_service.execute_spot_trade(
|
||||
with (
|
||||
patch.object(trade_service, "audit_event", return_value=None),
|
||||
self.assertRaisesRegex(RuntimeError, "requires --quote"),
|
||||
):
|
||||
trade_service.execute_spot_trade(
|
||||
{"trading": {"dry_run_default": False}},
|
||||
side="buy",
|
||||
symbol="BTCUSDT",
|
||||
@@ -72,9 +74,11 @@ class TradeServiceTestCase(unittest.TestCase):
|
||||
)
|
||||
|
||||
def test_spot_market_buy_rejects_qty(self):
|
||||
with patch.object(trade_service, "audit_event", return_value=None):
|
||||
with self.assertRaisesRegex(RuntimeError, "accepts --quote only"):
|
||||
trade_service.execute_spot_trade(
|
||||
with (
|
||||
patch.object(trade_service, "audit_event", return_value=None),
|
||||
self.assertRaisesRegex(RuntimeError, "accepts --quote only"),
|
||||
):
|
||||
trade_service.execute_spot_trade(
|
||||
{"trading": {"dry_run_default": False}},
|
||||
side="buy",
|
||||
symbol="BTCUSDT",
|
||||
@@ -87,9 +91,11 @@ class TradeServiceTestCase(unittest.TestCase):
|
||||
)
|
||||
|
||||
def test_spot_market_sell_rejects_quote(self):
|
||||
with patch.object(trade_service, "audit_event", return_value=None):
|
||||
with self.assertRaisesRegex(RuntimeError, "accepts --qty only"):
|
||||
trade_service.execute_spot_trade(
|
||||
with (
|
||||
patch.object(trade_service, "audit_event", return_value=None),
|
||||
self.assertRaisesRegex(RuntimeError, "accepts --qty only"),
|
||||
):
|
||||
trade_service.execute_spot_trade(
|
||||
{"trading": {"dry_run_default": False}},
|
||||
side="sell",
|
||||
symbol="BTCUSDT",
|
||||
|
||||
Reference in New Issue
Block a user