Skip to content

Commit ea05ed0

Browse files
TexasCodingclaude
andcommitted
fix: Remove stub methods causing authentication failure
- Removed stub _make_request() from AuthenticationMixin that was returning None - Removed stub _refresh_authentication() from HttpMixin - These stubs were overriding actual implementations from other mixins - Added proper TYPE_CHECKING imports and Protocol type hints instead - All methods now properly typed with ProjectXClientProtocol for self parameter - Authentication now works correctly with all examples passing The stub methods were added for type annotation purposes but were inadvertently overriding the real implementations due to Python's MRO (Method Resolution Order). Using TYPE_CHECKING with Protocol type hints is the correct approach for typing mixins that depend on methods from other mixins. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 98f55a6 commit ea05ed0

File tree

2 files changed

+17
-39
lines changed

2 files changed

+17
-39
lines changed

src/project_x_py/client/auth.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async def main():
5454
import base64
5555
import datetime
5656
from datetime import timedelta
57-
from typing import Any
57+
from typing import TYPE_CHECKING
5858

5959
import orjson
6060
import pytz
@@ -70,6 +70,9 @@ async def main():
7070
validate_response,
7171
)
7272

73+
if TYPE_CHECKING:
74+
from project_x_py.types import ProjectXClientProtocol
75+
7376
logger = ProjectXLogger.get_logger(__name__)
7477

7578

@@ -82,18 +85,6 @@ class AuthenticationMixin:
8285
account_name: str | None
8386
headers: dict[str, str]
8487

85-
async def _make_request(
86-
self,
87-
method: str,
88-
endpoint: str,
89-
data: dict[str, Any] | None = None,
90-
params: dict[str, Any] | None = None,
91-
headers: dict[str, str] | None = None,
92-
retry_count: int = 0,
93-
) -> Any:
94-
"""Provided by HttpMixin."""
95-
_ = (method, endpoint, data, params, headers, retry_count)
96-
9788
def __init__(self) -> None:
9889
"""Initialize authentication attributes."""
9990
super().__init__()
@@ -102,7 +93,7 @@ def __init__(self) -> None:
10293
self._authenticated = False
10394
self.account_info: Account | None = None
10495

105-
async def _refresh_authentication(self) -> None:
96+
async def _refresh_authentication(self: "ProjectXClientProtocol") -> None:
10697
"""
10798
Refresh authentication if token is expired or about to expire.
10899
@@ -118,7 +109,7 @@ async def _refresh_authentication(self) -> None:
118109
if self._should_refresh_token():
119110
await self.authenticate()
120111

121-
def _should_refresh_token(self) -> bool:
112+
def _should_refresh_token(self: "ProjectXClientProtocol") -> bool:
122113
"""
123114
Check if the authentication token should be refreshed.
124115
@@ -140,7 +131,7 @@ def _should_refresh_token(self) -> bool:
140131
return datetime.datetime.now(pytz.UTC) >= (self.token_expiry - buffer_time)
141132

142133
@handle_errors("authenticate")
143-
async def authenticate(self) -> None:
134+
async def authenticate(self: "ProjectXClientProtocol") -> None:
144135
"""
145136
Authenticate with ProjectX API and select account.
146137
@@ -179,7 +170,6 @@ async def authenticate(self) -> None:
179170
response = await self._make_request("POST", "/Auth/loginKey", data=auth_data)
180171

181172
if not response:
182-
logger.error(f"Empty response from auth endpoint")
183173
raise ProjectXAuthenticationError(ErrorMessages.AUTH_FAILED)
184174

185175
self.session_token = response["token"]
@@ -252,7 +242,7 @@ async def authenticate(self) -> None:
252242
},
253243
)
254244

255-
async def _ensure_authenticated(self) -> None:
245+
async def _ensure_authenticated(self: "ProjectXClientProtocol") -> None:
256246
"""
257247
Ensure client is authenticated before making API calls.
258248
@@ -277,7 +267,7 @@ async def _ensure_authenticated(self) -> None:
277267

278268
@handle_errors("list accounts")
279269
@validate_response(required_fields=["success", "accounts"])
280-
async def list_accounts(self) -> list[Account]:
270+
async def list_accounts(self: "ProjectXClientProtocol") -> list[Account]:
281271
"""
282272
List all accounts available to the authenticated user.
283273

src/project_x_py/client/http.py

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ async def main():
5252
"""
5353

5454
import time
55-
from typing import Any, TypeVar
55+
from typing import TYPE_CHECKING, Any, TypeVar
5656

5757
import httpx
5858

@@ -77,6 +77,9 @@ async def main():
7777
retry_on_network_error,
7878
)
7979

80+
if TYPE_CHECKING:
81+
from project_x_py.types import ProjectXClientProtocol
82+
8083
T = TypeVar("T")
8184

8285
logger = ProjectXLogger.get_logger(__name__)
@@ -94,16 +97,13 @@ class HttpMixin:
9497
cache_hit_count: int
9598
api_call_count: int
9699

97-
async def _refresh_authentication(self) -> None:
98-
"""Provided by AuthenticationMixin."""
99-
100100
def __init__(self) -> None:
101101
"""Initialize HTTP client attributes."""
102102
super().__init__()
103103
self._client: httpx.AsyncClient | None = None
104104
self.api_call_count = 0
105105

106-
async def _create_client(self) -> httpx.AsyncClient:
106+
async def _create_client(self: "ProjectXClientProtocol") -> httpx.AsyncClient:
107107
"""
108108
Create an optimized httpx async client with connection pooling and retries.
109109
@@ -147,7 +147,7 @@ async def _create_client(self) -> httpx.AsyncClient:
147147

148148
return client
149149

150-
async def _ensure_client(self) -> httpx.AsyncClient:
150+
async def _ensure_client(self: "ProjectXClientProtocol") -> httpx.AsyncClient:
151151
"""
152152
Ensure HTTP client is initialized and ready for API requests.
153153
@@ -169,7 +169,7 @@ async def _ensure_client(self) -> httpx.AsyncClient:
169169
@handle_rate_limit()
170170
@retry_on_network_error(max_attempts=3)
171171
async def _make_request(
172-
self,
172+
self: "ProjectXClientProtocol",
173173
method: str,
174174
endpoint: str,
175175
data: dict[str, Any] | None = None,
@@ -280,9 +280,6 @@ async def _make_request(
280280
retry_count=retry_count + 1,
281281
)
282282
return retry_result
283-
logger.error(
284-
f"Authentication failed for {endpoint}, status: {response.status_code}, response: {response.text[:200]}"
285-
)
286283
raise ProjectXAuthenticationError(ErrorMessages.AUTH_FAILED)
287284

288285
# Handle client errors
@@ -297,15 +294,6 @@ async def _make_request(
297294
except Exception:
298295
error_msg = response.text
299296

300-
# Log authentication endpoint errors for debugging
301-
if endpoint == "/Auth/loginKey":
302-
logger.error(
303-
f"Auth endpoint error - Status: {response.status_code}, Message: {error_msg}"
304-
)
305-
return (
306-
None # Return None for auth failures to match expected behavior
307-
)
308-
309297
if response.status_code == 404:
310298
raise ProjectXDataError(
311299
format_error_message(
@@ -330,7 +318,7 @@ async def _make_request(
330318

331319
@handle_errors("get health status")
332320
async def get_health_status(
333-
self,
321+
self: "ProjectXClientProtocol",
334322
) -> PerformanceStatsResponse:
335323
"""
336324
Get client statistics and performance metrics.

0 commit comments

Comments
 (0)