-
Notifications
You must be signed in to change notification settings - Fork 340
Description
Bug Report: Timeout parameters are accepted but not used
Summary
The RESTClient constructor accepts connect_timeout and read_timeout parameters, creates a urllib3.Timeout object, but never passes it to the PoolManager or uses it in HTTP requests. This means requests can hang indefinitely.
Environment
- Package: massive==2.0.3
- Python: 3.13
- OS: macOS
Steps to Reproduce
from massive import RESTClient
# Create client with explicit timeouts
client = RESTClient(
api_key="your_api_key",
connect_timeout=5.0,
read_timeout=5.0
)
# Check if timeout is actually used
print("Timeout object:", client.timeout)
print("PoolManager kwargs:", client.client.connection_pool_kw)Expected Behavior
The timeout should be passed to either:
urllib3.PoolManager(timeout=...)at construction, orself.client.request(..., timeout=self.timeout)on each request
Actual Behavior
Timeout object: Timeout(connect=5.0, read=5.0, total=None)
PoolManager kwargs: {'ca_certs': '...', 'cert_reqs': 'CERT_REQUIRED', 'retries': Retry(...)}
The timeout object is created but never used. The connection_pool_kw does not contain a timeout, and the _get method in base.py does not pass timeout to requests.
Root Cause
In massive/rest/base.py:
# Line 81: Timeout is created
self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout)
# Line 73-79: PoolManager is created WITHOUT timeout
self.client = urllib3.PoolManager(
num_pools=num_pools,
headers=self.headers,
ca_certs=certifi.where(),
cert_reqs="CERT_REQUIRED",
retries=retry_strategy,
# timeout=self.timeout ← MISSING
)
# Line 119-124: Request is made WITHOUT timeout
resp = self.client.request(
"GET",
self.BASE + path,
fields=params,
headers=headers,
# timeout=self.timeout ← MISSING
)Suggested Fix
Either pass timeout to PoolManager (applies to all requests):
self.client = urllib3.PoolManager(
num_pools=num_pools,
headers=self.headers,
ca_certs=certifi.where(),
cert_reqs="CERT_REQUIRED",
retries=retry_strategy,
timeout=self.timeout, # Add this
)Or pass timeout on each request (more flexible):
resp = self.client.request(
"GET",
self.BASE + path,
fields=params,
headers=headers,
timeout=self.timeout, # Add this
)Impact
Without a working timeout, any network issue (slow server, DNS hang, etc.) can cause the SDK to hang indefinitely, blocking the calling thread.
Workaround
For async code, wrap SDK calls with asyncio.timeout():
import asyncio
async def get_data_with_timeout():
async with asyncio.timeout(15):
return await asyncio.to_thread(client.get_snapshot_ticker, ...)