From 232680a760ac7566cdaab6e8171d2bc151e8f969 Mon Sep 17 00:00:00 2001 From: Patrick Selamy Date: Mon, 9 Mar 2026 22:03:10 -0400 Subject: [PATCH] chore: smoke test fixes and code quality improvements (#88) * fix: replace deprecated datetime.utcnow() and websockets.legacy APIs - Replace datetime.utcnow() with datetime.now(UTC) in Orderbook model - Use websockets.asyncio.client.connect instead of legacy websockets.connect - Import ConnectionClosed from websockets.exceptions directly - Update test mocks to patch the new import paths Co-Authored-By: Claude Opus 4.6 * fix: resolve ruff lint errors in alembic migration - Replace typing.Union with X | Y syntax (UP007) - Import Sequence from collections.abc instead of typing (UP035) Co-Authored-By: Claude Opus 4.6 * fix: remove deprecated version key from docker-compose.yml The top-level 'version' key is obsolete in modern Docker Compose and produces a warning. Co-Authored-By: Claude Opus 4.6 * docs: fix README to match actual project structure and tooling - Replace pip commands with uv equivalents - Fix run command from 'python -m src.main' to 'python -m polymarket_insider_tracker' - Update project structure tree to reflect actual src/polymarket_insider_tracker/ layout Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- README.md | 42 ++++++++----------- .../versions/20260104_0000_initial_schema.py | 8 ++-- docker-compose.yml | 2 - .../ingestor/models.py | 2 +- .../ingestor/websocket.py | 9 ++-- tests/ingestor/test_websocket.py | 10 ++++- 6 files changed, 35 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 40904f6..78bed6d 100644 --- a/README.md +++ b/README.md @@ -126,13 +126,13 @@ docker compose up -d docker compose ps # Install Python dependencies -pip install -e . +uv sync --all-extras # Run database migrations -alembic upgrade head +uv run alembic upgrade head # Run the tracker -python -m src.main +uv run python -m polymarket_insider_tracker ``` ### Docker Services @@ -188,24 +188,16 @@ LIQUIDITY_IMPACT_THRESHOLD=0.02 ``` polymarket-insider-tracker/ ├── src/ -│ ├── ingestor/ # Real-time market data ingestion -│ │ ├── clob_client.py # Polymarket CLOB API wrapper -│ │ └── websocket.py # WebSocket event handler -│ ├── profiler/ # Wallet analysis -│ │ ├── analyzer.py # Core wallet profiling logic -│ │ ├── chain.py # Polygon blockchain client -│ │ └── funding.py # Funding chain tracer -│ ├── detector/ # Anomaly detection engines -│ │ ├── fresh_wallet.py -│ │ ├── size_anomaly.py -│ │ ├── sniper.py # DBSCAN clustering -│ │ └── scorer.py # Composite risk scoring -│ ├── alerter/ # Notification dispatch -│ │ ├── formatter.py # Alert message formatting -│ │ └── dispatcher.py # Multi-channel delivery -│ └── storage/ # Persistence layer -│ ├── models.py # SQLAlchemy models -│ └── repos.py # Repository pattern +│ └── polymarket_insider_tracker/ +│ ├── __main__.py # CLI entry point +│ ├── pipeline.py # Core detection pipeline +│ ├── ingestor/ # Real-time market data ingestion +│ │ ├── clob_client.py # Polymarket CLOB API wrapper +│ │ └── websocket.py # WebSocket event handler +│ ├── profiler/ # Wallet analysis +│ ├── detector/ # Anomaly detection engines +│ ├── alerter/ # Notification dispatch +│ └── storage/ # Persistence layer ├── tests/ # Test suite ├── scripts/ │ └── backtest.py # Historical analysis @@ -289,16 +281,16 @@ Contributions are welcome! Please read our Contributing Guide before submitting ```bash # Install dev dependencies -pip install -e ".[dev]" +uv sync --all-extras # Run tests -pytest +uv run pytest # Run linting -ruff check src/ +uv run ruff check src/ # Run type checking -mypy src/ +uv run mypy src/ ``` --- diff --git a/alembic/versions/20260104_0000_initial_schema.py b/alembic/versions/20260104_0000_initial_schema.py index 9ab69b6..902fd87 100644 --- a/alembic/versions/20260104_0000_initial_schema.py +++ b/alembic/versions/20260104_0000_initial_schema.py @@ -5,16 +5,16 @@ Revises: Create Date: 2026-01-04 00:00:00.000000+00:00 """ -from typing import Sequence, Union +from collections.abc import Sequence import sqlalchemy as sa from alembic import op # revision identifiers, used by Alembic. revision: str = "001_initial" -down_revision: Union[str, None] = None -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None +down_revision: str | None = None +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None def upgrade() -> None: diff --git a/docker-compose.yml b/docker-compose.yml index cb0f962..6d353b8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.8" - services: postgres: image: postgres:15 diff --git a/src/polymarket_insider_tracker/ingestor/models.py b/src/polymarket_insider_tracker/ingestor/models.py index ac7b29e..618ccba 100644 --- a/src/polymarket_insider_tracker/ingestor/models.py +++ b/src/polymarket_insider_tracker/ingestor/models.py @@ -86,7 +86,7 @@ class Orderbook: bids: tuple[OrderbookLevel, ...] asks: tuple[OrderbookLevel, ...] tick_size: Decimal - timestamp: datetime = field(default_factory=datetime.utcnow) + timestamp: datetime = field(default_factory=lambda: datetime.now(UTC)) @classmethod def from_clob_orderbook(cls, orderbook: Any) -> "Orderbook": diff --git a/src/polymarket_insider_tracker/ingestor/websocket.py b/src/polymarket_insider_tracker/ingestor/websocket.py index b481f8d..133e915 100644 --- a/src/polymarket_insider_tracker/ingestor/websocket.py +++ b/src/polymarket_insider_tracker/ingestor/websocket.py @@ -9,8 +9,9 @@ from dataclasses import dataclass from enum import Enum from typing import Any -import websockets from websockets.asyncio.client import ClientConnection +from websockets.asyncio.client import connect as ws_connect +from websockets.exceptions import ConnectionClosed from polymarket_insider_tracker.ingestor.models import TradeEvent @@ -156,7 +157,7 @@ class TradeStreamHandler: await self._set_state(ConnectionState.CONNECTING) try: - ws = await websockets.connect( + ws = await ws_connect( self._host, ping_interval=self._ping_interval, ping_timeout=self._ping_interval * 2, @@ -227,7 +228,7 @@ class TradeStreamHandler: else: logger.debug("Received binary message (%d bytes)", len(message)) - except websockets.ConnectionClosed as e: + except ConnectionClosed as e: logger.warning("Connection closed: %s", e) raise except Exception as e: @@ -284,7 +285,7 @@ class TradeStreamHandler: while self._running: try: await self._listen(self._ws) - except (websockets.ConnectionClosed, Exception) as e: + except (ConnectionClosed, Exception) as e: if not self._running: break diff --git a/tests/ingestor/test_websocket.py b/tests/ingestor/test_websocket.py index bb51804..37c671a 100644 --- a/tests/ingestor/test_websocket.py +++ b/tests/ingestor/test_websocket.py @@ -231,7 +231,10 @@ class TestTradeStreamHandler: mock_ws = AsyncMock() mock_ws.send = AsyncMock() - with patch("websockets.connect", AsyncMock(return_value=mock_ws)): + with patch( + "polymarket_insider_tracker.ingestor.websocket.ws_connect", + AsyncMock(return_value=mock_ws), + ): ws = await handler._connect() assert ws is mock_ws @@ -333,7 +336,10 @@ class TestTradeStreamHandlerIntegration: mock_ws = MockWebSocket(handler, trade_message) - with patch("websockets.connect", AsyncMock(return_value=mock_ws)): + with patch( + "polymarket_insider_tracker.ingestor.websocket.ws_connect", + AsyncMock(return_value=mock_ws), + ): # Run with timeout to prevent hanging try: await asyncio.wait_for(handler.start(), timeout=1.0)