tradedangerous 10.16.17__py3-none-any.whl → 11.0.0__py3-none-any.whl
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.
Potentially problematic release.
This version of tradedangerous might be problematic. Click here for more details.
- tradedangerous/__init__.py +4 -4
- tradedangerous/cache.py +183 -148
- tradedangerous/cli.py +2 -7
- tradedangerous/commands/TEMPLATE.py +1 -2
- tradedangerous/commands/__init__.py +2 -4
- tradedangerous/commands/buildcache_cmd.py +6 -11
- tradedangerous/commands/buy_cmd.py +11 -12
- tradedangerous/commands/commandenv.py +16 -15
- tradedangerous/commands/exceptions.py +6 -4
- tradedangerous/commands/export_cmd.py +2 -4
- tradedangerous/commands/import_cmd.py +3 -5
- tradedangerous/commands/local_cmd.py +16 -25
- tradedangerous/commands/market_cmd.py +9 -8
- tradedangerous/commands/nav_cmd.py +17 -25
- tradedangerous/commands/olddata_cmd.py +9 -15
- tradedangerous/commands/parsing.py +9 -6
- tradedangerous/commands/rares_cmd.py +9 -10
- tradedangerous/commands/run_cmd.py +25 -26
- tradedangerous/commands/sell_cmd.py +9 -9
- tradedangerous/commands/shipvendor_cmd.py +4 -7
- tradedangerous/commands/station_cmd.py +8 -14
- tradedangerous/commands/trade_cmd.py +5 -10
- tradedangerous/commands/update_cmd.py +10 -7
- tradedangerous/commands/update_gui.py +1 -3
- tradedangerous/corrections.py +1 -3
- tradedangerous/csvexport.py +8 -8
- tradedangerous/edscupdate.py +4 -6
- tradedangerous/edsmupdate.py +4 -4
- tradedangerous/formatting.py +53 -40
- tradedangerous/fs.py +6 -6
- tradedangerous/gui.py +53 -62
- tradedangerous/jsonprices.py +8 -16
- tradedangerous/mapping.py +4 -3
- tradedangerous/mfd/__init__.py +2 -4
- tradedangerous/mfd/saitek/__init__.py +0 -1
- tradedangerous/mfd/saitek/directoutput.py +8 -11
- tradedangerous/mfd/saitek/x52pro.py +5 -7
- tradedangerous/misc/checkpricebounds.py +2 -3
- tradedangerous/misc/clipboard.py +2 -3
- tradedangerous/misc/coord64.py +2 -1
- tradedangerous/misc/derp-sentinel.py +1 -1
- tradedangerous/misc/diff-system-csvs.py +3 -0
- tradedangerous/misc/eddb.py +1 -3
- tradedangerous/misc/eddn.py +2 -2
- tradedangerous/misc/edsc.py +7 -14
- tradedangerous/misc/edsm.py +1 -8
- tradedangerous/misc/importeddbstats.py +2 -1
- tradedangerous/misc/prices-json-exp.py +7 -5
- tradedangerous/misc/progress.py +2 -2
- tradedangerous/plugins/__init__.py +2 -2
- tradedangerous/plugins/edapi_plug.py +13 -19
- tradedangerous/plugins/edcd_plug.py +4 -5
- tradedangerous/plugins/eddblink_plug.py +14 -17
- tradedangerous/plugins/edmc_batch_plug.py +3 -5
- tradedangerous/plugins/journal_plug.py +2 -1
- tradedangerous/plugins/netlog_plug.py +5 -5
- tradedangerous/plugins/spansh_plug.py +393 -176
- tradedangerous/prices.py +19 -20
- tradedangerous/submit-distances.py +3 -8
- tradedangerous/templates/TradeDangerous.sql +305 -306
- tradedangerous/trade.py +12 -5
- tradedangerous/tradecalc.py +30 -34
- tradedangerous/tradedb.py +140 -206
- tradedangerous/tradeenv.py +143 -69
- tradedangerous/tradegui.py +4 -2
- tradedangerous/transfers.py +23 -20
- tradedangerous/version.py +1 -1
- {tradedangerous-10.16.17.dist-info → tradedangerous-11.0.0.dist-info}/METADATA +2 -2
- tradedangerous-11.0.0.dist-info/RECORD +79 -0
- tradedangerous-10.16.17.dist-info/RECORD +0 -79
- {tradedangerous-10.16.17.dist-info → tradedangerous-11.0.0.dist-info}/LICENSE +0 -0
- {tradedangerous-10.16.17.dist-info → tradedangerous-11.0.0.dist-info}/WHEEL +0 -0
- {tradedangerous-10.16.17.dist-info → tradedangerous-11.0.0.dist-info}/entry_points.txt +0 -0
- {tradedangerous-10.16.17.dist-info → tradedangerous-11.0.0.dist-info}/top_level.txt +0 -0
tradedangerous/tradedb.py
CHANGED
|
@@ -49,41 +49,32 @@ Simplistic use might be:
|
|
|
49
49
|
|
|
50
50
|
######################################################################
|
|
51
51
|
# Imports
|
|
52
|
+
from __future__ import annotations
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
from collections import namedtuple, defaultdict
|
|
55
|
-
from pathlib import Path
|
|
56
|
-
from .tradeenv import TradeEnv
|
|
57
|
-
from .tradeexcept import TradeException
|
|
58
|
-
|
|
59
|
-
from . import cache, fs
|
|
54
|
+
from collections import namedtuple
|
|
60
55
|
from contextlib import closing
|
|
56
|
+
from math import sqrt as math_sqrt
|
|
57
|
+
from pathlib import Path
|
|
61
58
|
import heapq
|
|
62
59
|
import itertools
|
|
63
60
|
import locale
|
|
64
|
-
import math
|
|
65
|
-
import os
|
|
66
61
|
import re
|
|
67
62
|
import sqlite3
|
|
68
63
|
import sys
|
|
64
|
+
import typing
|
|
65
|
+
|
|
66
|
+
from .tradeenv import TradeEnv
|
|
67
|
+
from .tradeexcept import TradeException
|
|
68
|
+
from . import cache, fs
|
|
69
|
+
|
|
70
|
+
if typing.TYPE_CHECKING:
|
|
71
|
+
from typing import Generator
|
|
72
|
+
from typing import Optional, Union
|
|
69
73
|
|
|
70
|
-
haveNumpy = False
|
|
71
|
-
try:
|
|
72
|
-
import numpy
|
|
73
|
-
import numpy.linalg
|
|
74
|
-
haveNumpy = True
|
|
75
|
-
except (KeyError, ImportError):
|
|
76
|
-
pass
|
|
77
|
-
if not haveNumpy:
|
|
78
|
-
class numpy(object):
|
|
79
|
-
array = False
|
|
80
|
-
float32 = False
|
|
81
|
-
ascontiguousarray = False
|
|
82
|
-
class linalg(object):
|
|
83
|
-
norm = False
|
|
84
74
|
|
|
85
75
|
locale.setlocale(locale.LC_ALL, '')
|
|
86
76
|
|
|
77
|
+
|
|
87
78
|
######################################################################
|
|
88
79
|
# Classes
|
|
89
80
|
|
|
@@ -115,22 +106,20 @@ class AmbiguityError(TradeException):
|
|
|
115
106
|
key(c) for c in anyMatch[0:-1]
|
|
116
107
|
)
|
|
117
108
|
opportunities += " or " + key(anyMatch[-1])
|
|
118
|
-
return '{} "{}" could match {}'
|
|
119
|
-
self.lookupType, str(self.searchKey),
|
|
120
|
-
opportunities
|
|
121
|
-
)
|
|
109
|
+
return f'{self.lookupType} "{self.searchKey}" could match {opportunities}'
|
|
122
110
|
|
|
123
111
|
class SystemNotStationError(TradeException):
|
|
124
112
|
"""
|
|
125
113
|
Raised when a station lookup matched a System but
|
|
126
114
|
could not be automatically reduced to a Station.
|
|
127
115
|
"""
|
|
128
|
-
pass
|
|
116
|
+
pass # pylint: disable=unnecessary-pass # (it's not)
|
|
117
|
+
|
|
129
118
|
|
|
130
119
|
######################################################################
|
|
131
120
|
|
|
132
121
|
|
|
133
|
-
def
|
|
122
|
+
def make_stellar_grid_key(x: float, y: float, z: float) -> int:
|
|
134
123
|
"""
|
|
135
124
|
The Stellar Grid is a map of systems based on their Stellar
|
|
136
125
|
co-ordinates rounded down to 32lys. This makes it much easier
|
|
@@ -138,7 +127,8 @@ def makeStellarGridKey(x, y, z):
|
|
|
138
127
|
"""
|
|
139
128
|
return (int(x) >> 5, int(y) >> 5, int(z) >> 5)
|
|
140
129
|
|
|
141
|
-
|
|
130
|
+
|
|
131
|
+
class System:
|
|
142
132
|
"""
|
|
143
133
|
Describes a star system which may contain one or more Station objects.
|
|
144
134
|
|
|
@@ -152,65 +142,28 @@ class System(object):
|
|
|
152
142
|
'_rangeCache'
|
|
153
143
|
)
|
|
154
144
|
|
|
155
|
-
class RangeCache
|
|
145
|
+
class RangeCache:
|
|
156
146
|
"""
|
|
157
147
|
Lazily populated cache of neighboring systems.
|
|
158
148
|
"""
|
|
159
149
|
def __init__(self):
|
|
160
150
|
self.systems = []
|
|
161
|
-
self.
|
|
151
|
+
self.probed_ly = 0.
|
|
162
152
|
|
|
163
|
-
def __init__(
|
|
164
|
-
self, ID, dbname, posX, posY, posZ, addedID,
|
|
165
|
-
ary=numpy.array,
|
|
166
|
-
nptype=numpy.float32,
|
|
167
|
-
):
|
|
153
|
+
def __init__(self, ID, dbname, posX, posY, posZ, addedID) -> None:
|
|
168
154
|
self.ID = ID
|
|
169
155
|
self.dbname = dbname
|
|
170
156
|
self.posX, self.posY, self.posZ = posX, posY, posZ
|
|
171
|
-
if ary:
|
|
172
|
-
self.pos = ary([posX, posY, posZ], nptype)
|
|
173
157
|
self.addedID = addedID or 0
|
|
174
158
|
self.stations = ()
|
|
175
159
|
self._rangeCache = None
|
|
176
160
|
|
|
177
161
|
@property
|
|
178
|
-
def system(self):
|
|
162
|
+
def system(self) -> 'System':
|
|
163
|
+
""" Returns self for compatibility with the undefined 'Positional' interface. """
|
|
179
164
|
return self
|
|
180
165
|
|
|
181
|
-
def
|
|
182
|
-
"""
|
|
183
|
-
Returns the square of the distance between two systems.
|
|
184
|
-
|
|
185
|
-
It is slightly cheaper to calculate the square of the
|
|
186
|
-
distance between two points, so when you are primarily
|
|
187
|
-
doing distance checks you can use this less expensive
|
|
188
|
-
distance query and only perform a sqrt (** 0.5) on the
|
|
189
|
-
distances that fall within your constraint.
|
|
190
|
-
|
|
191
|
-
Args:
|
|
192
|
-
other:
|
|
193
|
-
The other System to measure the distance between.
|
|
194
|
-
|
|
195
|
-
Returns:
|
|
196
|
-
Distance in light years to the power of 2 (i.e. squared).
|
|
197
|
-
|
|
198
|
-
Example:
|
|
199
|
-
# Calculate which of [systems] is within 12 ly
|
|
200
|
-
# of System "target".
|
|
201
|
-
maxLySq = 12 ** 2 # Maximum of 12 ly.
|
|
202
|
-
inRange = []
|
|
203
|
-
for sys in systems:
|
|
204
|
-
if sys.distToSq(target) <= maxLySq:
|
|
205
|
-
inRange.append(sys)
|
|
206
|
-
"""
|
|
207
|
-
return (
|
|
208
|
-
(self.posX - other.posX) ** 2 +
|
|
209
|
-
(self.posY - other.posY) ** 2 +
|
|
210
|
-
(self.posZ - other.posZ) ** 2
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
def distanceTo(self, other):
|
|
166
|
+
def distanceTo(self, other: 'System') -> float:
|
|
214
167
|
"""
|
|
215
168
|
Returns the distance (in ly) between two systems.
|
|
216
169
|
|
|
@@ -226,26 +179,10 @@ class System(object):
|
|
|
226
179
|
lhs.distanceTo(rhs),
|
|
227
180
|
))
|
|
228
181
|
"""
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
(self.posY - other.posY) ** 2 +
|
|
232
|
-
(self.posZ - other.posZ) ** 2
|
|
233
|
-
) ** 0.5 # fast sqrt
|
|
234
|
-
|
|
235
|
-
if haveNumpy:
|
|
236
|
-
def all_distances(
|
|
237
|
-
self, iterable,
|
|
238
|
-
ary=numpy.ascontiguousarray, norm=numpy.linalg.norm,
|
|
239
|
-
):
|
|
240
|
-
"""
|
|
241
|
-
Takes a list of systems and returns their distances from this system.
|
|
242
|
-
"""
|
|
243
|
-
return numpy.linalg.norm(
|
|
244
|
-
ary([s.pos for s in iterable]) - self.pos,
|
|
245
|
-
ord=2, axis=1.
|
|
246
|
-
)
|
|
182
|
+
dx, dy, dz = self.posX - other.posX, self.posY - other.posY, self.posZ - other.posZ
|
|
183
|
+
return math_sqrt(dx * dx + dy * dy + dz * dz)
|
|
247
184
|
|
|
248
|
-
def getStation(self,
|
|
185
|
+
def getStation(self, name: str) -> 'Optional[Station]':
|
|
249
186
|
"""
|
|
250
187
|
Quick case-insensitive lookup of a station name within the
|
|
251
188
|
stations in this system.
|
|
@@ -254,16 +191,17 @@ class System(object):
|
|
|
254
191
|
Station() object if a match is found,
|
|
255
192
|
otherwise None.
|
|
256
193
|
"""
|
|
257
|
-
|
|
194
|
+
name = name.upper()
|
|
258
195
|
for station in self.stations:
|
|
259
|
-
if station.
|
|
196
|
+
if station.name == name:
|
|
260
197
|
return station
|
|
261
198
|
return None
|
|
262
199
|
|
|
263
|
-
def name(self, detail=0):
|
|
200
|
+
def name(self, detail: int = 0) -> str: # pylint: disable=unused-argument
|
|
201
|
+
""" Returns the display name for this System."""
|
|
264
202
|
return self.dbname
|
|
265
203
|
|
|
266
|
-
def
|
|
204
|
+
def text(self) -> str:
|
|
267
205
|
return self.dbname
|
|
268
206
|
|
|
269
207
|
######################################################################
|
|
@@ -278,7 +216,7 @@ class DestinationNode(namedtuple('DestinationNode', [
|
|
|
278
216
|
])):
|
|
279
217
|
pass
|
|
280
218
|
|
|
281
|
-
class Station
|
|
219
|
+
class Station:
|
|
282
220
|
"""
|
|
283
221
|
Describes a station (trading or otherwise) in a system.
|
|
284
222
|
|
|
@@ -315,8 +253,8 @@ class Station(object):
|
|
|
315
253
|
self.dataAge = dataAge
|
|
316
254
|
system.stations = system.stations + (self,)
|
|
317
255
|
|
|
318
|
-
def name(self, detail=0):
|
|
319
|
-
return
|
|
256
|
+
def name(self, detail: int = 0) -> str: # pylint: disable=unused-argument
|
|
257
|
+
return f"{self.system.dbname}/{self.dbname}"
|
|
320
258
|
|
|
321
259
|
def checkPadSize(self, maxPadSize):
|
|
322
260
|
"""
|
|
@@ -379,16 +317,16 @@ class Station(object):
|
|
|
379
317
|
Same as checkPlanetary, but for fleet carriers.
|
|
380
318
|
"""
|
|
381
319
|
return (not fleet or self.fleet in fleet)
|
|
382
|
-
|
|
383
|
-
|
|
320
|
+
|
|
321
|
+
|
|
384
322
|
def checkOdyssey(self, odyssey):
|
|
385
323
|
"""
|
|
386
324
|
Same as checkPlanetary, but for Odyssey.
|
|
387
325
|
"""
|
|
388
326
|
return (not odyssey or self.odyssey in odyssey)
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
def distFromStar(self, addSuffix=False):
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def distFromStar(self, addSuffix: bool = False) -> str:
|
|
392
330
|
"""
|
|
393
331
|
Returns a textual description of the distance from this
|
|
394
332
|
Station to the parent star.
|
|
@@ -399,23 +337,20 @@ class Station(object):
|
|
|
399
337
|
"""
|
|
400
338
|
ls = self.lsFromStar
|
|
401
339
|
if not ls:
|
|
402
|
-
if addSuffix
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
340
|
+
return "Unk" if addSuffix else "?"
|
|
341
|
+
|
|
342
|
+
suffix = "ls" if addSuffix else ""
|
|
343
|
+
|
|
406
344
|
if ls < 1000:
|
|
407
|
-
|
|
408
|
-
return '{:n}'.format(ls)+suffix
|
|
345
|
+
return f"{ls:n}{suffix}"
|
|
409
346
|
if ls < 10000:
|
|
410
|
-
|
|
411
|
-
return '{:.2f}K'.format(ls / 1000)+suffix
|
|
347
|
+
return f"{ls / 1000:.2f}K{suffix}"
|
|
412
348
|
if ls < 1000000:
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
return '{:.2f}ly'.format(ls / (365*24*60*60))
|
|
349
|
+
return f"{int(ls / 1000):n}K{suffix}"
|
|
350
|
+
return f'{ls / (365*24*60*60):.2f}ly'
|
|
416
351
|
|
|
417
352
|
@property
|
|
418
|
-
def isTrading(self):
|
|
353
|
+
def isTrading(self) -> bool:
|
|
419
354
|
"""
|
|
420
355
|
True if the station is thought to be trading.
|
|
421
356
|
|
|
@@ -428,11 +363,11 @@ class Station(object):
|
|
|
428
363
|
def itemDataAgeStr(self):
|
|
429
364
|
""" Returns the age in days of item data if present, else "-". """
|
|
430
365
|
if self.itemCount and self.dataAge:
|
|
431
|
-
return "{:7.2f}"
|
|
366
|
+
return f"{self.dataAge:7.2f}"
|
|
432
367
|
return "-"
|
|
433
368
|
|
|
434
|
-
def
|
|
435
|
-
return
|
|
369
|
+
def text(self) -> str:
|
|
370
|
+
return f"{self.system.dbname}/{self.dbname}"
|
|
436
371
|
|
|
437
372
|
######################################################################
|
|
438
373
|
|
|
@@ -450,7 +385,7 @@ class Ship(namedtuple('Ship', (
|
|
|
450
385
|
stations -- List of Stations ship is sold at.
|
|
451
386
|
"""
|
|
452
387
|
|
|
453
|
-
def name(self, detail=0):
|
|
388
|
+
def name(self, detail=0): # pylint: disable=unused-argument
|
|
454
389
|
return self.dbname
|
|
455
390
|
|
|
456
391
|
######################################################################
|
|
@@ -478,13 +413,13 @@ class Category(namedtuple('Category', (
|
|
|
478
413
|
Returns the display name for this Category.
|
|
479
414
|
"""
|
|
480
415
|
|
|
481
|
-
def name(self, detail=0):
|
|
416
|
+
def name(self, detail=0): # pylint: disable=unused-argument
|
|
482
417
|
return self.dbname.upper()
|
|
483
418
|
|
|
484
419
|
######################################################################
|
|
485
420
|
|
|
486
421
|
|
|
487
|
-
class Item
|
|
422
|
+
class Item:
|
|
488
423
|
"""
|
|
489
424
|
A product that can be bought/sold in the game.
|
|
490
425
|
|
|
@@ -554,7 +489,7 @@ class Trade(namedtuple('Trade', (
|
|
|
554
489
|
######################################################################
|
|
555
490
|
|
|
556
491
|
|
|
557
|
-
class TradeDB
|
|
492
|
+
class TradeDB:
|
|
558
493
|
"""
|
|
559
494
|
Encapsulation for the database layer.
|
|
560
495
|
|
|
@@ -635,7 +570,7 @@ class TradeDB(object):
|
|
|
635
570
|
load=True,
|
|
636
571
|
debug=None,
|
|
637
572
|
):
|
|
638
|
-
self.conn
|
|
573
|
+
self.conn: sqlite3.Connection = None
|
|
639
574
|
self.tradingCount = None
|
|
640
575
|
|
|
641
576
|
tdenv = tdenv or TradeEnv(debug=(debug or 0))
|
|
@@ -666,6 +601,18 @@ class TradeDB(object):
|
|
|
666
601
|
|
|
667
602
|
self.avgSelling, self.avgBuying = None, None
|
|
668
603
|
self.tradingStationCount = 0
|
|
604
|
+
self.addedByID = None
|
|
605
|
+
self.systemByID = None
|
|
606
|
+
self.systemByName = None
|
|
607
|
+
self.stellarGrid = None
|
|
608
|
+
self.stationByID = None
|
|
609
|
+
self.shipByID = None
|
|
610
|
+
self.categoryByID = None
|
|
611
|
+
self.itemByID = None
|
|
612
|
+
self.itemByName = None
|
|
613
|
+
self.itemByFDevID = None
|
|
614
|
+
self.rareItemByID = None
|
|
615
|
+
self.rareItemByName = None
|
|
669
616
|
|
|
670
617
|
if load:
|
|
671
618
|
self.reloadCache()
|
|
@@ -676,22 +623,16 @@ class TradeDB(object):
|
|
|
676
623
|
"""
|
|
677
624
|
Returns the distance in ly between two points.
|
|
678
625
|
"""
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
dZ = (lz - rz)
|
|
682
|
-
distSq = (dX ** 2) + (dY ** 2) + (dZ ** 2)
|
|
683
|
-
return distSq
|
|
626
|
+
dx, dy, dz = lx - rx, ly - ry, lz - rz
|
|
627
|
+
return (dx * dx) + (dy * dy) + (dz * dz)
|
|
684
628
|
|
|
685
629
|
@staticmethod
|
|
686
630
|
def calculateDistance(lx, ly, lz, rx, ry, rz):
|
|
687
631
|
"""
|
|
688
632
|
Returns the distance in ly between two points.
|
|
689
633
|
"""
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
dZ = (lz - rz)
|
|
693
|
-
distSq = (dX ** 2) + (dY ** 2) + (dZ ** 2)
|
|
694
|
-
return distSq ** 0.5
|
|
634
|
+
dx, dy, dz = lx - rx, ly - ry, lz - rz
|
|
635
|
+
return math_sqrt((dx * dx) + (dy * dy) + (dz * dz))
|
|
695
636
|
|
|
696
637
|
############################################################
|
|
697
638
|
# Access to the underlying database.
|
|
@@ -705,7 +646,7 @@ class TradeDB(object):
|
|
|
705
646
|
conn.execute("PRAGMA synchronous=OFF")
|
|
706
647
|
conn.execute("PRAGMA temp_store=MEMORY")
|
|
707
648
|
conn.execute("PRAGMA auto_vacuum=INCREMENTAL")
|
|
708
|
-
|
|
649
|
+
|
|
709
650
|
conn.create_function('dist2', 6, TradeDB.calculateDistance2)
|
|
710
651
|
self.conn = conn
|
|
711
652
|
return conn
|
|
@@ -912,7 +853,7 @@ class TradeDB(object):
|
|
|
912
853
|
commit=True,
|
|
913
854
|
):
|
|
914
855
|
""" Removes a system and it's stations from the local DB. """
|
|
915
|
-
for stn in self.stations:
|
|
856
|
+
for stn in self.stations():
|
|
916
857
|
self.removeLocalStation(stn, commit=False)
|
|
917
858
|
db = self.getDB()
|
|
918
859
|
db.execute("""
|
|
@@ -939,9 +880,9 @@ class TradeDB(object):
|
|
|
939
880
|
Divides the galaxy into a fixed-sized grid allowing us to
|
|
940
881
|
aggregate small numbers of stars by locality.
|
|
941
882
|
"""
|
|
942
|
-
stellarGrid = self.stellarGrid =
|
|
883
|
+
stellarGrid = self.stellarGrid = {}
|
|
943
884
|
for system in self.systemByID.values():
|
|
944
|
-
key =
|
|
885
|
+
key = make_stellar_grid_key(system.posX, system.posY, system.posZ)
|
|
945
886
|
try:
|
|
946
887
|
grid = stellarGrid[key]
|
|
947
888
|
except KeyError:
|
|
@@ -970,9 +911,9 @@ class TradeDB(object):
|
|
|
970
911
|
self.__buildStellarGrid()
|
|
971
912
|
|
|
972
913
|
sysX, sysY, sysZ = system.posX, system.posY, system.posZ
|
|
973
|
-
lwrBound =
|
|
974
|
-
uprBound =
|
|
975
|
-
lySq = ly **
|
|
914
|
+
lwrBound = make_stellar_grid_key(sysX - ly, sysY - ly, sysZ - ly)
|
|
915
|
+
uprBound = make_stellar_grid_key(sysX + ly, sysY + ly, sysZ + ly)
|
|
916
|
+
lySq = ly * ly # in 64-bit python, ** invokes a function call making it 4x expensive as *.
|
|
976
917
|
stellarGrid = self.stellarGrid
|
|
977
918
|
for x in range(lwrBound[0], uprBound[0]+1):
|
|
978
919
|
for y in range(lwrBound[1], uprBound[1]+1):
|
|
@@ -982,17 +923,20 @@ class TradeDB(object):
|
|
|
982
923
|
except KeyError:
|
|
983
924
|
continue
|
|
984
925
|
for candidate in grid:
|
|
985
|
-
|
|
926
|
+
delta = candidate.posX - sysX
|
|
927
|
+
distSq = delta * delta
|
|
986
928
|
if distSq > lySq:
|
|
987
929
|
continue
|
|
988
|
-
|
|
930
|
+
delta = candidate.posY - sysY
|
|
931
|
+
distSq += delta * delta
|
|
989
932
|
if distSq > lySq:
|
|
990
933
|
continue
|
|
991
|
-
|
|
934
|
+
delta = candidate.posZ - sysZ
|
|
935
|
+
distSq += delta * delta
|
|
992
936
|
if distSq > lySq:
|
|
993
937
|
continue
|
|
994
938
|
if candidate is not system:
|
|
995
|
-
yield candidate, distSq
|
|
939
|
+
yield candidate, math_sqrt(distSq)
|
|
996
940
|
|
|
997
941
|
def genSystemsInRange(self, system, ly, includeSelf=False):
|
|
998
942
|
"""
|
|
@@ -1016,32 +960,32 @@ class TradeDB(object):
|
|
|
1016
960
|
The distance in lightyears between system and candidate.
|
|
1017
961
|
"""
|
|
1018
962
|
|
|
1019
|
-
|
|
1020
|
-
if not
|
|
1021
|
-
|
|
1022
|
-
|
|
963
|
+
cur_cache = system._rangeCache # pylint: disable=protected-access
|
|
964
|
+
if not cur_cache:
|
|
965
|
+
cur_cache = system._rangeCache = System.RangeCache()
|
|
966
|
+
cached_systems = cur_cache.systems
|
|
1023
967
|
|
|
1024
|
-
if ly >
|
|
968
|
+
if ly > cur_cache.probed_ly:
|
|
1025
969
|
# Consult the database for stars we haven't seen.
|
|
1026
|
-
|
|
970
|
+
cached_systems = cur_cache.systems = list(
|
|
1027
971
|
self.genStellarGrid(system, ly)
|
|
1028
972
|
)
|
|
1029
|
-
|
|
1030
|
-
|
|
973
|
+
cached_systems.sort(key=lambda ent: ent[1])
|
|
974
|
+
cur_cache.probed_ly = ly
|
|
1031
975
|
|
|
1032
976
|
if includeSelf:
|
|
1033
977
|
yield system, 0.
|
|
1034
978
|
|
|
1035
|
-
if
|
|
979
|
+
if cur_cache.probed_ly > ly:
|
|
1036
980
|
# Cache may contain values outside our view
|
|
1037
|
-
for
|
|
981
|
+
for candidate, dist in cached_systems:
|
|
1038
982
|
if dist <= ly:
|
|
1039
|
-
yield
|
|
983
|
+
yield candidate, dist
|
|
1040
984
|
else:
|
|
1041
985
|
# No need to be conditional inside the loop
|
|
1042
|
-
yield from
|
|
986
|
+
yield from cached_systems
|
|
1043
987
|
|
|
1044
|
-
def getRoute(self, origin, dest, maxJumpLy, avoiding=
|
|
988
|
+
def getRoute(self, origin, dest, maxJumpLy, avoiding=None, stationInterval=0):
|
|
1045
989
|
"""
|
|
1046
990
|
Find a shortest route between two systems with an additional
|
|
1047
991
|
constraint that each system be a maximum of maxJumpLy from
|
|
@@ -1083,6 +1027,9 @@ class TradeDB(object):
|
|
|
1083
1027
|
|
|
1084
1028
|
"""
|
|
1085
1029
|
|
|
1030
|
+
if avoiding is None:
|
|
1031
|
+
avoiding = []
|
|
1032
|
+
|
|
1086
1033
|
if isinstance(origin, Station):
|
|
1087
1034
|
origin = origin.system
|
|
1088
1035
|
if isinstance(dest, Station):
|
|
@@ -1119,12 +1066,11 @@ class TradeDB(object):
|
|
|
1119
1066
|
|
|
1120
1067
|
maxPadSize = self.tdenv.padSize
|
|
1121
1068
|
if not maxPadSize:
|
|
1122
|
-
checkStations
|
|
1069
|
+
def checkStations(system: System) -> bool: # pylint: disable=function-redefined, missing-docstring
|
|
1070
|
+
return bool(system.stations())
|
|
1123
1071
|
else:
|
|
1124
|
-
checkStations
|
|
1125
|
-
stn for stn in system.stations
|
|
1126
|
-
if stn.checkPadSize(maxPadSize)
|
|
1127
|
-
)
|
|
1072
|
+
def checkStations(system: System) -> bool: # pylint: disable=function-redefined, missing-docstring
|
|
1073
|
+
return any(stn for stn in system.stations if stn.checkPadSize(maxPadSize))
|
|
1128
1074
|
|
|
1129
1075
|
while openSet:
|
|
1130
1076
|
weight, curDist, curSysID, stnDist = heappop(openSet)
|
|
@@ -1182,7 +1128,7 @@ class TradeDB(object):
|
|
|
1182
1128
|
############################################################
|
|
1183
1129
|
# Station data.
|
|
1184
1130
|
|
|
1185
|
-
def stations(self):
|
|
1131
|
+
def stations(self) -> 'Generator[Station, None, None]':
|
|
1186
1132
|
""" Iterate through the list of stations. """
|
|
1187
1133
|
yield from self.stationByID.values()
|
|
1188
1134
|
|
|
@@ -1211,7 +1157,7 @@ class TradeDB(object):
|
|
|
1211
1157
|
ID, systemID, name,
|
|
1212
1158
|
lsFromStar, market, blackMarket, shipyard,
|
|
1213
1159
|
maxPadSize, outfitting, rearm, refuel, repair, planetary, type_id
|
|
1214
|
-
) in cur
|
|
1160
|
+
) in cur:
|
|
1215
1161
|
isFleet = 'Y' if int(type_id) in types['fleet-carrier'] else 'N'
|
|
1216
1162
|
isOdyssey = 'Y' if int(type_id) in types['odyssey'] else 'N'
|
|
1217
1163
|
station = Station(
|
|
@@ -1372,7 +1318,7 @@ class TradeDB(object):
|
|
|
1372
1318
|
|
|
1373
1319
|
def _changed(label, old, new):
|
|
1374
1320
|
changes.append(
|
|
1375
|
-
"{}('{}'=>'{}')"
|
|
1321
|
+
f"{label}('{old}'=>'{new}')"
|
|
1376
1322
|
)
|
|
1377
1323
|
|
|
1378
1324
|
if name is not None:
|
|
@@ -1510,7 +1456,7 @@ class TradeDB(object):
|
|
|
1510
1456
|
@system/station
|
|
1511
1457
|
"""
|
|
1512
1458
|
|
|
1513
|
-
if isinstance(name, System
|
|
1459
|
+
if isinstance(name, (System, Station)):
|
|
1514
1460
|
return name
|
|
1515
1461
|
|
|
1516
1462
|
slashPos = name.find('/')
|
|
@@ -1577,7 +1523,8 @@ class TradeDB(object):
|
|
|
1577
1523
|
else:
|
|
1578
1524
|
anyMatch.append(place)
|
|
1579
1525
|
continue
|
|
1580
|
-
|
|
1526
|
+
|
|
1527
|
+
if subPos > 0:
|
|
1581
1528
|
if placeNameNorm[subPos] == ' ' and \
|
|
1582
1529
|
placeNameNorm[subPos + nameNormLen] == ' ':
|
|
1583
1530
|
wordMatch.append(place)
|
|
@@ -1602,10 +1549,11 @@ class TradeDB(object):
|
|
|
1602
1549
|
|
|
1603
1550
|
if sysName:
|
|
1604
1551
|
try:
|
|
1605
|
-
|
|
1606
|
-
exactMatch = [
|
|
1552
|
+
system = self.systemByName[sysName]
|
|
1553
|
+
exactMatch = [system]
|
|
1607
1554
|
except KeyError:
|
|
1608
1555
|
lookup(sysName, self.systemByID.values())
|
|
1556
|
+
|
|
1609
1557
|
if stnName:
|
|
1610
1558
|
# Are we considering the name as a station?
|
|
1611
1559
|
# (we don't if they type, e,g '@aulin')
|
|
@@ -1616,10 +1564,10 @@ class TradeDB(object):
|
|
|
1616
1564
|
# stations we compare against. Check first if there are
|
|
1617
1565
|
# any matches.
|
|
1618
1566
|
stationCandidates = []
|
|
1619
|
-
for
|
|
1567
|
+
for system in itertools.chain(
|
|
1620
1568
|
exactMatch, closeMatch, wordMatch, anyMatch
|
|
1621
1569
|
):
|
|
1622
|
-
stationCandidates +=
|
|
1570
|
+
stationCandidates += system.stations
|
|
1623
1571
|
# Clear out the candidate lists
|
|
1624
1572
|
exactMatch = []
|
|
1625
1573
|
closeMatch = []
|
|
@@ -1643,7 +1591,7 @@ class TradeDB(object):
|
|
|
1643
1591
|
# Note: this was a TradeException and may need to be again,
|
|
1644
1592
|
# but then we need to catch that error in commandenv
|
|
1645
1593
|
# when we process avoids
|
|
1646
|
-
raise LookupError("Unrecognized place: {}"
|
|
1594
|
+
raise LookupError(f"Unrecognized place: {name}")
|
|
1647
1595
|
|
|
1648
1596
|
# More than one match
|
|
1649
1597
|
raise AmbiguityError(
|
|
@@ -1661,12 +1609,7 @@ class TradeDB(object):
|
|
|
1661
1609
|
if isinstance(name, System):
|
|
1662
1610
|
# When given a system with only one station, return the station.
|
|
1663
1611
|
if len(name.stations) != 1:
|
|
1664
|
-
raise SystemNotStationError(
|
|
1665
|
-
"System '%s' has %d stations, "
|
|
1666
|
-
"please specify a station instead." % (
|
|
1667
|
-
name.str(), len(name.stations)
|
|
1668
|
-
)
|
|
1669
|
-
)
|
|
1612
|
+
raise SystemNotStationError(f"System '{name}' has {len(name.stations)} stations, please specify a station instead.")
|
|
1670
1613
|
return name.stations[0]
|
|
1671
1614
|
|
|
1672
1615
|
if system:
|
|
@@ -1675,7 +1618,7 @@ class TradeDB(object):
|
|
|
1675
1618
|
"Station", name, system.stations,
|
|
1676
1619
|
key=lambda system: system.dbname)
|
|
1677
1620
|
|
|
1678
|
-
|
|
1621
|
+
station, system = None, None
|
|
1679
1622
|
try:
|
|
1680
1623
|
system = TradeDB.listSearch(
|
|
1681
1624
|
"System", name, self.systemByID.values(),
|
|
@@ -1692,9 +1635,7 @@ class TradeDB(object):
|
|
|
1692
1635
|
pass
|
|
1693
1636
|
# If neither matched, we have a lookup error.
|
|
1694
1637
|
if not (station or system):
|
|
1695
|
-
raise LookupError(
|
|
1696
|
-
"'%s' did not match any station or system." % (name)
|
|
1697
|
-
)
|
|
1638
|
+
raise LookupError(f"'{name}' did not match any station or system.")
|
|
1698
1639
|
|
|
1699
1640
|
# If we matched both a station and a system, make sure they resovle to
|
|
1700
1641
|
# the same station otherwise we have an ambiguity. Some stations have
|
|
@@ -1711,10 +1652,7 @@ class TradeDB(object):
|
|
|
1711
1652
|
# system otherwise they need to specify a station name.
|
|
1712
1653
|
if len(system.stations) != 1:
|
|
1713
1654
|
raise SystemNotStationError(
|
|
1714
|
-
"System '
|
|
1715
|
-
"please specify a station instead." % (
|
|
1716
|
-
system.name(), len(system.stations)
|
|
1717
|
-
)
|
|
1655
|
+
f"System '{system.name()}' has {len(system.stations)} stations, please specify a station instead."
|
|
1718
1656
|
)
|
|
1719
1657
|
return system.stations[0]
|
|
1720
1658
|
|
|
@@ -1911,7 +1849,7 @@ class TradeDB(object):
|
|
|
1911
1849
|
category = self.categoryByID[categoryID]
|
|
1912
1850
|
item = Item(
|
|
1913
1851
|
ID, name, category,
|
|
1914
|
-
|
|
1852
|
+
f"{category.dbname}/{name}",
|
|
1915
1853
|
avgPrice, fdevID
|
|
1916
1854
|
)
|
|
1917
1855
|
itemByID[ID] = item
|
|
@@ -1945,7 +1883,7 @@ class TradeDB(object):
|
|
|
1945
1883
|
Query the database for average selling prices of all items.
|
|
1946
1884
|
"""
|
|
1947
1885
|
if not self.avgSelling:
|
|
1948
|
-
self.avgSelling = {itemID: 0 for itemID in self.itemByID
|
|
1886
|
+
self.avgSelling = {itemID: 0 for itemID in self.itemByID}
|
|
1949
1887
|
self.avgSelling.update({
|
|
1950
1888
|
ID: int(cr)
|
|
1951
1889
|
for ID, cr in self.getDB().execute("""
|
|
@@ -1965,7 +1903,7 @@ class TradeDB(object):
|
|
|
1965
1903
|
Query the database for average buying prices of all items.
|
|
1966
1904
|
"""
|
|
1967
1905
|
if not self.avgBuying:
|
|
1968
|
-
self.avgBuying = {itemID: 0 for itemID in self.itemByID
|
|
1906
|
+
self.avgBuying = {itemID: 0 for itemID in self.itemByID}
|
|
1969
1907
|
self.avgBuying.update({
|
|
1970
1908
|
ID: int(cr)
|
|
1971
1909
|
for ID, cr in self.getDB().execute("""
|
|
@@ -1992,8 +1930,8 @@ class TradeDB(object):
|
|
|
1992
1930
|
cost, max_allocation, illegal, suppressed
|
|
1993
1931
|
FROM RareItem
|
|
1994
1932
|
"""
|
|
1995
|
-
|
|
1996
|
-
|
|
1933
|
+
|
|
1934
|
+
|
|
1997
1935
|
rareItemByID, rareItemByName = {}, {}
|
|
1998
1936
|
stationByID = self.stationByID
|
|
1999
1937
|
with closing(self.query(stmt)) as cur:
|
|
@@ -2005,7 +1943,7 @@ class TradeDB(object):
|
|
|
2005
1943
|
category = self.categoryByID[catID]
|
|
2006
1944
|
rare = RareItem(
|
|
2007
1945
|
ID, station, name, cost, maxAlloc, illegal, suppressed,
|
|
2008
|
-
category,
|
|
1946
|
+
category, f"{category.dbname}/{name}"
|
|
2009
1947
|
)
|
|
2010
1948
|
rareItemByID[ID] = rareItemByName[name] = rare
|
|
2011
1949
|
self.rareItemByID = rareItemByID
|
|
@@ -2020,7 +1958,6 @@ class TradeDB(object):
|
|
|
2020
1958
|
# Price data.
|
|
2021
1959
|
|
|
2022
1960
|
def close(self):
|
|
2023
|
-
self.cur = None
|
|
2024
1961
|
if self.conn:
|
|
2025
1962
|
self.conn.close()
|
|
2026
1963
|
self.conn = None
|
|
@@ -2036,8 +1973,8 @@ class TradeDB(object):
|
|
|
2036
1973
|
"""
|
|
2037
1974
|
|
|
2038
1975
|
self.tdenv.DEBUG1("Loading data")
|
|
2039
|
-
|
|
2040
|
-
|
|
1976
|
+
|
|
1977
|
+
|
|
2041
1978
|
|
|
2042
1979
|
self._loadAdded()
|
|
2043
1980
|
self._loadSystems()
|
|
@@ -2082,7 +2019,7 @@ class TradeDB(object):
|
|
|
2082
2019
|
needle = lookup.translate(normTrans).translate(trimTrans)
|
|
2083
2020
|
partialMatch, wordMatch = [], []
|
|
2084
2021
|
# make a regex to match whole words
|
|
2085
|
-
wordRe = re.compile(
|
|
2022
|
+
wordRe = re.compile(f"\\b{lookup}\\b", re.IGNORECASE)
|
|
2086
2023
|
# describe a match
|
|
2087
2024
|
for entry in values:
|
|
2088
2025
|
entryKey = key(entry)
|
|
@@ -2113,12 +2050,10 @@ class TradeDB(object):
|
|
|
2113
2050
|
)
|
|
2114
2051
|
return partialMatch[0].value
|
|
2115
2052
|
# No matches
|
|
2116
|
-
raise LookupError(
|
|
2117
|
-
"Error: '%s' doesn't match any %s" % (lookup, listType)
|
|
2118
|
-
)
|
|
2053
|
+
raise LookupError(f"Error: '{lookup}' doesn't match any {listType}")
|
|
2119
2054
|
|
|
2120
2055
|
@staticmethod
|
|
2121
|
-
def normalizedStr(text):
|
|
2056
|
+
def normalizedStr(text: str) -> str:
|
|
2122
2057
|
"""
|
|
2123
2058
|
Returns a case folded, sanitized version of 'str' suitable for
|
|
2124
2059
|
performing simple and partial matches against. Removes various
|
|
@@ -2134,7 +2069,7 @@ class TradeDB(object):
|
|
|
2134
2069
|
######################################################################
|
|
2135
2070
|
# Assorted helpers
|
|
2136
2071
|
|
|
2137
|
-
def describeAge(ageInSeconds):
|
|
2072
|
+
def describeAge(ageInSeconds: Union[float, int]) -> str:
|
|
2138
2073
|
"""
|
|
2139
2074
|
Turns an age (in seconds) into a text representation.
|
|
2140
2075
|
"""
|
|
@@ -2144,10 +2079,9 @@ def describeAge(ageInSeconds):
|
|
|
2144
2079
|
if hours == 1:
|
|
2145
2080
|
return "1 hr"
|
|
2146
2081
|
if hours < 48:
|
|
2147
|
-
return
|
|
2082
|
+
return f"{hours} hrs"
|
|
2148
2083
|
days = int(hours / 24)
|
|
2149
2084
|
if days < 90:
|
|
2150
|
-
return
|
|
2085
|
+
return f"{days} days"
|
|
2151
2086
|
|
|
2152
|
-
|
|
2153
|
-
return str(months) + " mths"
|
|
2087
|
+
return f"{int(days / 31)} mths"
|