tradedangerous 11.5.3__py3-none-any.whl → 12.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/cache.py +567 -395
- tradedangerous/cli.py +2 -2
- tradedangerous/commands/TEMPLATE.py +25 -26
- tradedangerous/commands/__init__.py +8 -16
- tradedangerous/commands/buildcache_cmd.py +40 -10
- tradedangerous/commands/buy_cmd.py +57 -46
- tradedangerous/commands/commandenv.py +0 -2
- tradedangerous/commands/export_cmd.py +78 -50
- tradedangerous/commands/import_cmd.py +67 -31
- tradedangerous/commands/market_cmd.py +52 -19
- tradedangerous/commands/olddata_cmd.py +120 -107
- tradedangerous/commands/rares_cmd.py +122 -110
- tradedangerous/commands/run_cmd.py +118 -66
- tradedangerous/commands/sell_cmd.py +52 -45
- tradedangerous/commands/shipvendor_cmd.py +49 -234
- tradedangerous/commands/station_cmd.py +55 -485
- tradedangerous/commands/update_cmd.py +56 -420
- tradedangerous/csvexport.py +173 -162
- tradedangerous/gui.py +2 -2
- tradedangerous/plugins/eddblink_plug.py +387 -251
- tradedangerous/plugins/spansh_plug.py +2488 -821
- tradedangerous/prices.py +124 -142
- tradedangerous/templates/TradeDangerous.sql +6 -6
- tradedangerous/tradecalc.py +1227 -1109
- tradedangerous/tradedb.py +533 -384
- tradedangerous/tradeenv.py +12 -1
- tradedangerous/version.py +1 -1
- {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.0.dist-info}/METADATA +6 -4
- {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.0.dist-info}/RECORD +33 -38
- {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.0.dist-info}/WHEEL +1 -1
- tradedangerous/commands/update_gui.py +0 -721
- tradedangerous/jsonprices.py +0 -254
- tradedangerous/plugins/edapi_plug.py +0 -1071
- tradedangerous/plugins/journal_plug.py +0 -537
- tradedangerous/plugins/netlog_plug.py +0 -316
- {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.0.dist-info}/entry_points.txt +0 -0
- {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.0.dist-info/licenses}/LICENSE +0 -0
- {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,497 +1,67 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
),
|
|
30
|
-
]
|
|
31
|
-
switches = [
|
|
32
|
-
MutuallyExclusiveGroup(
|
|
33
|
-
ParseArgument(
|
|
34
|
-
'--update', '-u',
|
|
35
|
-
help='Indicates you expect the entry to already exist.',
|
|
36
|
-
action='store_true',
|
|
37
|
-
),
|
|
38
|
-
ParseArgument(
|
|
39
|
-
'--remove', '-rm',
|
|
40
|
-
help='Indicates you want to remove an entry.',
|
|
41
|
-
action='store_true',
|
|
42
|
-
),
|
|
43
|
-
ParseArgument(
|
|
44
|
-
'--add', '-a',
|
|
45
|
-
help='Indicates you want to add a new station.',
|
|
46
|
-
action='store_true',
|
|
47
|
-
),
|
|
48
|
-
),
|
|
49
|
-
ParseArgument(
|
|
50
|
-
'--ls-from-star',
|
|
51
|
-
help='Number of light seconds between station and star.',
|
|
52
|
-
type=int,
|
|
53
|
-
dest='lsFromStar',
|
|
54
|
-
),
|
|
55
|
-
# Note: these are not the usual arguments, they're asking the
|
|
56
|
-
# user to assign rather than select values.
|
|
57
|
-
ParseArgument(
|
|
58
|
-
'--black-market', '--bm',
|
|
59
|
-
help='Does the station have a black market (Y or N) or ? if unknown.',
|
|
60
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
61
|
-
dest='blackMarket',
|
|
62
|
-
),
|
|
63
|
-
ParseArgument(
|
|
64
|
-
'--market',
|
|
65
|
-
help='Does the station have a commodities market (Y or N), ? for unknown.',
|
|
66
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
67
|
-
),
|
|
68
|
-
ParseArgument(
|
|
69
|
-
'--shipyard',
|
|
70
|
-
help='Does the station have a shipyard (Y or N) or ? if unknown.',
|
|
71
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
72
|
-
),
|
|
73
|
-
ParseArgument(
|
|
74
|
-
'--pad-size',
|
|
75
|
-
help='Maximum supported pad size (S, M, or L) or ? if unknown.',
|
|
76
|
-
choices=['S', 's', 'M', 'm', 'L', 'l', '?'],
|
|
77
|
-
dest='padSize',
|
|
78
|
-
),
|
|
79
|
-
ParseArgument(
|
|
80
|
-
'--outfitting',
|
|
81
|
-
help='Does the station provide outfitting (Y or N) or ? if unknown.',
|
|
82
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
83
|
-
),
|
|
84
|
-
ParseArgument(
|
|
85
|
-
'--rearm', '--arm',
|
|
86
|
-
help='Does the station provide rearming (Y or N) or ? if unknown.',
|
|
87
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
88
|
-
),
|
|
89
|
-
ParseArgument(
|
|
90
|
-
'--refuel',
|
|
91
|
-
help='Does the station provide refueling (Y or N) or ? if unknown.',
|
|
92
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
93
|
-
),
|
|
94
|
-
ParseArgument(
|
|
95
|
-
'--repair',
|
|
96
|
-
help='Does the station provide repairs (Y or N) or ? if unknown.',
|
|
97
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
98
|
-
),
|
|
99
|
-
ParseArgument(
|
|
100
|
-
'--planetary',
|
|
101
|
-
help='Is the station on a planet (Y or N) or ? if unknown.',
|
|
102
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
103
|
-
),
|
|
1
|
+
# tradedangerous/commands/station_cmd.py — DEPRECATED (no-op)
|
|
2
|
+
# This command no longer edits station records directly.
|
|
3
|
+
#
|
|
4
|
+
# How to maintain station data going forward:
|
|
5
|
+
# • Import authoritative data via: trade import -P spansh | trade import -P eddblink
|
|
6
|
+
# • Solo/offline players (manual capture via EDMC plugin):
|
|
7
|
+
# TradeDangerous DB-Update for EDMC → https://github.com/bgol/UpdateTD
|
|
8
|
+
#
|
|
9
|
+
# To inspect a station’s data, use read-only commands like:
|
|
10
|
+
# trade station <name> ← (legacy pattern; now deprecated)
|
|
11
|
+
# trade local --near "<system>" (discoverability)
|
|
12
|
+
# trade market --origin "<station>" (market view)
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
from .parsing import ParseArgument
|
|
16
|
+
|
|
17
|
+
# ---- Command metadata ----
|
|
18
|
+
help = "DEPRECATED: no longer used. See deprecation banner when run."
|
|
19
|
+
name = "station"
|
|
20
|
+
epilog = None
|
|
21
|
+
acceptUnknown = True
|
|
22
|
+
|
|
23
|
+
# No DB access is needed for this no-op command.
|
|
24
|
+
wantsTradeDB = False
|
|
25
|
+
usesTradeData = False
|
|
26
|
+
|
|
27
|
+
# Accept ANY number of positional args and ignore them (prevents parser errors).
|
|
28
|
+
arguments = (
|
|
104
29
|
ParseArgument(
|
|
105
|
-
'
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
109
|
-
),
|
|
110
|
-
ParseArgument(
|
|
111
|
-
'--odyssey', '--od',
|
|
112
|
-
help='Is the station an Odyssey Settlement (Y or N) or ? if unknown.',
|
|
113
|
-
choices=['Y', 'y', 'N', 'n', '?'],
|
|
114
|
-
),
|
|
115
|
-
ParseArgument(
|
|
116
|
-
'--confirm',
|
|
117
|
-
help='For confirmation suspicious looking station names.',
|
|
118
|
-
metavar='CONFIRMATION CODE',
|
|
30
|
+
'args',
|
|
31
|
+
help="(deprecated) ignored",
|
|
32
|
+
nargs='*',
|
|
119
33
|
type=str,
|
|
120
34
|
),
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
35
|
+
)
|
|
36
|
+
# No switches; unknown switches will still be rejected by the global parser.
|
|
37
|
+
switches = tuple()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _banner() -> str:
|
|
41
|
+
return (
|
|
42
|
+
"\n"
|
|
43
|
+
"=== DEPRECATION NOTICE: station ====================================\n"
|
|
44
|
+
"This command no longer edits station records and does not modify the DB.\n"
|
|
45
|
+
"• Import station data via: trade import -P eddblink | -P spansh\n"
|
|
46
|
+
"• Solo/offline capture via EDMC plugin:\n"
|
|
47
|
+
" TradeDangerous DB-Update → https://github.com/bgol/UpdateTD\n"
|
|
48
|
+
"=====================================================================\n"
|
|
126
49
|
)
|
|
127
|
-
]
|
|
128
50
|
|
|
129
|
-
######################################################################
|
|
130
|
-
# Helpers
|
|
131
51
|
|
|
132
|
-
def
|
|
52
|
+
def run(results, cmdenv, tdb=None):
|
|
133
53
|
"""
|
|
134
|
-
|
|
54
|
+
No-op implementation: print banner and exit immediately.
|
|
55
|
+
All arguments/switches are ignored by design.
|
|
135
56
|
"""
|
|
136
|
-
|
|
137
|
-
for cand in candidates:
|
|
138
|
-
for character in cand:
|
|
139
|
-
checksum <<= 4
|
|
140
|
-
checksum += ord(character)
|
|
141
|
-
|
|
142
|
-
# python integers don't overflow, so we only need
|
|
143
|
-
# to modulo at the end of the checksum.
|
|
144
|
-
checksum %= 65521 # arbitrary prime < 2^32
|
|
145
|
-
|
|
146
|
-
return hex(checksum).upper()[2:]
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
def checkStationDoesNotExist(tdb, cmdenv, system, stationName):
|
|
150
|
-
if not system.stations:
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
upperName = stationName.upper()
|
|
154
|
-
similarities = set()
|
|
57
|
+
banner = _banner()
|
|
155
58
|
try:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
"Station \"{}\" "
|
|
160
|
-
"in system \"{}\" "
|
|
161
|
-
"already exists.".format(
|
|
162
|
-
stationName, system.name(),
|
|
163
|
-
))
|
|
164
|
-
similarities.add(station.dbname.upper())
|
|
165
|
-
except LookupError:
|
|
166
|
-
pass
|
|
167
|
-
except AmbiguityError as e:
|
|
168
|
-
for cand in e.anyMatch:
|
|
169
|
-
similarities.add(e.key(cand).upper())
|
|
170
|
-
|
|
171
|
-
# Check to see if there are stations with somewhat
|
|
172
|
-
# similar names, but allow the user to get around
|
|
173
|
-
# cases where difflib matches 'X Port' to 'Y Port'.
|
|
174
|
-
stationNames = [
|
|
175
|
-
stn.dbname.upper()
|
|
176
|
-
for stn in system.stations
|
|
177
|
-
]
|
|
178
|
-
cmdenv.DEBUG0("Comparing {} to {}".format(
|
|
179
|
-
upperName, list(stationNames),
|
|
180
|
-
))
|
|
181
|
-
candidates = difflib.get_close_matches(
|
|
182
|
-
upperName, stationNames, cutoff=0.6,
|
|
183
|
-
)
|
|
184
|
-
for cand in candidates:
|
|
185
|
-
similarities.add(cand)
|
|
186
|
-
|
|
187
|
-
if not similarities:
|
|
188
|
-
return
|
|
189
|
-
|
|
190
|
-
confCode = makeConfirmationCode(system.ID, similarities)
|
|
191
|
-
|
|
192
|
-
if not cmdenv.confirm:
|
|
193
|
-
raise CommandLineError(
|
|
194
|
-
"\"{}\" contains similar station names:\n"
|
|
195
|
-
" {}\n"
|
|
196
|
-
"\n"
|
|
197
|
-
"If you want to add this station anyway, re-run the "
|
|
198
|
-
"command and add:\n"
|
|
199
|
-
" --conf {}".format(
|
|
200
|
-
system.name(),
|
|
201
|
-
', '.join(candidates),
|
|
202
|
-
confCode
|
|
203
|
-
))
|
|
204
|
-
|
|
205
|
-
if cmdenv.confirm.upper() != confCode:
|
|
206
|
-
raise CommandLineError(
|
|
207
|
-
"Wrong confirmation code."
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
cmdenv.NOTE("Confirmation code accepted.")
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def checkSystemAndStation(tdb, cmdenv):
|
|
214
|
-
# In add mode, the user has to be more specific.
|
|
215
|
-
stnName = ' '.join(cmdenv.station).strip()
|
|
216
|
-
|
|
217
|
-
if not cmdenv.add:
|
|
218
|
-
try:
|
|
219
|
-
station = tdb.lookupPlace(stnName)
|
|
220
|
-
except LookupError:
|
|
221
|
-
raise CommandLineError("Unrecognized Station: {}".format(
|
|
222
|
-
cmdenv.station
|
|
223
|
-
))
|
|
224
|
-
if not isinstance(station, Station):
|
|
225
|
-
raise CommandLineError(
|
|
226
|
-
"Expecting a STATION, got {}".format(stnName)
|
|
227
|
-
)
|
|
228
|
-
cmdenv.system = station.system.name()
|
|
229
|
-
cmdenv.station = station.dbname
|
|
230
|
-
|
|
231
|
-
return station.system, station
|
|
232
|
-
|
|
233
|
-
# Clean up the station name and potentially lift the system
|
|
234
|
-
# name out of it.
|
|
235
|
-
stnName = re.sub(r" +", " ", stnName)
|
|
236
|
-
stnName = re.sub(r"[ /]*/[ /]*", "/", stnName)
|
|
237
|
-
while stnName.startswith('/'):
|
|
238
|
-
stnName = stnName[1:]
|
|
239
|
-
slashPos = stnName.find('/')
|
|
240
|
-
if slashPos > 0:
|
|
241
|
-
sysName, stnName = stnName[:slashPos], stnName[slashPos+1:]
|
|
242
|
-
sysName = sysName.upper()
|
|
243
|
-
else:
|
|
244
|
-
sysName = None
|
|
245
|
-
|
|
246
|
-
if not stnName:
|
|
247
|
-
raise CommandLineError("Invalid station name: {stnName}")
|
|
248
|
-
|
|
249
|
-
if not sysName:
|
|
250
|
-
raise CommandLineError("No system name specified")
|
|
251
|
-
|
|
252
|
-
cmdenv.system, cmdenv.station = sysName, utils.titleFixup(stnName)
|
|
253
|
-
try:
|
|
254
|
-
system = tdb.lookupSystem(sysName)
|
|
255
|
-
except LookupError:
|
|
256
|
-
raise CommandLineError(
|
|
257
|
-
"Unknown SYSTEM name: \"{}\"".format(
|
|
258
|
-
sysName
|
|
259
|
-
))
|
|
260
|
-
|
|
261
|
-
# check the station does not exist
|
|
262
|
-
checkStationDoesNotExist(tdb, cmdenv, system, stnName)
|
|
263
|
-
|
|
264
|
-
return system, None
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def addStation(tdb, cmdenv, system, stationName):
|
|
268
|
-
return tdb.addLocalStation(
|
|
269
|
-
system=system,
|
|
270
|
-
name=stationName,
|
|
271
|
-
lsFromStar=cmdenv.lsFromStar or 0,
|
|
272
|
-
market=cmdenv.market or '?',
|
|
273
|
-
blackMarket=cmdenv.blackMarket or '?',
|
|
274
|
-
shipyard=cmdenv.shipyard or '?',
|
|
275
|
-
outfitting=cmdenv.outfitting or '?',
|
|
276
|
-
rearm=cmdenv.rearm or '?',
|
|
277
|
-
refuel=cmdenv.refuel or '?',
|
|
278
|
-
repair=cmdenv.repair or '?',
|
|
279
|
-
maxPadSize=cmdenv.padSize or '?',
|
|
280
|
-
planetary=cmdenv.planetary or '?',
|
|
281
|
-
fleet=cmdenv.fleet or '?',
|
|
282
|
-
odyssey=cmdenv.odyssey or '?',
|
|
283
|
-
commit=True,
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
def updateStation(tdb, cmdenv, station):
|
|
288
|
-
return tdb.updateLocalStation(
|
|
289
|
-
station=station,
|
|
290
|
-
lsFromStar=cmdenv.lsFromStar,
|
|
291
|
-
market=cmdenv.market,
|
|
292
|
-
blackMarket=cmdenv.blackMarket,
|
|
293
|
-
shipyard=cmdenv.shipyard,
|
|
294
|
-
outfitting=cmdenv.outfitting,
|
|
295
|
-
rearm=cmdenv.rearm,
|
|
296
|
-
refuel=cmdenv.refuel,
|
|
297
|
-
repair=cmdenv.repair,
|
|
298
|
-
maxPadSize=cmdenv.padSize,
|
|
299
|
-
planetary=cmdenv.planetary,
|
|
300
|
-
fleet=cmdenv.fleet,
|
|
301
|
-
odyssey=cmdenv.odyssey,
|
|
302
|
-
force=True,
|
|
303
|
-
commit=True,
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def removeStation(tdb, cmdenv, station):
|
|
308
|
-
db = tdb.getDB()
|
|
309
|
-
db.execute("""
|
|
310
|
-
DELETE FROM Station WHERE station_id = ?
|
|
311
|
-
""", [station.ID])
|
|
312
|
-
db.commit()
|
|
313
|
-
cmdenv.NOTE("{} (#{}) removed from {} database.",
|
|
314
|
-
station.name(), station.ID, tdb.dbPath)
|
|
315
|
-
cmdenv.stationItemCount = station.itemCount
|
|
316
|
-
return True
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
def checkResultAndExportStations(tdb, cmdenv, result):
|
|
320
|
-
if not result:
|
|
321
|
-
cmdenv.NOTE("No changes.")
|
|
322
|
-
return None
|
|
323
|
-
if cmdenv.noExport:
|
|
324
|
-
cmdenv.DEBUG0("no-export set, not exporting stations")
|
|
325
|
-
return None
|
|
326
|
-
|
|
327
|
-
lines, csvPath = csvexport.exportTableToFile(tdb, cmdenv, "Station")
|
|
328
|
-
cmdenv.NOTE("{} updated.", csvPath)
|
|
329
|
-
|
|
330
|
-
if cmdenv.remove:
|
|
331
|
-
if cmdenv.stationItemCount:
|
|
332
|
-
cmdenv.NOTE("Station had items, regenerating .prices file")
|
|
333
|
-
cache.regeneratePricesFile(tdb, cmdenv)
|
|
334
|
-
|
|
59
|
+
cmdenv.NOTE("{}", banner)
|
|
60
|
+
except Exception:
|
|
61
|
+
print(banner)
|
|
335
62
|
return None
|
|
336
63
|
|
|
337
64
|
|
|
338
|
-
|
|
339
|
-
#
|
|
340
|
-
|
|
341
|
-
def run(results, cmdenv, tdb):
|
|
342
|
-
if cmdenv.lsFromStar and cmdenv.lsFromStar < 0:
|
|
343
|
-
raise CommandLineError("Invalid (negative) --ls option")
|
|
344
|
-
|
|
345
|
-
system, station = checkSystemAndStation(tdb, cmdenv)
|
|
346
|
-
|
|
347
|
-
stationName = cmdenv.station
|
|
348
|
-
|
|
349
|
-
if cmdenv.add:
|
|
350
|
-
result = addStation(tdb, cmdenv, system, stationName)
|
|
351
|
-
return checkResultAndExportStations(tdb, cmdenv, result)
|
|
352
|
-
elif cmdenv.update:
|
|
353
|
-
result = updateStation(tdb, cmdenv, station)
|
|
354
|
-
return checkResultAndExportStations(tdb, cmdenv, result)
|
|
355
|
-
elif cmdenv.remove:
|
|
356
|
-
result = removeStation(tdb, cmdenv, station)
|
|
357
|
-
return checkResultAndExportStations(tdb, cmdenv, result)
|
|
358
|
-
|
|
359
|
-
# Otherwise, it's just a query
|
|
360
|
-
results.summary = ResultRow()
|
|
361
|
-
results.summary.system = station.system
|
|
362
|
-
results.summary.station = station
|
|
363
|
-
|
|
364
|
-
avgSell = results.summary.avgSelling = tdb.getAverageSelling()
|
|
365
|
-
avgBuy = results.summary.avgBuying = tdb.getAverageBuying()
|
|
366
|
-
|
|
367
|
-
class ItemTrade:
|
|
368
|
-
def __init__(self, ID, price, avgAgainst):
|
|
369
|
-
self.ID, self.item = ID, tdb.itemByID[ID]
|
|
370
|
-
self.price = int(price)
|
|
371
|
-
self.avgTrade = avgAgainst.get(ID, 0)
|
|
372
|
-
|
|
373
|
-
# Look up all selling and buying by the station
|
|
374
|
-
selling, buying = [], []
|
|
375
|
-
cur = tdb.query("""
|
|
376
|
-
SELECT item_id, demand_price, supply_price
|
|
377
|
-
FROM StationItem
|
|
378
|
-
WHERE station_id = ?
|
|
379
|
-
AND (demand_price > 10 or supply_price > 10)
|
|
380
|
-
""", [station.ID])
|
|
381
|
-
for ID, demand_price, supply_price in cur:
|
|
382
|
-
if demand_price > 10 and avgSell.get(ID, 0) > 10:
|
|
383
|
-
buying.append(ItemTrade(ID, demand_price, avgSell))
|
|
384
|
-
if supply_price > 10 and avgBuy.get(ID, 0) > 10:
|
|
385
|
-
selling.append(ItemTrade(ID, supply_price, avgBuy))
|
|
386
|
-
selling.sort(
|
|
387
|
-
key=lambda item: item.price - item.avgTrade,
|
|
388
|
-
)
|
|
389
|
-
results.summary.selling = selling[:5]
|
|
390
|
-
buying.sort(
|
|
391
|
-
key=lambda item: item.avgTrade - item.price,
|
|
392
|
-
)
|
|
393
|
-
results.summary.buying = buying[:5]
|
|
394
|
-
|
|
395
|
-
return results
|
|
396
|
-
|
|
397
|
-
def render(results, cmdenv, tdb):
|
|
398
|
-
system, station = results.summary.system, results.summary.station
|
|
399
|
-
|
|
400
|
-
if cmdenv.detail:
|
|
401
|
-
sysDetail = "(#{} @ {},{},{})".format(
|
|
402
|
-
system.ID, system.posX, system.posY, system.posZ
|
|
403
|
-
)
|
|
404
|
-
else:
|
|
405
|
-
sysDetail = "(#{})".format(system.ID)
|
|
406
|
-
|
|
407
|
-
print("Station Data:")
|
|
408
|
-
print("System....:", system.name(), sysDetail)
|
|
409
|
-
print("Station...:", station.dbname, "(#{})".format(station.ID))
|
|
410
|
-
|
|
411
|
-
if cmdenv.detail:
|
|
412
|
-
siblings = ", ".join(
|
|
413
|
-
stn.dbname
|
|
414
|
-
for stn in system.stations
|
|
415
|
-
if stn is not station
|
|
416
|
-
)
|
|
417
|
-
if siblings:
|
|
418
|
-
print("Also Here.:", siblings)
|
|
419
|
-
|
|
420
|
-
ls = station.distFromStar()
|
|
421
|
-
if cmdenv.detail and ls == '?':
|
|
422
|
-
ls = '0 [unknown]'
|
|
423
|
-
print("Stn/Ls....:", ls)
|
|
424
|
-
|
|
425
|
-
def _detail(value, source):
|
|
426
|
-
detail = source[value]
|
|
427
|
-
if cmdenv.detail and detail == '?':
|
|
428
|
-
detail += ' [unknown]'
|
|
429
|
-
return detail
|
|
430
|
-
print("Pad Size..:", _detail(station.maxPadSize, TradeDB.padSizes))
|
|
431
|
-
print("Market....:", _detail(station.market, TradeDB.marketStates))
|
|
432
|
-
print("B/Market..:", _detail(station.blackMarket, TradeDB.marketStates))
|
|
433
|
-
print("Shipyard..:", _detail(station.shipyard, TradeDB.marketStates))
|
|
434
|
-
print("Outfitting:", _detail(station.outfitting, TradeDB.marketStates))
|
|
435
|
-
print("Rearm.....:", _detail(station.rearm, TradeDB.marketStates))
|
|
436
|
-
print("Refuel....:", _detail(station.refuel, TradeDB.marketStates))
|
|
437
|
-
print("Repair....:", _detail(station.repair, TradeDB.marketStates))
|
|
438
|
-
print("Planetary.:", _detail(station.planetary, TradeDB.planetStates))
|
|
439
|
-
print("Fleet.....:", _detail(station.fleet, TradeDB.fleetStates))
|
|
440
|
-
print("Odyssey...:", _detail(station.odyssey, TradeDB.odysseyStates))
|
|
441
|
-
print("Prices....:", station.itemCount or 'None')
|
|
442
|
-
|
|
443
|
-
if station.itemCount == 0:
|
|
444
|
-
return
|
|
445
|
-
|
|
446
|
-
newest, oldest = tdb.query("""
|
|
447
|
-
SELECT JULIANDAY('NOW') - JULIANDAY(MAX(si.modified)),
|
|
448
|
-
JULIANDAY('NOW') - JULIANDAY(MIN(si.modified))
|
|
449
|
-
FROM StationItem si
|
|
450
|
-
WHERE station_id = ?
|
|
451
|
-
""", [station.ID]).fetchone()
|
|
452
|
-
if newest or oldest:
|
|
453
|
-
# less than a quarter hour difference? ignore?
|
|
454
|
-
if abs(newest - oldest) < (1 / (24 * 4)):
|
|
455
|
-
pricesAge = "{:.2f} days".format(oldest)
|
|
456
|
-
else:
|
|
457
|
-
pricesAge = "{:.2f}-{:.2f} days".format(newest, oldest)
|
|
458
|
-
else:
|
|
459
|
-
pricesAge = "[n/a]"
|
|
460
|
-
|
|
461
|
-
print("Price Age.:", pricesAge)
|
|
462
|
-
|
|
463
|
-
def makeBest(rows, explanation, alt, maxLen, starFn):
|
|
464
|
-
if not rows:
|
|
465
|
-
return "[n/a]"
|
|
466
|
-
best = []
|
|
467
|
-
for irow in rows:
|
|
468
|
-
star = '*' if starFn(irow.price, irow.avgTrade) else ''
|
|
469
|
-
best.append([irow, star])
|
|
470
|
-
|
|
471
|
-
if not cmdenv.detail:
|
|
472
|
-
return ', '.join(irow[0].item.name() + irow[1] for irow in best)
|
|
473
|
-
|
|
474
|
-
bestText = "("+explanation+")"
|
|
475
|
-
for irow in best:
|
|
476
|
-
bestText += "\n {:<{len}} @ {:7n}cr (Avg {} {:7n}cr)".format(
|
|
477
|
-
irow[0].item.name(cmdenv.detail) + irow[1],
|
|
478
|
-
irow[0].price,
|
|
479
|
-
alt,
|
|
480
|
-
irow[0].avgTrade,
|
|
481
|
-
len=maxLen + 1,
|
|
482
|
-
)
|
|
483
|
-
return bestText
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
longestNameLen = max(
|
|
487
|
-
max_len(results.summary.selling, key=lambda row: row.item.name(cmdenv.detail)),
|
|
488
|
-
max_len(results.summary.buying, key=lambda row: row.item.name(cmdenv.detail)),
|
|
489
|
-
)
|
|
490
|
-
print("Best Buy..:", makeBest(
|
|
491
|
-
results.summary.selling, "Buy from this station", "Sell", longestNameLen,
|
|
492
|
-
starFn=lambda price, avgCr: price <= (avgCr * 0.9),
|
|
493
|
-
))
|
|
494
|
-
print("Best Sale.:", makeBest(
|
|
495
|
-
results.summary.buying, "Sell to this station", "Cost", longestNameLen,
|
|
496
|
-
starFn=lambda price, avgCr: price >= (avgCr * 1.1),
|
|
497
|
-
))
|
|
65
|
+
def render(results, cmdenv, tdb=None):
|
|
66
|
+
# No output beyond the banner emitted in run().
|
|
67
|
+
return
|