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
|
@@ -7,6 +7,7 @@ from .parsing import (
|
|
|
7
7
|
)
|
|
8
8
|
from ..tradedb import TradeDB, System, Station
|
|
9
9
|
from ..formatting import RowFormat
|
|
10
|
+
from sqlalchemy import text
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
######################################################################
|
|
@@ -81,6 +82,14 @@ switches = [
|
|
|
81
82
|
# Perform query and populate result set
|
|
82
83
|
|
|
83
84
|
def run(results, cmdenv, tdb: TradeDB):
|
|
85
|
+
"""
|
|
86
|
+
Backend-neutral implementation:
|
|
87
|
+
- Use SQLAlchemy text() with NAMED binds (':param') instead of '?'.
|
|
88
|
+
- Eagerly materialize rows via engine.connect().execute(...).fetchall()
|
|
89
|
+
to avoid closed-cursor errors when iterating later.
|
|
90
|
+
- Preserve all existing filters, sorting, and output fields.
|
|
91
|
+
"""
|
|
92
|
+
|
|
84
93
|
if cmdenv.lt and cmdenv.gt:
|
|
85
94
|
if cmdenv.lt <= cmdenv.gt:
|
|
86
95
|
raise CommandLineError("--gt must be lower than --lt")
|
|
@@ -96,37 +105,54 @@ def run(results, cmdenv, tdb: TradeDB):
|
|
|
96
105
|
results.summary.avoidSystems = avoidSystems
|
|
97
106
|
results.summary.avoidStations = avoidStations
|
|
98
107
|
|
|
108
|
+
# Detail: average demand price for this item (portable named bind)
|
|
99
109
|
if cmdenv.detail:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"(item_id = {} AND demand_price > 0)".format(item.ID),
|
|
111
|
-
]
|
|
112
|
-
columns = [
|
|
113
|
-
'si.station_id',
|
|
114
|
-
'si.demand_price',
|
|
115
|
-
'si.demand_units',
|
|
116
|
-
]
|
|
117
|
-
bindValues = []
|
|
110
|
+
with tdb.engine.connect() as conn:
|
|
111
|
+
avg_val = conn.execute(
|
|
112
|
+
text("""
|
|
113
|
+
SELECT AVG(si.demand_price)
|
|
114
|
+
FROM StationItem AS si
|
|
115
|
+
WHERE si.item_id = :item_id AND si.demand_price > 0
|
|
116
|
+
"""),
|
|
117
|
+
{"item_id": item.ID},
|
|
118
|
+
).scalar()
|
|
119
|
+
results.summary.avg = int(avg_val or 0)
|
|
118
120
|
|
|
121
|
+
# Build the main query with named binds
|
|
122
|
+
columns = "si.station_id, si.demand_price, si.demand_units"
|
|
123
|
+
where = ["si.item_id = :item_id", "si.demand_price > 0"]
|
|
124
|
+
params = {"item_id": item.ID}
|
|
125
|
+
|
|
119
126
|
if cmdenv.demand:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
where.append("si.demand_units >= :demand")
|
|
128
|
+
params["demand"] = cmdenv.demand
|
|
123
129
|
if cmdenv.lt:
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
where.append("si.demand_price < :lt")
|
|
131
|
+
params["lt"] = cmdenv.lt
|
|
126
132
|
if cmdenv.gt:
|
|
127
|
-
|
|
128
|
-
|
|
133
|
+
where.append("si.demand_price > :gt")
|
|
134
|
+
params["gt"] = cmdenv.gt
|
|
135
|
+
|
|
136
|
+
stmt = f"""
|
|
137
|
+
SELECT DISTINCT {columns}
|
|
138
|
+
FROM StationItem AS si
|
|
139
|
+
WHERE {' AND '.join(where)}
|
|
140
|
+
"""
|
|
141
|
+
cmdenv.DEBUG0('SQL: {} ; params={}', stmt, params)
|
|
142
|
+
|
|
143
|
+
# Execute and eagerly fetch rows
|
|
144
|
+
with tdb.engine.connect() as conn:
|
|
145
|
+
cur_rows = conn.execute(text(stmt), params).fetchall()
|
|
129
146
|
|
|
147
|
+
stationByID = tdb.stationByID
|
|
148
|
+
padSize = cmdenv.padSize
|
|
149
|
+
planetary = cmdenv.planetary
|
|
150
|
+
fleet = cmdenv.fleet
|
|
151
|
+
odyssey = cmdenv.odyssey
|
|
152
|
+
wantNoPlanet = cmdenv.noPlanet
|
|
153
|
+
wantBlackMarket = cmdenv.blackMarket
|
|
154
|
+
|
|
155
|
+
# System-based search
|
|
130
156
|
nearSystem = cmdenv.nearSystem
|
|
131
157
|
if nearSystem:
|
|
132
158
|
maxLy = cmdenv.maxLyPer or tdb.maxSystemLinkLy
|
|
@@ -136,24 +162,7 @@ def run(results, cmdenv, tdb: TradeDB):
|
|
|
136
162
|
else:
|
|
137
163
|
distanceFn = None
|
|
138
164
|
|
|
139
|
-
|
|
140
|
-
stmt = """SELECT DISTINCT {columns} FROM {tables} WHERE {where}""".format(
|
|
141
|
-
columns=','.join(columns),
|
|
142
|
-
tables=tables,
|
|
143
|
-
where=whereClause
|
|
144
|
-
)
|
|
145
|
-
cmdenv.DEBUG0('SQL: {}', stmt)
|
|
146
|
-
cur = tdb.query(stmt, bindValues)
|
|
147
|
-
|
|
148
|
-
stationByID = tdb.stationByID
|
|
149
|
-
padSize = cmdenv.padSize
|
|
150
|
-
planetary = cmdenv.planetary
|
|
151
|
-
fleet = cmdenv.fleet
|
|
152
|
-
odyssey = cmdenv.odyssey
|
|
153
|
-
wantNoPlanet = cmdenv.noPlanet
|
|
154
|
-
wantBlackMarket = cmdenv.blackMarket
|
|
155
|
-
|
|
156
|
-
for (stationID, priceCr, demand) in cur:
|
|
165
|
+
for (stationID, priceCr, demand) in cur_rows:
|
|
157
166
|
station = stationByID[stationID]
|
|
158
167
|
if padSize and not station.checkPadSize(padSize):
|
|
159
168
|
continue
|
|
@@ -187,8 +196,6 @@ def run(results, cmdenv, tdb: TradeDB):
|
|
|
187
196
|
row.age = station.itemDataAgeStr
|
|
188
197
|
results.rows.append(row)
|
|
189
198
|
|
|
190
|
-
cur.close()
|
|
191
|
-
|
|
192
199
|
if not results.rows:
|
|
193
200
|
raise NoDataError("No available items found")
|
|
194
201
|
|
|
@@ -1,244 +1,59 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
# tradedangerous/commands/shipvendor_cmd.py — DEPRECATED (no-op)
|
|
2
|
+
# This command no longer maintains ship lists directly.
|
|
3
|
+
# Guidance:
|
|
4
|
+
# • Import authoritative data via: trade import -P spansh | trade import -P eddblink
|
|
5
|
+
# • Search for ships via: trade buy --near "<place>" --ly N "<ship>"
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
from .parsing import ParseArgument # to swallow arbitrary positional args
|
|
9
|
+
|
|
10
|
+
# ---- Command metadata ----
|
|
11
|
+
help = "DEPRECATED: no longer used. See deprecation banner when run."
|
|
12
|
+
name = "shipvendor"
|
|
13
|
+
epilog = None
|
|
14
|
+
acceptUnknown = True
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
# No DB access needed.
|
|
17
|
+
wantsTradeDB = False
|
|
18
|
+
usesTradeData = False
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
epilog = None
|
|
20
|
-
arguments = [
|
|
20
|
+
# Accept ANY number of positional args and ignore them (prevents parser errors).
|
|
21
|
+
arguments = (
|
|
21
22
|
ParseArgument(
|
|
22
|
-
'
|
|
23
|
-
help
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
type = str,
|
|
27
|
-
),
|
|
28
|
-
ParseArgument(
|
|
29
|
-
'ship',
|
|
30
|
-
help = 'Comma or space separated list of ship names.',
|
|
31
|
-
type = str,
|
|
32
|
-
nargs = '*',
|
|
33
|
-
),
|
|
34
|
-
]
|
|
35
|
-
switches = [
|
|
36
|
-
MutuallyExclusiveGroup(
|
|
37
|
-
ParseArgument(
|
|
38
|
-
'--remove', '-rm',
|
|
39
|
-
help = 'Indicates you want to remove an entry.',
|
|
40
|
-
action = 'store_true',
|
|
41
|
-
),
|
|
42
|
-
ParseArgument(
|
|
43
|
-
'--add', '-a',
|
|
44
|
-
help = 'Indicates you want to add a new station.',
|
|
45
|
-
action = 'store_true',
|
|
46
|
-
),
|
|
47
|
-
ParseArgument(
|
|
48
|
-
'--name-sort',
|
|
49
|
-
help = 'Sort listed ships by name.',
|
|
50
|
-
action = 'store_true',
|
|
51
|
-
dest = 'nameSort',
|
|
52
|
-
),
|
|
23
|
+
'args',
|
|
24
|
+
help="(deprecated) ignored",
|
|
25
|
+
nargs='*',
|
|
26
|
+
type=str,
|
|
53
27
|
),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
db = tdb.getDB()
|
|
68
|
-
db.execute("""
|
|
69
|
-
INSERT INTO ShipVendor (
|
|
70
|
-
ship_id, station_id
|
|
71
|
-
) VALUES (
|
|
72
|
-
?, ?
|
|
73
|
-
)
|
|
74
|
-
""", [
|
|
75
|
-
ship.ID, station.ID
|
|
76
|
-
])
|
|
77
|
-
db.commit()
|
|
78
|
-
cmdenv.NOTE("At {} adding {}", station.name(), ship.name())
|
|
79
|
-
return ship
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def removeShipVendor(tdb, cmdenv, station, ship):
|
|
83
|
-
db = tdb.getDB()
|
|
84
|
-
db.execute("""
|
|
85
|
-
DELETE FROM ShipVendor WHERE ship_id = ? and station_id = ?
|
|
86
|
-
""", [ship.ID, station.ID])
|
|
87
|
-
db.commit()
|
|
88
|
-
cmdenv.NOTE("At {} removing {}", station.name(), ship.name())
|
|
89
|
-
return ship
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def maybeExportToCSV(tdb, cmdenv):
|
|
93
|
-
if cmdenv.noExport:
|
|
94
|
-
cmdenv.DEBUG0("no-export set, not exporting stations")
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
lines, csvPath = csvexport.exportTableToFile(tdb, cmdenv, "ShipVendor")
|
|
98
|
-
cmdenv.NOTE("{} updated.", csvPath)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def checkShipPresent(tdb, station, ship):
|
|
102
|
-
# Ask the database how many rows it sees claiming
|
|
103
|
-
# this ship is sold at that station. The value will
|
|
104
|
-
# be zero if we don't have an entry, otherwise it
|
|
105
|
-
# will be some positive number.
|
|
106
|
-
cur = tdb.query("""
|
|
107
|
-
SELECT COUNT(*)
|
|
108
|
-
FROM ShipVendor
|
|
109
|
-
WHERE ship_id = ? AND station_id = ?
|
|
110
|
-
""", [ship.ID, station.ID]
|
|
111
|
-
)
|
|
112
|
-
# Get the first result of the row and get the first column of that row
|
|
113
|
-
count = int(cur.fetchone()[0])
|
|
114
|
-
|
|
115
|
-
# Test if count > 0, if so, we'll return True, otherwise False
|
|
116
|
-
return (count > 0)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def listShipsPresent(tdb, cmdenv, station, results):
|
|
120
|
-
""" Populate results with a list of ships present at the given station """
|
|
121
|
-
cur = tdb.query("""
|
|
122
|
-
SELECT ship_id
|
|
123
|
-
FROM ShipVendor
|
|
124
|
-
WHERE station_id = ?
|
|
125
|
-
""", [station.ID]
|
|
28
|
+
)
|
|
29
|
+
# No switches; unknown switches will still be rejected by the global parser.
|
|
30
|
+
switches = tuple()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _banner() -> str:
|
|
34
|
+
return (
|
|
35
|
+
"\n"
|
|
36
|
+
"=== DEPRECATION NOTICE: shipvendor ==================================\n"
|
|
37
|
+
"This command is no longer used and does not modify the database.\n"
|
|
38
|
+
"• Import authoritative data with: trade import -P eddblink | -P spansh\n"
|
|
39
|
+
"• Search for ships using: trade buy --near \"<place>\" --ly N \"<ship>\"\n"
|
|
40
|
+
"======================================================================\n"
|
|
126
41
|
)
|
|
127
|
-
|
|
128
|
-
results.summary = ResultRow()
|
|
129
|
-
results.summary.station = station
|
|
130
|
-
ships = tdb.shipByID
|
|
131
|
-
addShip = results.rows.append
|
|
132
|
-
|
|
133
|
-
for (ship_id,) in cur:
|
|
134
|
-
ship = ships.get(ship_id, None)
|
|
135
|
-
if ship:
|
|
136
|
-
addShip(ResultRow(ship = ship))
|
|
137
|
-
|
|
138
|
-
if cmdenv.nameSort:
|
|
139
|
-
results.rows.sort(key = lambda row: row.ship.name())
|
|
140
|
-
else:
|
|
141
|
-
results.rows.sort(key = lambda row: row.ship.cost, reverse = True)
|
|
142
|
-
|
|
143
|
-
return results
|
|
144
|
-
|
|
145
|
-
######################################################################
|
|
146
|
-
# Perform query and populate result set
|
|
147
42
|
|
|
148
43
|
|
|
149
|
-
def run(results, cmdenv, tdb):
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
.format(station.name())
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
if cmdenv.add:
|
|
163
|
-
action = addShipVendor
|
|
164
|
-
elif cmdenv.remove:
|
|
165
|
-
action = removeShipVendor
|
|
166
|
-
else:
|
|
167
|
-
return listShipsPresent(tdb, cmdenv, station, results)
|
|
168
|
-
|
|
169
|
-
if not cmdenv.ship:
|
|
170
|
-
raise CommandLineError(
|
|
171
|
-
"No ship names specified."
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
cmdenv.NOTE("Using local database ({})", tdb.dbPath)
|
|
175
|
-
ships = {}
|
|
176
|
-
shipNames = chain.from_iterable(
|
|
177
|
-
name.split(",") for name in cmdenv.ship
|
|
178
|
-
)
|
|
179
|
-
for shipName in shipNames:
|
|
180
|
-
try:
|
|
181
|
-
ship = tdb.lookupShip(shipName)
|
|
182
|
-
except LookupError:
|
|
183
|
-
raise CommandLineError("Unrecognized Ship: {}".format(shipName))
|
|
184
|
-
|
|
185
|
-
# Lets see if that ship sails from the specified port.
|
|
186
|
-
shipPresent = checkShipPresent(tdb, station, ship)
|
|
187
|
-
if cmdenv.add:
|
|
188
|
-
if shipPresent:
|
|
189
|
-
cmdenv.DEBUG0("{} is already listed at {}",
|
|
190
|
-
ship.name(), station.name()
|
|
191
|
-
)
|
|
192
|
-
else:
|
|
193
|
-
ships[ship.ID] = ship
|
|
194
|
-
else:
|
|
195
|
-
if not shipPresent:
|
|
196
|
-
cmdenv.DEBUG0("{} is not listed at {}",
|
|
197
|
-
ship.name(), station.name()
|
|
198
|
-
)
|
|
199
|
-
else:
|
|
200
|
-
ships[ship.ID] = ship
|
|
201
|
-
|
|
202
|
-
if len(ships) == 0:
|
|
203
|
-
cmdenv.NOTE("Nothing to do.")
|
|
204
|
-
return None
|
|
205
|
-
|
|
206
|
-
# We've checked that everything should be good.
|
|
207
|
-
dataToExport = False
|
|
208
|
-
for ship in ships.values():
|
|
209
|
-
if action(tdb, cmdenv, station, ship):
|
|
210
|
-
dataToExport = True
|
|
211
|
-
|
|
212
|
-
cmdenv.DEBUG0("dataToExport = {}", dataToExport)
|
|
213
|
-
|
|
214
|
-
maybeExportToCSV(tdb, cmdenv)
|
|
215
|
-
|
|
44
|
+
def run(results, cmdenv, tdb=None):
|
|
45
|
+
"""
|
|
46
|
+
No-op implementation: print banner and exit immediately.
|
|
47
|
+
All arguments/switches are ignored by design.
|
|
48
|
+
"""
|
|
49
|
+
banner = _banner()
|
|
50
|
+
try:
|
|
51
|
+
cmdenv.NOTE("{}", banner)
|
|
52
|
+
except Exception:
|
|
53
|
+
print(banner)
|
|
216
54
|
return None
|
|
217
55
|
|
|
218
|
-
######################################################################
|
|
219
|
-
# Transform result set into output
|
|
220
|
-
|
|
221
56
|
|
|
222
|
-
def render(results, cmdenv, tdb):
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
"No ships available at {}"
|
|
226
|
-
.format(results.summary.station.name())
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
maxShipLen = max_len(results.rows, key = lambda row: row.ship.name())
|
|
230
|
-
|
|
231
|
-
rowFmt = RowFormat().append(
|
|
232
|
-
ColumnFormat("Ship", '<', maxShipLen,
|
|
233
|
-
key = lambda row: row.ship.name())
|
|
234
|
-
).append(
|
|
235
|
-
ColumnFormat("Cost", '>', 12, 'n',
|
|
236
|
-
key = lambda row: row.ship.cost)
|
|
237
|
-
)
|
|
238
|
-
|
|
239
|
-
if not cmdenv.quiet:
|
|
240
|
-
heading, underline = rowFmt.heading()
|
|
241
|
-
print(heading, underline, sep = '\n')
|
|
242
|
-
|
|
243
|
-
for row in results.rows:
|
|
244
|
-
print(rowFmt.format(row))
|
|
57
|
+
def render(results, cmdenv, tdb=None):
|
|
58
|
+
# No output beyond the banner emitted in run().
|
|
59
|
+
return
|