diff --git a/binance/async_client.py b/binance/async_client.py index f0a623f4e..73844e7f0 100644 --- a/binance/async_client.py +++ b/binance/async_client.py @@ -38,11 +38,12 @@ def __init__( private_key_pass: Optional[str] = None, https_proxy: Optional[str] = None, time_unit: Optional[str] = None, + verbose: bool = False, ): self.https_proxy = https_proxy self.loop = loop or get_loop() self._session_params: Dict[str, Any] = session_params or {} - + # Convert https_proxy to requests_params format for BaseClient if https_proxy and requests_params is None: requests_params = {'proxies': {'http': https_proxy, 'https': https_proxy}} @@ -50,7 +51,7 @@ def __init__( if 'proxies' not in requests_params: requests_params['proxies'] = {} requests_params['proxies'].update({'http': https_proxy, 'https': https_proxy}) - + super().__init__( api_key, api_secret, @@ -62,6 +63,7 @@ def __init__( private_key, private_key_pass, time_unit=time_unit, + verbose=verbose, ) @classmethod @@ -80,6 +82,7 @@ async def create( private_key_pass: Optional[str] = None, https_proxy: Optional[str] = None, time_unit: Optional[str] = None, + verbose: bool = False, ): self = cls( api_key, @@ -94,7 +97,8 @@ async def create( private_key, private_key_pass, https_proxy, - time_unit + time_unit, + verbose ) self.https_proxy = https_proxy # move this to the constructor @@ -175,6 +179,20 @@ async def _request( **kwargs, ) as response: self.response = response + + if self.verbose: + response_text = await response.text() + self.logger.debug( + "\nRequest: %s %s\nRequestHeaders: %s\nRequestBody: %s\nResponse: %s\nResponseHeaders: %s\nResponseBody: %s", + method.upper(), + uri, + headers, + data, + response.status, + dict(response.headers), + response_text[:1000] if response_text else None + ) + return await self._handle_response(response) async def _handle_response(self, response: aiohttp.ClientResponse): diff --git a/binance/base_client.py b/binance/base_client.py index b7ae76d74..d6423048b 100644 --- a/binance/base_client.py +++ b/binance/base_client.py @@ -6,6 +6,7 @@ import asyncio import hashlib import hmac +import logging import time from Crypto.PublicKey import RSA, ECC from Crypto.Hash import SHA256 @@ -167,6 +168,7 @@ def __init__( private_key_pass: Optional[str] = None, loop: Optional[asyncio.AbstractEventLoop] = None, time_unit: Optional[str] = None, + verbose: bool = False, ): """Binance API Client constructor @@ -184,10 +186,19 @@ def __init__( :type private_key_pass: optional - str :param time_unit: Time unit to use for requests. Supported values: "MILLISECOND", "MICROSECOND" :type time_unit: optional - str + :param verbose: Enable verbose logging for debugging + :type verbose: bool """ self.tld = tld + self.verbose = verbose + self.logger = logging.getLogger(__name__) + + # Set logger level based on verbose flag + # Users can override this by configuring logging externally + if verbose: + self.logger.setLevel(logging.DEBUG) self.API_URL = self.API_URL.format(base_endpoint, tld) self.MARGIN_API_URL = self.MARGIN_API_URL.format(base_endpoint, tld) self.WEBSITE_URL = self.WEBSITE_URL.format(tld) diff --git a/binance/client.py b/binance/client.py index 5774469e5..e14f7ae95 100755 --- a/binance/client.py +++ b/binance/client.py @@ -34,6 +34,7 @@ def __init__( private_key_pass: Optional[str] = None, ping: Optional[bool] = True, time_unit: Optional[str] = None, + verbose: bool = False, ): super().__init__( api_key, @@ -46,6 +47,7 @@ def __init__( private_key, private_key_pass, time_unit=time_unit, + verbose=verbose, ) # init DNS and SSL cert @@ -88,6 +90,19 @@ def _request( data = f"{url_encoded_data}&signature={signature}" self.response = getattr(self.session, method)(uri, headers=headers, data=data, **kwargs) + + if self.verbose: + self.logger.debug( + "\nRequest: %s %s\nRequestHeaders: %s\nRequestBody: %s\nResponse: %s\nResponseHeaders: %s\nResponseBody: %s", + method.upper(), + uri, + headers, + data, + self.response.status_code, + dict(self.response.headers), + self.response.text[:1000] if self.response.text else None + ) + return self._handle_response(self.response) @staticmethod diff --git a/binance/ws/streams.py b/binance/ws/streams.py index 33d5f3bea..f3f27fe8b 100755 --- a/binance/ws/streams.py +++ b/binance/ws/streams.py @@ -2,6 +2,7 @@ import time from enum import Enum from typing import Optional, List, Dict, Callable, Any +import logging from binance.ws.constants import KEEPALIVE_TIMEOUT from binance.ws.keepalive_websocket import KeepAliveWebsocket @@ -40,10 +41,11 @@ class BinanceSocketManager: WEBSOCKET_DEPTH_20 = "20" def __init__( - self, - client: AsyncClient, + self, + client: AsyncClient, user_timeout=KEEPALIVE_TIMEOUT, max_queue_size: int = 100, + verbose: bool = False, ): """Initialise the BinanceSocketManager @@ -52,6 +54,8 @@ def __init__( :param user_timeout: Timeout for user socket in seconds :param max_queue_size: Max size of the websocket queue, defaults to 100 :type max_queue_size: int + :param verbose: Enable verbose logging for WebSocket connections + :type verbose: bool """ self.STREAM_URL = self.STREAM_URL.format(client.tld) self.FSTREAM_URL = self.FSTREAM_URL.format(client.tld) @@ -65,8 +69,12 @@ def __init__( self.testnet = self._client.testnet self.demo = self._client.demo self._max_queue_size = max_queue_size + self.verbose = verbose self.ws_kwargs = {} + if verbose: + logging.getLogger('binance.ws').setLevel(logging.DEBUG) + def _get_stream_url(self, stream_url: Optional[str] = None): if stream_url: return stream_url @@ -871,7 +879,7 @@ def multiplex_socket(self, streams: List[str]): def options_multiplex_socket(self, streams: List[str]): """Start a multiplexed socket using a list of socket names. - + https://developers.binance.com/docs/derivatives/option/websocket-market-streams """ @@ -966,7 +974,6 @@ def margin_socket(self): stream_url = self.STREAM_DEMO_URL return self._get_account_socket("margin", stream_url=stream_url) - def futures_socket(self): """Start a websocket for futures data @@ -1040,7 +1047,7 @@ def options_ticker_socket(self, symbol: str): API Reference: https://developers.binance.com/docs/derivatives/option/websocket-market-streams/24-hour-TICKER - Stream provides real-time 24hr ticker information for all symbols. Only symbols whose ticker info + Stream provides real-time 24hr ticker information for all symbols. Only symbols whose ticker info changed will be sent. Updates every 1000ms. :param symbol: The option symbol to subscribe to (e.g. "BTC-220930-18000-C") @@ -1065,7 +1072,7 @@ def options_ticker_by_expiration_socket(self, symbol: str, expiration_date: str) def options_recent_trades_socket(self, symbol: str): """Subscribe to a real-time trade information stream. - + API Reference: https://developers.binance.com/docs/derivatives/option/websocket-market-streams/Trade-Streams Stream pushes raw trade information for a specific symbol or underlying asset. @@ -1080,7 +1087,7 @@ def options_kline_socket( self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE ): """Subscribe to a Kline/Candlestick data stream. - + API Reference: https://developers.binance.com/docs/derivatives/option/websocket-market-streams/Kline-Candlestick-Streams Stream pushes updates to the current klines/candlestick every 1000ms (if existing). diff --git a/binance/ws/threaded_stream.py b/binance/ws/threaded_stream.py index 47993e0c6..8bf6eb6e4 100755 --- a/binance/ws/threaded_stream.py +++ b/binance/ws/threaded_stream.py @@ -18,14 +18,28 @@ def __init__( session_params: Optional[Dict[str, Any]] = None, https_proxy: Optional[str] = None, _loop: Optional[asyncio.AbstractEventLoop] = None, + verbose: bool = False, ): - """Initialise the BinanceSocketManager""" + """Initialise the ThreadedApiManager + + :param api_key: Binance API key + :param api_secret: Binance API secret + :param requests_params: optional - Dictionary of requests params + :param tld: optional - Top level domain, default is 'com' + :param testnet: optional - Use testnet endpoint + :param session_params: optional - Session params for aiohttp + :param https_proxy: optional - Proxy URL + :param _loop: optional - Event loop + :param verbose: Enable verbose logging for WebSocket connections + :type verbose: bool + """ super().__init__() self._loop: asyncio.AbstractEventLoop = get_loop() if _loop is None else _loop self._client: Optional[AsyncClient] = None self._running: bool = True self._socket_running: Dict[str, bool] = {} self._log = logging.getLogger(__name__) + self.verbose = verbose self._client_params = { "api_key": api_key, "api_secret": api_secret, @@ -34,8 +48,12 @@ def __init__( "testnet": testnet, "session_params": session_params, "https_proxy": https_proxy, + "verbose": verbose, } + if verbose: + logging.getLogger('binance.ws').setLevel(logging.DEBUG) + async def _before_socket_listener_start(self): ... async def socket_listener(self): diff --git a/docs/faqs.rst b/docs/faqs.rst index 43eb2d3cc..db8c9558f 100644 --- a/docs/faqs.rst +++ b/docs/faqs.rst @@ -20,3 +20,15 @@ Check recvWindow is an integer and not a string. *A2*: You may need to regenerate your API Key and Secret *A3*: You may be attempting to access the API from a Chinese IP address, these are now restricted by Binance. + +*Q: How can I debug API issues?* + +*A*: Enable verbose mode to see detailed request and response information: + +.. code:: python + + client = Client(api_key, api_secret, verbose=True) + +This will log all HTTP requests and responses, including headers, body, and status codes. This is particularly helpful for debugging authentication issues, understanding API behavior, and troubleshooting network problems. + +See the Logging section in the `Getting Started guide `_ for more details. diff --git a/docs/overview.rst b/docs/overview.rst index fa8f0dca3..f0d6cedd6 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -276,4 +276,201 @@ For more detailed logging with timestamps and log levels: format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', ) +Verbose Mode +~~~~~~~~~~~~ + +Verbose mode provides detailed logging of all HTTP requests and responses, which is particularly useful for debugging API issues, understanding request/response formats, and troubleshooting authentication or network problems. + +Method 1: Using the verbose Parameter (Recommended for Quick Debugging) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable verbose mode by passing ``verbose=True`` when creating the client: + +.. code:: python + + from binance.client import Client + import logging + + # Configure logging (optional - for seeing the output) + logging.basicConfig(level=logging.DEBUG) + + # Enable verbose mode + client = Client(api_key, api_secret, verbose=True) + + # All API calls will now log detailed information + server_time = client.get_server_time() + +For AsyncClient: + +.. code:: python + + import asyncio + import logging + from binance.async_client import AsyncClient + + logging.basicConfig(level=logging.DEBUG) + + async def main(): + # Enable verbose mode + client = await AsyncClient.create(api_key, api_secret, verbose=True) + + # All API calls will now log detailed information + server_time = await client.get_server_time() + + await client.close_connection() + + if __name__ == "__main__": + asyncio.run(main()) + +Method 2: Using Python's Logging Module (Recommended for Production) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For more control over logging configuration, use Python's standard logging module: + +.. code:: python + + import logging + from binance.client import Client + + # Configure logging for binance module + logging.basicConfig( + level=logging.INFO, # Set root level + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' + ) + + # Enable debug logging for binance specifically + logging.getLogger('binance.base_client').setLevel(logging.DEBUG) + + # Create client (verbose parameter not needed) + client = Client(api_key, api_secret) + +This approach gives you fine-grained control and integrates with your application's existing logging infrastructure. + +What Gets Logged +^^^^^^^^^^^^^^^^ + +When verbose mode is enabled, you'll see detailed logs for each request including: + +- HTTP method and URL +- Request headers and body +- Response status code +- Response headers and body (truncated to 1000 characters) + +Example output: + +.. code-block:: text + + 2025-11-30 22:01:26,957 - binance.base_client - DEBUG - + Request: GET https://api.binance.com/api/v3/time + RequestHeaders: {'Accept': 'application/json', 'Content-Type': 'application/json'} + RequestBody: None + Response: 200 + ResponseHeaders: {'Content-Type': 'application/json;charset=UTF-8', ...} + ResponseBody: {"serverTime":1764536487218} + +**Note:** Verbose mode should typically be disabled in production environments to minimize overhead and log volume. Use the logging module approach for production with appropriate log levels. + +WebSocket Verbose Logging +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +WebSocket connections support verbose mode just like REST API calls. + +Method 1: Using the verbose Parameter (Recommended for Quick Debugging) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +.. code:: python + + import logging + from binance import AsyncClient, BinanceSocketManager + + # Configure logging to see output + logging.basicConfig(level=logging.DEBUG) + + async def main(): + client = await AsyncClient.create() + + # Enable verbose mode for WebSocket connections + bm = BinanceSocketManager(client, verbose=True) + + # WebSocket messages will be logged at DEBUG level + ts = bm.trade_socket('BTCUSDT') + async with ts as tscm: + msg = await tscm.recv() + print(msg) + + await client.close_connection() + +Method 2: Using Python's Logging Module (Recommended for Production) +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +.. code:: python + + import logging + from binance import AsyncClient, BinanceSocketManager + + # Configure logging + logging.basicConfig(level=logging.DEBUG) + + # Enable debug logging for all WebSocket connections + logging.getLogger('binance.ws').setLevel(logging.DEBUG) + + async def main(): + client = await AsyncClient.create() + bm = BinanceSocketManager(client) + + # WebSocket messages will be logged at DEBUG level + ts = bm.trade_socket('BTCUSDT') + async with ts as tscm: + msg = await tscm.recv() + print(msg) + + await client.close_connection() + +You can also enable logging for specific WebSocket components: + +.. code:: python + + # Log only WebSocket API messages + logging.getLogger('binance.ws.websocket_api').setLevel(logging.DEBUG) + + # Log reconnection events + logging.getLogger('binance.ws.reconnecting_websocket').setLevel(logging.DEBUG) + + # Log stream events + logging.getLogger('binance.ws.streams').setLevel(logging.DEBUG) + +WebSocket debug logs include: + +- Raw received messages +- Connection state changes +- Reconnection attempts +- Subscription events +- Error messages + +**Tip:** For comprehensive debugging, enable verbose mode for both REST API and WebSocket connections: + +.. code:: python + + import logging + from binance import AsyncClient, BinanceSocketManager + + logging.basicConfig(level=logging.DEBUG) + + # Enable verbose for both REST API and WebSocket + client = await AsyncClient.create(verbose=True) + bm = BinanceSocketManager(client, verbose=True) + +For Threaded WebSocket Manager: + +.. code:: python + + import logging + from binance.ws.threaded_stream import ThreadedApiManager + + logging.basicConfig(level=logging.DEBUG) + + # Enable verbose mode for threaded WebSocket manager + twm = ThreadedApiManager(api_key='your_key', api_secret='your_secret', verbose=True) + twm.start() + .. image:: https://analytics-pixel.appspot.com/UA-111417213-1/github/python-binance/docs/overview?pixel diff --git a/examples/verbose_example.py b/examples/verbose_example.py new file mode 100644 index 000000000..e07e3f594 --- /dev/null +++ b/examples/verbose_example.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +""" +Comprehensive verbose mode example for python-binance + +This example demonstrates verbose logging for: +- Synchronous Client (REST API) +- Async Client (REST API) +- WebSocket streams (BinanceSocketManager) +""" + +import asyncio +import logging +from binance import Client, AsyncClient, BinanceSocketManager + +# Configure logging to see verbose output +logging.basicConfig( + level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) + + +def sync_client_example(): + """Example 1: Synchronous Client with verbose mode""" + print("\n" + "=" * 80) + print("Example 1: Synchronous Client (verbose=True)") + print("=" * 80) + + client = Client(verbose=True) + + # Make API call - will show detailed HTTP logs + server_time = client.get_server_time() + print(f"Server time: {server_time['serverTime']}\n") + + +async def async_client_example(): + """Example 2: Async Client with verbose mode""" + print("\n" + "=" * 80) + print("Example 2: Async Client (verbose=True)") + print("=" * 80) + + client = await AsyncClient.create(verbose=True) + + # Make API call - will show detailed HTTP logs + ticker = await client.get_symbol_ticker(symbol="BTCUSDT") + print(f"BTC/USDT price: {ticker['price']}\n") + + await client.close_connection() + + +async def websocket_example(): + """Example 3: WebSocket with verbose mode""" + print("\n" + "=" * 80) + print("Example 3: WebSocket Streams (verbose=True)") + print("=" * 80) + + client = await AsyncClient.create() + + # Create socket manager with verbose mode + bm = BinanceSocketManager(client, verbose=True) + + # Start trade socket - will show detailed WebSocket logs + ts = bm.trade_socket("ETHUSDT") + + print("Receiving 3 trade messages...\n") + async with ts as tscm: + for i in range(3): + msg = await tscm.recv() + print(f"Trade {i + 1}: Price={msg['p']}, Qty={msg['q']}") + + await client.close_connection() + + +async def combined_example(): + """Example 4: Combined REST + WebSocket verbose mode""" + print("\n" + "=" * 80) + print("Example 4: Combined REST + WebSocket (both verbose=True)") + print("=" * 80) + + # Enable verbose for both REST and WebSocket + client = await AsyncClient.create(verbose=True) + bm = BinanceSocketManager(client, verbose=True) + + # REST API call + await client.get_server_time() + + # WebSocket stream + ts = bm.trade_socket("BNBUSDT") + async with ts as tscm: + msg = await tscm.recv() + print(f"BNB/USDT trade: {msg['p']}\n") + + await client.close_connection() + + +def main(): + """Run all examples""" + print("\n" + "=" * 80) + print("Python-Binance Verbose Mode Examples") + print("=" * 80) + print("\nThese examples show how to enable verbose logging for debugging:") + print("- REST API requests/responses (HTTP details)") + print("- WebSocket messages (connection & data)") + print("\nWatch the DEBUG logs above each example output.\n") + + # Run sync example + sync_client_example() + + # Run async examples + asyncio.run(async_client_example()) + asyncio.run(websocket_example()) + asyncio.run(combined_example()) + + print("\n" + "=" * 80) + print("All examples completed!") + print("=" * 80) + print("\nKey takeaways:") + print(" ✓ Use verbose=True for quick debugging") + print(" ✓ Works with Client, AsyncClient, and BinanceSocketManager") + print(" ✓ Shows full HTTP request/response details") + print(" ✓ Logs WebSocket messages as they arrive") + print(" ✓ Disable verbose mode in production (it's off by default)") + + +if __name__ == "__main__": + main() diff --git a/tests/test_threaded_stream.py b/tests/test_threaded_stream.py index 2d726934a..44a62a52c 100644 --- a/tests/test_threaded_stream.py +++ b/tests/test_threaded_stream.py @@ -26,6 +26,7 @@ async def __aiter__(self): async def __anext__(self): raise StopAsyncIteration + @pytest.mark.asyncio async def test_initialization(): """Test that manager initializes with correct parameters""" @@ -48,6 +49,7 @@ async def test_initialization(): "testnet": True, "session_params": {"trust_env": True}, "https_proxy": None, + "verbose": False, } @@ -63,6 +65,7 @@ async def test_start_and_stop_socket(manager): # Track number of recv calls recv_count = 0 + async def controlled_recv(): nonlocal recv_count recv_count += 1 diff --git a/tests/test_verbose_mode.py b/tests/test_verbose_mode.py new file mode 100644 index 000000000..b2689a5dd --- /dev/null +++ b/tests/test_verbose_mode.py @@ -0,0 +1,56 @@ +"""Tests for verbose mode functionality""" + +import pytest +import logging +from binance.client import Client +from binance.async_client import AsyncClient + + +def test_client_verbose_initialization(): + """Test that Client can be initialized with verbose mode""" + client = Client(verbose=True, ping=False) + assert client.verbose is True + assert client.logger is not None + assert client.logger.level == logging.DEBUG + + +def test_client_non_verbose_initialization(): + """Test that Client defaults to non-verbose mode""" + client = Client(verbose=False, ping=False) + assert client.verbose is False + assert client.logger is not None + # When verbose=False, we don't set the logger level (respects external config) + + +def test_client_default_verbose(): + """Test that Client defaults to verbose=False""" + client = Client(ping=False) + assert client.verbose is False + + +@pytest.mark.asyncio() +async def test_async_client_verbose_initialization(): + """Test that AsyncClient can be initialized with verbose mode""" + client = AsyncClient(verbose=True) + assert client.verbose is True + assert client.logger is not None + assert client.logger.level == logging.DEBUG + await client.close_connection() + + +@pytest.mark.asyncio() +async def test_async_client_non_verbose_initialization(): + """Test that AsyncClient defaults to non-verbose mode""" + client = AsyncClient(verbose=False) + assert client.verbose is False + assert client.logger is not None + # When verbose=False, we don't set the logger level (respects external config) + await client.close_connection() + + +@pytest.mark.asyncio() +async def test_async_client_default_verbose(): + """Test that AsyncClient defaults to verbose=False""" + client = AsyncClient() + assert client.verbose is False + await client.close_connection() diff --git a/tests/test_websocket_verbose.py b/tests/test_websocket_verbose.py new file mode 100644 index 000000000..1effa29c9 --- /dev/null +++ b/tests/test_websocket_verbose.py @@ -0,0 +1,117 @@ +"""Tests for WebSocket verbose logging""" + +import logging +import pytest + + +def test_websocket_logger_exists(): + """Test that WebSocket loggers can be configured""" + # Test main WebSocket logger + ws_logger = logging.getLogger("binance.ws") + assert ws_logger is not None + + # Test WebSocket API logger + ws_api_logger = logging.getLogger("binance.ws.websocket_api") + assert ws_api_logger is not None + + # Test reconnecting WebSocket logger + ws_reconnect_logger = logging.getLogger("binance.ws.reconnecting_websocket") + assert ws_reconnect_logger is not None + + # Test streams logger + ws_streams_logger = logging.getLogger("binance.ws.streams") + assert ws_streams_logger is not None + + +def test_websocket_logger_level_configuration(): + """Test that WebSocket logger levels can be set""" + ws_logger = logging.getLogger("binance.ws.test_config") + + # Set to DEBUG + ws_logger.setLevel(logging.DEBUG) + assert ws_logger.level == logging.DEBUG + + # Set to INFO + ws_logger.setLevel(logging.INFO) + assert ws_logger.level == logging.INFO + + # Set to WARNING + ws_logger.setLevel(logging.WARNING) + assert ws_logger.level == logging.WARNING + + +def test_combined_logging_configuration(): + """Test that both REST and WebSocket logging can be configured together""" + # Configure REST verbose logging + from binance.client import Client + + # This should work without errors + client = Client(verbose=True, ping=False) + assert client.verbose is True + assert client.logger is not None + + # Configure WebSocket logging + ws_logger = logging.getLogger("binance.ws") + ws_logger.setLevel(logging.DEBUG) + assert ws_logger.level == logging.DEBUG + + # Both should be independently configurable + assert client.logger.level == logging.DEBUG + assert ws_logger.level == logging.DEBUG + + +@pytest.mark.asyncio() +async def test_binance_socket_manager_verbose(): + """Test that BinanceSocketManager can be initialized with verbose mode""" + from binance import AsyncClient, BinanceSocketManager + + client = AsyncClient() + + # Test with verbose=True + bm_verbose = BinanceSocketManager(client, verbose=True) + assert bm_verbose.verbose is True + + # Test with verbose=False (default) + bm_quiet = BinanceSocketManager(client, verbose=False) + assert bm_quiet.verbose is False + + # Test default + bm_default = BinanceSocketManager(client) + assert bm_default.verbose is False + + await client.close_connection() + + +def test_threaded_websocket_manager_verbose(): + """Test that ThreadedApiManager can be initialized with verbose mode""" + from binance.ws.threaded_stream import ThreadedApiManager + + # Test with verbose=True + twm_verbose = ThreadedApiManager(verbose=True) + assert twm_verbose.verbose is True + + # Test with verbose=False (default) + twm_quiet = ThreadedApiManager(verbose=False) + assert twm_quiet.verbose is False + + # Test default + twm_default = ThreadedApiManager() + assert twm_default.verbose is False + + +def test_websocket_manager_sets_logging_level(): + """Test that verbose mode sets the logging level for WebSocket managers""" + from binance.ws.threaded_stream import ThreadedApiManager + + # Get initial logging level + ws_logger = logging.getLogger("binance.ws") + initial_level = ws_logger.level + + # Create manager with verbose=True + twm = ThreadedApiManager(verbose=True) + + # Check that logging level was set to DEBUG + assert ws_logger.level == logging.DEBUG + + # Restore initial level + ws_logger.setLevel(initial_level)