python-eveonline 0.1.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/PKG-INFO +1 -1
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/pyproject.toml +1 -1
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/eveonline/__init__.py +1 -1
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/eveonline/client.py +121 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/eveonline/const.py +8 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/eveonline/models.py +59 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/PKG-INFO +1 -1
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/tests/test_client_authenticated.py +273 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/LICENSE +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/README.md +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/setup.cfg +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/eveonline/auth.py +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/eveonline/exceptions.py +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/eveonline/py.typed +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/SOURCES.txt +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/dependency_links.txt +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/requires.txt +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/top_level.txt +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/tests/test_auth.py +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/tests/test_client_public.py +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/tests/test_const.py +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/tests/test_exceptions.py +0 -0
- {python_eveonline-0.1.0 → python_eveonline-0.2.1}/tests/test_models.py +0 -0
|
@@ -22,7 +22,12 @@ from .models import (
|
|
|
22
22
|
CharacterPortrait,
|
|
23
23
|
CharacterPublicInfo,
|
|
24
24
|
CharacterShip,
|
|
25
|
+
CharacterSkillsSummary,
|
|
25
26
|
CorporationPublicInfo,
|
|
27
|
+
IndustryJob,
|
|
28
|
+
JumpFatigue,
|
|
29
|
+
MailLabelsSummary,
|
|
30
|
+
MarketOrder,
|
|
26
31
|
ServerStatus,
|
|
27
32
|
SkillQueueEntry,
|
|
28
33
|
UniverseName,
|
|
@@ -362,3 +367,119 @@ class EveOnlineClient:
|
|
|
362
367
|
)
|
|
363
368
|
for entry in data
|
|
364
369
|
]
|
|
370
|
+
|
|
371
|
+
async def async_get_skills(self, character_id: int) -> CharacterSkillsSummary:
|
|
372
|
+
"""Get a character's total and unallocated skill points.
|
|
373
|
+
|
|
374
|
+
Requires scope: ``esi-skills.read_skills.v1``
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
character_id: The Eve Online character ID.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
CharacterSkillsSummary with total SP and unallocated SP.
|
|
381
|
+
"""
|
|
382
|
+
data = await self._request("GET", f"characters/{character_id}/skills/", authenticated=True)
|
|
383
|
+
return CharacterSkillsSummary(
|
|
384
|
+
total_sp=data["total_sp"],
|
|
385
|
+
unallocated_sp=data.get("unallocated_sp", 0),
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
async def async_get_mail_labels(self, character_id: int) -> MailLabelsSummary:
|
|
389
|
+
"""Get a character's mail labels with unread counts.
|
|
390
|
+
|
|
391
|
+
Requires scope: ``esi-mail.read_mail.v1``
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
character_id: The Eve Online character ID.
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
MailLabelsSummary with total unread count.
|
|
398
|
+
"""
|
|
399
|
+
data = await self._request("GET", f"characters/{character_id}/mail/labels/", authenticated=True)
|
|
400
|
+
return MailLabelsSummary(
|
|
401
|
+
total_unread_count=data.get("total_unread_count", 0),
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
async def async_get_industry_jobs(self, character_id: int, *, include_completed: bool = False) -> list[IndustryJob]:
|
|
405
|
+
"""Get a character's industry jobs.
|
|
406
|
+
|
|
407
|
+
Requires scope: ``esi-industry.read_character_jobs.v1``
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
character_id: The Eve Online character ID.
|
|
411
|
+
include_completed: Whether to include completed jobs.
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
List of IndustryJob entries.
|
|
415
|
+
"""
|
|
416
|
+
params: dict[str, str] = {}
|
|
417
|
+
if include_completed:
|
|
418
|
+
params["include_completed"] = "true"
|
|
419
|
+
data = await self._request(
|
|
420
|
+
"GET", f"characters/{character_id}/industry/jobs/", authenticated=True, params=params
|
|
421
|
+
)
|
|
422
|
+
return [
|
|
423
|
+
IndustryJob(
|
|
424
|
+
job_id=entry["job_id"],
|
|
425
|
+
activity_id=entry["activity_id"],
|
|
426
|
+
status=entry["status"],
|
|
427
|
+
start_date=datetime.fromisoformat(entry["start_date"].replace("Z", "+00:00")),
|
|
428
|
+
end_date=datetime.fromisoformat(entry["end_date"].replace("Z", "+00:00")),
|
|
429
|
+
blueprint_type_id=entry["blueprint_type_id"],
|
|
430
|
+
output_location_id=entry["output_location_id"],
|
|
431
|
+
runs=entry["runs"],
|
|
432
|
+
product_type_id=entry.get("product_type_id"),
|
|
433
|
+
facility_id=entry.get("facility_id"),
|
|
434
|
+
cost=entry.get("cost"),
|
|
435
|
+
)
|
|
436
|
+
for entry in data
|
|
437
|
+
]
|
|
438
|
+
|
|
439
|
+
async def async_get_market_orders(self, character_id: int) -> list[MarketOrder]:
|
|
440
|
+
"""Get a character's open market orders.
|
|
441
|
+
|
|
442
|
+
Requires scope: ``esi-markets.read_character_orders.v1``
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
character_id: The Eve Online character ID.
|
|
446
|
+
|
|
447
|
+
Returns:
|
|
448
|
+
List of MarketOrder entries.
|
|
449
|
+
"""
|
|
450
|
+
data = await self._request("GET", f"characters/{character_id}/orders/", authenticated=True)
|
|
451
|
+
return [
|
|
452
|
+
MarketOrder(
|
|
453
|
+
order_id=entry["order_id"],
|
|
454
|
+
type_id=entry["type_id"],
|
|
455
|
+
is_buy_order=entry.get("is_buy_order", False),
|
|
456
|
+
price=entry["price"],
|
|
457
|
+
volume_remain=entry["volume_remain"],
|
|
458
|
+
volume_total=entry["volume_total"],
|
|
459
|
+
location_id=entry["location_id"],
|
|
460
|
+
region_id=entry["region_id"],
|
|
461
|
+
issued=datetime.fromisoformat(entry["issued"].replace("Z", "+00:00")),
|
|
462
|
+
duration=entry["duration"],
|
|
463
|
+
range=entry["range"],
|
|
464
|
+
min_volume=entry.get("min_volume"),
|
|
465
|
+
)
|
|
466
|
+
for entry in data
|
|
467
|
+
]
|
|
468
|
+
|
|
469
|
+
async def async_get_jump_fatigue(self, character_id: int) -> JumpFatigue:
|
|
470
|
+
"""Get a character's jump fatigue information.
|
|
471
|
+
|
|
472
|
+
Requires scope: ``esi-characters.read_fatigue.v1``
|
|
473
|
+
|
|
474
|
+
Args:
|
|
475
|
+
character_id: The Eve Online character ID.
|
|
476
|
+
|
|
477
|
+
Returns:
|
|
478
|
+
JumpFatigue with expiry date and last jump info.
|
|
479
|
+
"""
|
|
480
|
+
data = await self._request("GET", f"characters/{character_id}/fatigue/", authenticated=True)
|
|
481
|
+
return JumpFatigue(
|
|
482
|
+
jump_fatigue_expire_date=self._parse_datetime(data.get("jump_fatigue_expire_date")),
|
|
483
|
+
last_jump_date=self._parse_datetime(data.get("last_jump_date")),
|
|
484
|
+
last_update_date=self._parse_datetime(data.get("last_update_date")),
|
|
485
|
+
)
|
|
@@ -22,6 +22,10 @@ SCOPE_READ_KILLMAILS: Final = "esi-killmails.read_killmails.v1"
|
|
|
22
22
|
SCOPE_READ_CLONES: Final = "esi-clones.read_clones.v1"
|
|
23
23
|
SCOPE_READ_IMPLANTS: Final = "esi-clones.read_implants.v1"
|
|
24
24
|
SCOPE_READ_NOTIFICATIONS: Final = "esi-characters.read_notifications.v1"
|
|
25
|
+
SCOPE_READ_FATIGUE: Final = "esi-characters.read_fatigue.v1"
|
|
26
|
+
SCOPE_READ_MAIL: Final = "esi-mail.read_mail.v1"
|
|
27
|
+
SCOPE_READ_INDUSTRY_JOBS: Final = "esi-industry.read_character_jobs.v1"
|
|
28
|
+
SCOPE_READ_MARKET_ORDERS: Final = "esi-markets.read_character_orders.v1"
|
|
25
29
|
|
|
26
30
|
# Default scopes for a typical Home Assistant integration
|
|
27
31
|
DEFAULT_SCOPES: Final = [
|
|
@@ -31,4 +35,8 @@ DEFAULT_SCOPES: Final = [
|
|
|
31
35
|
SCOPE_READ_WALLET,
|
|
32
36
|
SCOPE_READ_SKILLS,
|
|
33
37
|
SCOPE_READ_SKILLQUEUE,
|
|
38
|
+
SCOPE_READ_FATIGUE,
|
|
39
|
+
SCOPE_READ_MAIL,
|
|
40
|
+
SCOPE_READ_INDUSTRY_JOBS,
|
|
41
|
+
SCOPE_READ_MARKET_ORDERS,
|
|
34
42
|
]
|
|
@@ -117,3 +117,62 @@ class UniverseName:
|
|
|
117
117
|
id: int
|
|
118
118
|
name: str
|
|
119
119
|
category: str
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass(frozen=True)
|
|
123
|
+
class CharacterSkillsSummary:
|
|
124
|
+
"""Character skills summary (requires auth)."""
|
|
125
|
+
|
|
126
|
+
total_sp: int
|
|
127
|
+
unallocated_sp: int
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass(frozen=True)
|
|
131
|
+
class MailLabelsSummary:
|
|
132
|
+
"""Mail labels with unread count (requires auth)."""
|
|
133
|
+
|
|
134
|
+
total_unread_count: int
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass(frozen=True)
|
|
138
|
+
class IndustryJob:
|
|
139
|
+
"""An active industry job (requires auth)."""
|
|
140
|
+
|
|
141
|
+
job_id: int
|
|
142
|
+
activity_id: int
|
|
143
|
+
status: str
|
|
144
|
+
start_date: datetime
|
|
145
|
+
end_date: datetime
|
|
146
|
+
blueprint_type_id: int
|
|
147
|
+
output_location_id: int
|
|
148
|
+
runs: int
|
|
149
|
+
product_type_id: int | None = None
|
|
150
|
+
facility_id: int | None = None
|
|
151
|
+
cost: float | None = None
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@dataclass(frozen=True)
|
|
155
|
+
class MarketOrder:
|
|
156
|
+
"""A character's market order (requires auth)."""
|
|
157
|
+
|
|
158
|
+
order_id: int
|
|
159
|
+
type_id: int
|
|
160
|
+
is_buy_order: bool
|
|
161
|
+
price: float
|
|
162
|
+
volume_remain: int
|
|
163
|
+
volume_total: int
|
|
164
|
+
location_id: int
|
|
165
|
+
region_id: int
|
|
166
|
+
issued: datetime
|
|
167
|
+
duration: int
|
|
168
|
+
range: str
|
|
169
|
+
min_volume: int | None = None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass(frozen=True)
|
|
173
|
+
class JumpFatigue:
|
|
174
|
+
"""Character jump fatigue information (requires auth)."""
|
|
175
|
+
|
|
176
|
+
jump_fatigue_expire_date: datetime | None = None
|
|
177
|
+
last_jump_date: datetime | None = None
|
|
178
|
+
last_update_date: datetime | None = None
|
|
@@ -15,6 +15,11 @@ from eveonline.models import (
|
|
|
15
15
|
CharacterLocation,
|
|
16
16
|
CharacterOnlineStatus,
|
|
17
17
|
CharacterShip,
|
|
18
|
+
CharacterSkillsSummary,
|
|
19
|
+
IndustryJob,
|
|
20
|
+
JumpFatigue,
|
|
21
|
+
MailLabelsSummary,
|
|
22
|
+
MarketOrder,
|
|
18
23
|
SkillQueueEntry,
|
|
19
24
|
WalletBalance,
|
|
20
25
|
)
|
|
@@ -70,6 +75,46 @@ class TestAuthRequired:
|
|
|
70
75
|
with pytest.raises(EveOnlineAuthenticationError):
|
|
71
76
|
await client.async_get_skill_queue(CHARACTER_ID)
|
|
72
77
|
|
|
78
|
+
@pytest.mark.asyncio
|
|
79
|
+
async def test_skills_without_auth_raises(self):
|
|
80
|
+
"""Calling skills endpoint without auth raises error."""
|
|
81
|
+
async with aiohttp.ClientSession() as session:
|
|
82
|
+
client = EveOnlineClient(session=session)
|
|
83
|
+
with pytest.raises(EveOnlineAuthenticationError):
|
|
84
|
+
await client.async_get_skills(CHARACTER_ID)
|
|
85
|
+
|
|
86
|
+
@pytest.mark.asyncio
|
|
87
|
+
async def test_mail_labels_without_auth_raises(self):
|
|
88
|
+
"""Calling mail labels endpoint without auth raises error."""
|
|
89
|
+
async with aiohttp.ClientSession() as session:
|
|
90
|
+
client = EveOnlineClient(session=session)
|
|
91
|
+
with pytest.raises(EveOnlineAuthenticationError):
|
|
92
|
+
await client.async_get_mail_labels(CHARACTER_ID)
|
|
93
|
+
|
|
94
|
+
@pytest.mark.asyncio
|
|
95
|
+
async def test_industry_jobs_without_auth_raises(self):
|
|
96
|
+
"""Calling industry jobs endpoint without auth raises error."""
|
|
97
|
+
async with aiohttp.ClientSession() as session:
|
|
98
|
+
client = EveOnlineClient(session=session)
|
|
99
|
+
with pytest.raises(EveOnlineAuthenticationError):
|
|
100
|
+
await client.async_get_industry_jobs(CHARACTER_ID)
|
|
101
|
+
|
|
102
|
+
@pytest.mark.asyncio
|
|
103
|
+
async def test_market_orders_without_auth_raises(self):
|
|
104
|
+
"""Calling market orders endpoint without auth raises error."""
|
|
105
|
+
async with aiohttp.ClientSession() as session:
|
|
106
|
+
client = EveOnlineClient(session=session)
|
|
107
|
+
with pytest.raises(EveOnlineAuthenticationError):
|
|
108
|
+
await client.async_get_market_orders(CHARACTER_ID)
|
|
109
|
+
|
|
110
|
+
@pytest.mark.asyncio
|
|
111
|
+
async def test_jump_fatigue_without_auth_raises(self):
|
|
112
|
+
"""Calling jump fatigue endpoint without auth raises error."""
|
|
113
|
+
async with aiohttp.ClientSession() as session:
|
|
114
|
+
client = EveOnlineClient(session=session)
|
|
115
|
+
with pytest.raises(EveOnlineAuthenticationError):
|
|
116
|
+
await client.async_get_jump_fatigue(CHARACTER_ID)
|
|
117
|
+
|
|
73
118
|
|
|
74
119
|
class TestCharacterOnline:
|
|
75
120
|
"""Test GET /characters/{character_id}/online/ endpoint."""
|
|
@@ -334,3 +379,231 @@ class TestSkillQueue:
|
|
|
334
379
|
assert queue[0].start_date is None
|
|
335
380
|
assert queue[0].finish_date is None
|
|
336
381
|
assert queue[0].training_start_sp is None
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class TestSkills:
|
|
385
|
+
"""Test GET /characters/{character_id}/skills/ endpoint."""
|
|
386
|
+
|
|
387
|
+
@pytest.mark.asyncio
|
|
388
|
+
async def test_get_skills_success(self, character_skills_data):
|
|
389
|
+
"""Successful skills summary fetch."""
|
|
390
|
+
with aioresponses() as mocked:
|
|
391
|
+
mocked.get(
|
|
392
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/skills/?datasource=tranquility",
|
|
393
|
+
payload=character_skills_data,
|
|
394
|
+
)
|
|
395
|
+
async with aiohttp.ClientSession() as session:
|
|
396
|
+
auth = MockAuth(session)
|
|
397
|
+
client = EveOnlineClient(auth=auth)
|
|
398
|
+
skills = await client.async_get_skills(CHARACTER_ID)
|
|
399
|
+
|
|
400
|
+
assert isinstance(skills, CharacterSkillsSummary)
|
|
401
|
+
assert skills.total_sp == 48500000
|
|
402
|
+
assert skills.unallocated_sp == 150000
|
|
403
|
+
|
|
404
|
+
@pytest.mark.asyncio
|
|
405
|
+
async def test_get_skills_no_unallocated(self):
|
|
406
|
+
"""Skills when unallocated_sp is missing defaults to 0."""
|
|
407
|
+
data = {"total_sp": 10000000, "skills": []}
|
|
408
|
+
with aioresponses() as mocked:
|
|
409
|
+
mocked.get(
|
|
410
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/skills/?datasource=tranquility",
|
|
411
|
+
payload=data,
|
|
412
|
+
)
|
|
413
|
+
async with aiohttp.ClientSession() as session:
|
|
414
|
+
auth = MockAuth(session)
|
|
415
|
+
client = EveOnlineClient(auth=auth)
|
|
416
|
+
skills = await client.async_get_skills(CHARACTER_ID)
|
|
417
|
+
|
|
418
|
+
assert skills.total_sp == 10000000
|
|
419
|
+
assert skills.unallocated_sp == 0
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class TestMailLabels:
|
|
423
|
+
"""Test GET /characters/{character_id}/mail/labels/ endpoint."""
|
|
424
|
+
|
|
425
|
+
@pytest.mark.asyncio
|
|
426
|
+
async def test_get_mail_labels_success(self, mail_labels_data):
|
|
427
|
+
"""Successful mail labels fetch."""
|
|
428
|
+
with aioresponses() as mocked:
|
|
429
|
+
mocked.get(
|
|
430
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/mail/labels/?datasource=tranquility",
|
|
431
|
+
payload=mail_labels_data,
|
|
432
|
+
)
|
|
433
|
+
async with aiohttp.ClientSession() as session:
|
|
434
|
+
auth = MockAuth(session)
|
|
435
|
+
client = EveOnlineClient(auth=auth)
|
|
436
|
+
labels = await client.async_get_mail_labels(CHARACTER_ID)
|
|
437
|
+
|
|
438
|
+
assert isinstance(labels, MailLabelsSummary)
|
|
439
|
+
assert labels.total_unread_count == 7
|
|
440
|
+
|
|
441
|
+
@pytest.mark.asyncio
|
|
442
|
+
async def test_get_mail_labels_no_unread(self):
|
|
443
|
+
"""Mail labels when no unread mail."""
|
|
444
|
+
data = {"total_unread_count": 0, "labels": []}
|
|
445
|
+
with aioresponses() as mocked:
|
|
446
|
+
mocked.get(
|
|
447
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/mail/labels/?datasource=tranquility",
|
|
448
|
+
payload=data,
|
|
449
|
+
)
|
|
450
|
+
async with aiohttp.ClientSession() as session:
|
|
451
|
+
auth = MockAuth(session)
|
|
452
|
+
client = EveOnlineClient(auth=auth)
|
|
453
|
+
labels = await client.async_get_mail_labels(CHARACTER_ID)
|
|
454
|
+
|
|
455
|
+
assert labels.total_unread_count == 0
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
class TestIndustryJobs:
|
|
459
|
+
"""Test GET /characters/{character_id}/industry/jobs/ endpoint."""
|
|
460
|
+
|
|
461
|
+
@pytest.mark.asyncio
|
|
462
|
+
async def test_get_industry_jobs_success(self, industry_jobs_data):
|
|
463
|
+
"""Successful industry jobs fetch."""
|
|
464
|
+
with aioresponses() as mocked:
|
|
465
|
+
mocked.get(
|
|
466
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/industry/jobs/?datasource=tranquility",
|
|
467
|
+
payload=industry_jobs_data,
|
|
468
|
+
)
|
|
469
|
+
async with aiohttp.ClientSession() as session:
|
|
470
|
+
auth = MockAuth(session)
|
|
471
|
+
client = EveOnlineClient(auth=auth)
|
|
472
|
+
jobs = await client.async_get_industry_jobs(CHARACTER_ID)
|
|
473
|
+
|
|
474
|
+
assert len(jobs) == 2
|
|
475
|
+
assert all(isinstance(j, IndustryJob) for j in jobs)
|
|
476
|
+
|
|
477
|
+
first = jobs[0]
|
|
478
|
+
assert first.job_id == 12345
|
|
479
|
+
assert first.activity_id == 1
|
|
480
|
+
assert first.status == "active"
|
|
481
|
+
assert first.blueprint_type_id == 1137
|
|
482
|
+
assert first.runs == 10
|
|
483
|
+
assert first.cost == 1500.50
|
|
484
|
+
assert first.start_date == datetime(2026, 3, 25, 10, 0, tzinfo=UTC)
|
|
485
|
+
assert first.end_date == datetime(2026, 3, 27, 10, 0, tzinfo=UTC)
|
|
486
|
+
|
|
487
|
+
second = jobs[1]
|
|
488
|
+
assert second.product_type_id is None
|
|
489
|
+
assert second.cost is None
|
|
490
|
+
|
|
491
|
+
@pytest.mark.asyncio
|
|
492
|
+
async def test_get_industry_jobs_include_completed(self):
|
|
493
|
+
"""Industry jobs with include_completed parameter."""
|
|
494
|
+
with aioresponses() as mocked:
|
|
495
|
+
mocked.get(
|
|
496
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/industry/jobs/"
|
|
497
|
+
"?datasource=tranquility&include_completed=true",
|
|
498
|
+
payload=[],
|
|
499
|
+
)
|
|
500
|
+
async with aiohttp.ClientSession() as session:
|
|
501
|
+
auth = MockAuth(session)
|
|
502
|
+
client = EveOnlineClient(auth=auth)
|
|
503
|
+
jobs = await client.async_get_industry_jobs(CHARACTER_ID, include_completed=True)
|
|
504
|
+
|
|
505
|
+
assert jobs == []
|
|
506
|
+
|
|
507
|
+
@pytest.mark.asyncio
|
|
508
|
+
async def test_get_industry_jobs_empty(self):
|
|
509
|
+
"""No active industry jobs returns empty list."""
|
|
510
|
+
with aioresponses() as mocked:
|
|
511
|
+
mocked.get(
|
|
512
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/industry/jobs/?datasource=tranquility",
|
|
513
|
+
payload=[],
|
|
514
|
+
)
|
|
515
|
+
async with aiohttp.ClientSession() as session:
|
|
516
|
+
auth = MockAuth(session)
|
|
517
|
+
client = EveOnlineClient(auth=auth)
|
|
518
|
+
jobs = await client.async_get_industry_jobs(CHARACTER_ID)
|
|
519
|
+
|
|
520
|
+
assert jobs == []
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
class TestMarketOrders:
|
|
524
|
+
"""Test GET /characters/{character_id}/orders/ endpoint."""
|
|
525
|
+
|
|
526
|
+
@pytest.mark.asyncio
|
|
527
|
+
async def test_get_market_orders_success(self, market_orders_data):
|
|
528
|
+
"""Successful market orders fetch."""
|
|
529
|
+
with aioresponses() as mocked:
|
|
530
|
+
mocked.get(
|
|
531
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/orders/?datasource=tranquility",
|
|
532
|
+
payload=market_orders_data,
|
|
533
|
+
)
|
|
534
|
+
async with aiohttp.ClientSession() as session:
|
|
535
|
+
auth = MockAuth(session)
|
|
536
|
+
client = EveOnlineClient(auth=auth)
|
|
537
|
+
orders = await client.async_get_market_orders(CHARACTER_ID)
|
|
538
|
+
|
|
539
|
+
assert len(orders) == 2
|
|
540
|
+
assert all(isinstance(o, MarketOrder) for o in orders)
|
|
541
|
+
|
|
542
|
+
sell = orders[0]
|
|
543
|
+
assert sell.order_id == 9876543
|
|
544
|
+
assert sell.is_buy_order is False
|
|
545
|
+
assert sell.price == 5.50
|
|
546
|
+
assert sell.volume_remain == 100000
|
|
547
|
+
assert sell.volume_total == 500000
|
|
548
|
+
assert sell.duration == 90
|
|
549
|
+
assert sell.range == "region"
|
|
550
|
+
assert sell.issued == datetime(2026, 3, 20, 12, 0, tzinfo=UTC)
|
|
551
|
+
|
|
552
|
+
buy = orders[1]
|
|
553
|
+
assert buy.is_buy_order is True
|
|
554
|
+
assert buy.price == 10.00
|
|
555
|
+
assert buy.min_volume is None
|
|
556
|
+
|
|
557
|
+
@pytest.mark.asyncio
|
|
558
|
+
async def test_get_market_orders_empty(self):
|
|
559
|
+
"""No active market orders returns empty list."""
|
|
560
|
+
with aioresponses() as mocked:
|
|
561
|
+
mocked.get(
|
|
562
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/orders/?datasource=tranquility",
|
|
563
|
+
payload=[],
|
|
564
|
+
)
|
|
565
|
+
async with aiohttp.ClientSession() as session:
|
|
566
|
+
auth = MockAuth(session)
|
|
567
|
+
client = EveOnlineClient(auth=auth)
|
|
568
|
+
orders = await client.async_get_market_orders(CHARACTER_ID)
|
|
569
|
+
|
|
570
|
+
assert orders == []
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
class TestJumpFatigue:
|
|
574
|
+
"""Test GET /characters/{character_id}/fatigue/ endpoint."""
|
|
575
|
+
|
|
576
|
+
@pytest.mark.asyncio
|
|
577
|
+
async def test_get_jump_fatigue_success(self, jump_fatigue_data):
|
|
578
|
+
"""Successful jump fatigue fetch."""
|
|
579
|
+
with aioresponses() as mocked:
|
|
580
|
+
mocked.get(
|
|
581
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/fatigue/?datasource=tranquility",
|
|
582
|
+
payload=jump_fatigue_data,
|
|
583
|
+
)
|
|
584
|
+
async with aiohttp.ClientSession() as session:
|
|
585
|
+
auth = MockAuth(session)
|
|
586
|
+
client = EveOnlineClient(auth=auth)
|
|
587
|
+
fatigue = await client.async_get_jump_fatigue(CHARACTER_ID)
|
|
588
|
+
|
|
589
|
+
assert isinstance(fatigue, JumpFatigue)
|
|
590
|
+
assert fatigue.jump_fatigue_expire_date == datetime(2026, 3, 27, 15, 30, tzinfo=UTC)
|
|
591
|
+
assert fatigue.last_jump_date == datetime(2026, 3, 26, 12, 0, tzinfo=UTC)
|
|
592
|
+
assert fatigue.last_update_date == datetime(2026, 3, 26, 12, 0, tzinfo=UTC)
|
|
593
|
+
|
|
594
|
+
@pytest.mark.asyncio
|
|
595
|
+
async def test_get_jump_fatigue_no_fatigue(self):
|
|
596
|
+
"""Character with no jump fatigue (all fields empty)."""
|
|
597
|
+
with aioresponses() as mocked:
|
|
598
|
+
mocked.get(
|
|
599
|
+
f"{ESI_BASE_URL}/characters/{CHARACTER_ID}/fatigue/?datasource=tranquility",
|
|
600
|
+
payload={},
|
|
601
|
+
)
|
|
602
|
+
async with aiohttp.ClientSession() as session:
|
|
603
|
+
auth = MockAuth(session)
|
|
604
|
+
client = EveOnlineClient(auth=auth)
|
|
605
|
+
fatigue = await client.async_get_jump_fatigue(CHARACTER_ID)
|
|
606
|
+
|
|
607
|
+
assert fatigue.jump_fatigue_expire_date is None
|
|
608
|
+
assert fatigue.last_jump_date is None
|
|
609
|
+
assert fatigue.last_update_date is None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/requires.txt
RENAMED
|
File without changes
|
{python_eveonline-0.1.0 → python_eveonline-0.2.1}/src/python_eveonline.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|