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,56 @@
|
||||
"""ESI client: error handling, empty bodies, datasource param."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from familiar import esi
|
||||
|
||||
|
||||
def test_get_raises_esi_error_on_http_error(mock_esi):
|
||||
mock_esi(lambda req: httpx.Response(404, json={"error": "not found"}))
|
||||
with pytest.raises(esi.EsiError) as exc:
|
||||
asyncio.run(esi.client().get("/universe/types/999999/"))
|
||||
assert exc.value.status == 404
|
||||
assert "404" in str(exc.value)
|
||||
|
||||
|
||||
def test_get_raises_on_network_error(mock_esi):
|
||||
def boom(req):
|
||||
raise httpx.ConnectError("boom")
|
||||
|
||||
mock_esi(boom)
|
||||
with pytest.raises(esi.EsiError):
|
||||
asyncio.run(esi.client().get("/anything/"))
|
||||
|
||||
|
||||
def test_empty_body_returns_none(mock_esi):
|
||||
mock_esi(lambda req: httpx.Response(200, content=b""))
|
||||
assert asyncio.run(esi.client().get("/x/")) is None
|
||||
|
||||
|
||||
def test_datasource_param_is_attached(mock_esi):
|
||||
seen = {}
|
||||
|
||||
def handler(req):
|
||||
seen["datasource"] = req.url.params.get("datasource")
|
||||
return httpx.Response(200, json={"ok": True})
|
||||
|
||||
mock_esi(handler)
|
||||
asyncio.run(esi.client().get("/x/"))
|
||||
assert seen["datasource"] == "tranquility"
|
||||
|
||||
|
||||
def test_error_detail_falls_back_to_text(mock_esi):
|
||||
mock_esi(lambda req: httpx.Response(500, content=b"upstream exploded"))
|
||||
with pytest.raises(esi.EsiError) as exc:
|
||||
asyncio.run(esi.client().get("/x/"))
|
||||
assert "upstream exploded" in str(exc.value)
|
||||
|
||||
|
||||
def test_default_client_is_singleton():
|
||||
esi.set_client(None)
|
||||
first = esi.client()
|
||||
assert esi.client() is first
|
||||
esi.set_client(None)
|
||||
Reference in new issue
Block a user