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>
38 lines
1.1 KiB
Python
38 lines
1.1 KiB
Python
"""Name <-> id resolution."""
|
|
|
|
import asyncio
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from familiar import lookup
|
|
|
|
|
|
def test_resolve_id_passes_through_numeric():
|
|
assert asyncio.run(lookup.resolve_id(34)) == 34
|
|
assert asyncio.run(lookup.resolve_id("34")) == 34
|
|
|
|
|
|
def test_resolve_name_picks_requested_category(mock_esi):
|
|
body = {
|
|
"inventory_types": [{"id": 34, "name": "Tritanium"}],
|
|
"systems": [{"id": 30000142, "name": "Jita"}],
|
|
}
|
|
mock_esi(lambda req: httpx.Response(200, json=body))
|
|
assert asyncio.run(lookup.resolve_name("Tritanium", "inventory_types")) == (
|
|
34,
|
|
"inventory_types",
|
|
)
|
|
|
|
|
|
def test_resolve_id_resolves_name(mock_esi):
|
|
body = {"inventory_types": [{"id": 34, "name": "Tritanium"}]}
|
|
mock_esi(lambda req: httpx.Response(200, json=body))
|
|
assert asyncio.run(lookup.resolve_id("Tritanium", "inventory_types")) == 34
|
|
|
|
|
|
def test_resolve_name_raises_when_absent(mock_esi):
|
|
mock_esi(lambda req: httpx.Response(200, json={}))
|
|
with pytest.raises(LookupError):
|
|
asyncio.run(lookup.resolve_name("Nope", "inventory_types"))
|