Phase 1: public market + universe lookups via ESI
Add a thin async ESI client (httpx, descriptive User-Agent, uniform errors, mockable transport) plus name<->id resolution. New read-only tools: - universe: resolve_names, get_item, get_system, get_station, get_region, get_route - market: list_hubs, get_market_price, get_market_orders, compare_hubs Trade-hub IDs (Jita/Amarr/Dodixie/Rens/Hek) are hardcoded constants. Market aggregation (best buy/sell, spread, order book) lives in pure helpers. 30 unit tests with mocked ESI; coverage 99%. SDE bulk-load deferred to a later phase. Closes #2 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
11 files changed
+839
-1
No files matched your search
@@ -0,0 +1,49 @@
|
||||
"""Shared test helpers: a mock ESI client backed by httpx.MockTransport."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from familiar import esi
|
||||
|
||||
Handler = Callable[[httpx.Request], httpx.Response]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_esi():
|
||||
"""Install a mock ESI client driven by a request handler.
|
||||
|
||||
Usage::
|
||||
|
||||
def test_x(mock_esi):
|
||||
def handler(request):
|
||||
return httpx.Response(200, json={...})
|
||||
mock_esi(handler)
|
||||
...
|
||||
|
||||
The shared client is reset after the test.
|
||||
"""
|
||||
|
||||
def _make(handler: Handler) -> esi.EsiClient:
|
||||
client = esi.EsiClient(transport=httpx.MockTransport(handler))
|
||||
esi.set_client(client)
|
||||
return client
|
||||
|
||||
yield _make
|
||||
esi.set_client(None)
|
||||
|
||||
|
||||
def route(request: httpx.Request, fixtures: dict[str, object]) -> httpx.Response:
|
||||
"""Match a request against ``{substring_in_path: json_body}`` and respond.
|
||||
|
||||
The special key ``"/universe/ids/"`` is matched for the name-resolution POST.
|
||||
A missing match returns 404 so tests fail loudly.
|
||||
"""
|
||||
path = request.url.path
|
||||
for needle, body in fixtures.items():
|
||||
if needle in path:
|
||||
return httpx.Response(200, json=body)
|
||||
return httpx.Response(404, json={"error": f"no fixture for {path}"})
|
||||
Reference in new issue
Block a user