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
|
@@ -4,6 +4,8 @@ from .parsing import (
|
|
|
4
4
|
ParseArgument, MutuallyExclusiveGroup,
|
|
5
5
|
)
|
|
6
6
|
from ..formatting import RowFormat
|
|
7
|
+
from sqlalchemy import select, table, column
|
|
8
|
+
from sqlalchemy.orm import Session
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
######################################################################
|
|
@@ -50,35 +52,63 @@ def render_units(units, level):
|
|
|
50
52
|
|
|
51
53
|
|
|
52
54
|
def run(results, cmdenv, tdb):
|
|
55
|
+
# Lazy import to avoid any import-time tangles elsewhere.
|
|
56
|
+
from tradedangerous.db.utils import age_in_days
|
|
57
|
+
|
|
53
58
|
origin = cmdenv.startStation
|
|
54
59
|
if not origin.itemCount:
|
|
55
60
|
raise CommandLineError(
|
|
56
61
|
"No trade data available for {}".format(origin.name())
|
|
57
62
|
)
|
|
58
|
-
|
|
63
|
+
|
|
59
64
|
buying, selling = cmdenv.buying, cmdenv.selling
|
|
60
|
-
|
|
65
|
+
|
|
61
66
|
results.summary = ResultRow()
|
|
62
67
|
results.summary.origin = origin
|
|
63
68
|
results.summary.buying = cmdenv.buying
|
|
64
69
|
results.summary.selling = cmdenv.selling
|
|
65
|
-
|
|
70
|
+
|
|
71
|
+
# Precompute averages (unchanged)
|
|
66
72
|
tdb.getAverageSelling()
|
|
67
73
|
tdb.getAverageBuying()
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
|
|
75
|
+
# --- Backend-neutral query using SQLAlchemy Core + age_in_days ---
|
|
76
|
+
si = table(
|
|
77
|
+
"StationItem",
|
|
78
|
+
column("item_id"),
|
|
79
|
+
column("station_id"),
|
|
80
|
+
column("demand_price"),
|
|
81
|
+
column("demand_units"),
|
|
82
|
+
column("demand_level"),
|
|
83
|
+
column("supply_price"),
|
|
84
|
+
column("supply_units"),
|
|
85
|
+
column("supply_level"),
|
|
86
|
+
column("modified"),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Build session bound to current engine (needed by age_in_days)
|
|
90
|
+
session = Session(bind=tdb.engine)
|
|
91
|
+
|
|
92
|
+
stmt = (
|
|
93
|
+
select(
|
|
94
|
+
si.c.item_id,
|
|
95
|
+
si.c.demand_price, si.c.demand_units, si.c.demand_level,
|
|
96
|
+
si.c.supply_price, si.c.supply_units, si.c.supply_level,
|
|
97
|
+
age_in_days(session, si.c.modified).label("age_days"),
|
|
98
|
+
)
|
|
99
|
+
.where(si.c.station_id == origin.ID)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
rows = session.execute(stmt).fetchall()
|
|
103
|
+
session.close()
|
|
104
|
+
|
|
105
|
+
for r in rows:
|
|
106
|
+
it = iter(r)
|
|
79
107
|
item = tdb.itemByID[next(it)]
|
|
108
|
+
|
|
80
109
|
row = ResultRow()
|
|
81
110
|
row.item = item
|
|
111
|
+
|
|
82
112
|
row.buyCr = int(next(it) or 0)
|
|
83
113
|
row.avgBuy = tdb.avgBuying.get(item.ID, 0)
|
|
84
114
|
units, level = int(next(it) or 0), int(next(it) or 0)
|
|
@@ -89,6 +119,7 @@ def run(results, cmdenv, tdb):
|
|
|
89
119
|
hasBuy = (row.buyCr or units or level)
|
|
90
120
|
else:
|
|
91
121
|
hasBuy = False
|
|
122
|
+
|
|
92
123
|
row.sellCr = int(next(it) or 0)
|
|
93
124
|
row.avgSell = tdb.avgSelling.get(item.ID, 0)
|
|
94
125
|
units, level = int(next(it) or 0), int(next(it) or 0)
|
|
@@ -99,17 +130,19 @@ def run(results, cmdenv, tdb):
|
|
|
99
130
|
hasSell = (row.sellCr or units or level)
|
|
100
131
|
else:
|
|
101
132
|
hasSell = False
|
|
102
|
-
|
|
103
|
-
|
|
133
|
+
|
|
134
|
+
age_days = next(it)
|
|
135
|
+
row.age = float(age_days or 0.0)
|
|
136
|
+
|
|
104
137
|
if hasBuy or hasSell:
|
|
105
138
|
results.rows.append(row)
|
|
106
|
-
|
|
139
|
+
|
|
107
140
|
if not results.rows:
|
|
108
141
|
raise CommandLineError("No items found")
|
|
109
|
-
|
|
142
|
+
|
|
110
143
|
results.rows.sort(key=lambda row: row.item.dbname)
|
|
111
144
|
results.rows.sort(key=lambda row: row.item.category.dbname)
|
|
112
|
-
|
|
145
|
+
|
|
113
146
|
return results
|
|
114
147
|
|
|
115
148
|
#######################################################################
|
|
@@ -4,6 +4,8 @@ from .parsing import (
|
|
|
4
4
|
)
|
|
5
5
|
from ..tradedb import TradeDB
|
|
6
6
|
from ..tradeexcept import TradeException
|
|
7
|
+
from sqlalchemy import select, table, column, func, literal
|
|
8
|
+
from sqlalchemy.orm import Session
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
######################################################################
|
|
@@ -61,150 +63,161 @@ switches = [
|
|
|
61
63
|
# Perform query and populate result set
|
|
62
64
|
|
|
63
65
|
def run(results, cmdenv, tdb):
|
|
66
|
+
"""
|
|
67
|
+
Backend-neutral rework:
|
|
68
|
+
- Use SQLAlchemy Core to compute age and (optionally) distance².
|
|
69
|
+
- age: age_in_days(session, MAX(StationItem.modified)) AS age_days
|
|
70
|
+
- dist2: (sys.pos_x - x0)^2 + (sys.pos_y - y0)^2 + (sys.pos_z - z0)^2 (when --near)
|
|
71
|
+
- Materialize rows to avoid closed-cursor errors.
|
|
72
|
+
- Preserve downstream filters/sorting/limit exactly as before.
|
|
73
|
+
"""
|
|
64
74
|
from .commandenv import ResultRow
|
|
65
|
-
|
|
75
|
+
from tradedangerous.db.utils import age_in_days
|
|
76
|
+
|
|
66
77
|
cmdenv = results.cmdenv
|
|
67
78
|
tdb = cmdenv.tdb
|
|
68
|
-
|
|
79
|
+
|
|
69
80
|
results.summary = ResultRow()
|
|
70
81
|
results.limit = cmdenv.limit
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
|
|
83
|
+
# SQLAlchemy lightweight table defs
|
|
84
|
+
si = table(
|
|
85
|
+
"StationItem",
|
|
86
|
+
column("station_id"),
|
|
87
|
+
column("item_id"),
|
|
88
|
+
column("modified"),
|
|
89
|
+
)
|
|
90
|
+
stn = table(
|
|
91
|
+
"Station",
|
|
92
|
+
column("station_id"),
|
|
93
|
+
column("system_id"),
|
|
94
|
+
column("ls_from_star"),
|
|
95
|
+
)
|
|
96
|
+
sys_tbl = table(
|
|
97
|
+
"System",
|
|
98
|
+
column("system_id"),
|
|
99
|
+
column("pos_x"),
|
|
100
|
+
column("pos_y"),
|
|
101
|
+
column("pos_z"),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Build session bound to current engine (age_in_days needs the session)
|
|
105
|
+
session = Session(bind=tdb.engine)
|
|
106
|
+
|
|
107
|
+
# Base SELECT: station_id, ls_from_star, age_days
|
|
108
|
+
age_expr = age_in_days(session, func.max(si.c.modified)).label("age_days")
|
|
109
|
+
|
|
110
|
+
# Optional near-system distance²
|
|
88
111
|
nearSys = cmdenv.nearSystem
|
|
112
|
+
join_sys = False
|
|
89
113
|
if nearSys:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"sys.pos_x, sys.pos_y, sys.pos_z,"
|
|
95
|
-
"{}, {}, {}"
|
|
96
|
-
") AS d2".format(
|
|
97
|
-
nearSys.posX,
|
|
98
|
-
nearSys.posY,
|
|
99
|
-
nearSys.posZ,
|
|
100
|
-
))
|
|
101
|
-
joins.append("INNER JOIN System sys USING (system_id)")
|
|
102
|
-
wheres.append("""(
|
|
103
|
-
sys.pos_x BETWEEN {} and {}
|
|
104
|
-
AND sys.pos_y BETWEEN {} and {}
|
|
105
|
-
AND sys.pos_z BETWEEN {} and {}
|
|
106
|
-
)""".format(
|
|
107
|
-
nearSys.posX - maxLy,
|
|
108
|
-
nearSys.posX + maxLy,
|
|
109
|
-
nearSys.posY - maxLy,
|
|
110
|
-
nearSys.posY + maxLy,
|
|
111
|
-
nearSys.posZ - maxLy,
|
|
112
|
-
nearSys.posZ + maxLy,
|
|
113
|
-
))
|
|
114
|
-
havings.append("d2 <= {}".format(maxLy2))
|
|
114
|
+
dx = (sys_tbl.c.pos_x - literal(nearSys.posX))
|
|
115
|
+
dy = (sys_tbl.c.pos_y - literal(nearSys.posY))
|
|
116
|
+
dz = (sys_tbl.c.pos_z - literal(nearSys.posZ))
|
|
117
|
+
dist2_expr = (dx * dx + dy * dy + dz * dz).label("d2")
|
|
115
118
|
else:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
else:
|
|
133
|
-
haveStr = ''
|
|
134
|
-
|
|
135
|
-
stmt = """
|
|
136
|
-
SELECT {fields}
|
|
137
|
-
FROM StationItem as si
|
|
138
|
-
INNER JOIN Station stn USING (station_id)
|
|
139
|
-
{joins}
|
|
140
|
-
{wheres}
|
|
141
|
-
GROUP BY 1
|
|
142
|
-
{having}
|
|
143
|
-
ORDER BY 2 DESC
|
|
144
|
-
""".format(
|
|
145
|
-
fields=fieldStr,
|
|
146
|
-
joins=joinStr,
|
|
147
|
-
wheres=whereStr,
|
|
148
|
-
having=haveStr,
|
|
119
|
+
dist2_expr = literal(0.0).label("d2")
|
|
120
|
+
|
|
121
|
+
stmt = (
|
|
122
|
+
select(
|
|
123
|
+
si.c.station_id,
|
|
124
|
+
age_expr,
|
|
125
|
+
stn.c.ls_from_star,
|
|
126
|
+
dist2_expr,
|
|
127
|
+
)
|
|
128
|
+
.select_from(
|
|
129
|
+
si.join(stn, stn.c.station_id == si.c.station_id)
|
|
130
|
+
.join(sys_tbl, sys_tbl.c.system_id == stn.c.system_id) if nearSys
|
|
131
|
+
else si.join(stn, stn.c.station_id == si.c.station_id)
|
|
132
|
+
)
|
|
133
|
+
.group_by(si.c.station_id, stn.c.ls_from_star, dist2_expr)
|
|
134
|
+
.order_by(age_expr.desc())
|
|
149
135
|
)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
136
|
+
|
|
137
|
+
# Bounding box for near (keeps scan small, mirrors original)
|
|
138
|
+
if nearSys:
|
|
139
|
+
maxLy = cmdenv.maxLyPer or tdb.maxSystemLinkLy
|
|
140
|
+
# Bounding box predicate
|
|
141
|
+
stmt = stmt.where(
|
|
142
|
+
sys_tbl.c.pos_x.between(nearSys.posX - maxLy, nearSys.posX + maxLy),
|
|
143
|
+
sys_tbl.c.pos_y.between(nearSys.posY - maxLy, nearSys.posY + maxLy),
|
|
144
|
+
sys_tbl.c.pos_z.between(nearSys.posZ - maxLy, nearSys.posZ + maxLy),
|
|
145
|
+
)
|
|
146
|
+
# Radius filter: HAVING dist2 <= maxLy^2
|
|
147
|
+
stmt = stmt.having(dist2_expr <= (maxLy * maxLy))
|
|
148
|
+
|
|
149
|
+
# Min-age filter (apply to aggregated age of MAX(modified))
|
|
150
|
+
if cmdenv.minAge:
|
|
151
|
+
stmt = stmt.having(age_expr >= float(cmdenv.minAge))
|
|
152
|
+
|
|
153
|
+
# Execute and materialize rows
|
|
154
|
+
rows = session.execute(stmt).fetchall()
|
|
155
|
+
session.close()
|
|
156
|
+
|
|
157
|
+
# Downstream filters (unchanged)
|
|
153
158
|
padSize = cmdenv.padSize
|
|
154
159
|
planetary = cmdenv.planetary
|
|
155
160
|
fleet = cmdenv.fleet
|
|
156
161
|
odyssey = cmdenv.odyssey
|
|
157
162
|
noPlanet = cmdenv.noPlanet
|
|
158
163
|
mls = cmdenv.maxLs
|
|
159
|
-
|
|
160
|
-
for (stnID, age, ls, dist2) in
|
|
164
|
+
|
|
165
|
+
for (stnID, age, ls, dist2) in rows:
|
|
161
166
|
cmdenv.DEBUG2("{}:{}:{}", stnID, age, ls)
|
|
162
167
|
row = ResultRow()
|
|
163
168
|
row.station = tdb.stationByID[stnID]
|
|
164
|
-
row.age = age
|
|
165
|
-
if ls
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
169
|
+
row.age = float(age or 0.0)
|
|
170
|
+
row.ls = "{:n}".format(ls) if ls else "?"
|
|
171
|
+
row.dist = (float(dist2) ** 0.5) if dist2 else 0.0
|
|
172
|
+
|
|
173
|
+
if padSize and not row.station.checkPadSize(padSize):
|
|
174
|
+
continue
|
|
175
|
+
if planetary and not row.station.checkPlanetary(planetary):
|
|
176
|
+
continue
|
|
177
|
+
if fleet and not row.station.checkFleet(fleet):
|
|
178
|
+
continue
|
|
179
|
+
if odyssey and not row.station.checkOdyssey(odyssey):
|
|
180
|
+
continue
|
|
181
|
+
if noPlanet and row.station.planetary != 'N':
|
|
182
|
+
continue
|
|
183
|
+
if mls and row.station.lsFromStar > mls:
|
|
184
|
+
continue
|
|
185
|
+
|
|
186
|
+
results.rows.append(row)
|
|
187
|
+
|
|
188
|
+
# Route optimization and limiting (unchanged)
|
|
178
189
|
if cmdenv.route and len(results.rows) > 1:
|
|
179
|
-
def walk(
|
|
180
|
-
|
|
181
|
-
startNode =
|
|
182
|
-
openList = set(
|
|
190
|
+
def walk(start_idx, dist):
|
|
191
|
+
rows_ = results.rows
|
|
192
|
+
startNode = rows_[start_idx]
|
|
193
|
+
openList = set(rows_)
|
|
183
194
|
path = [startNode]
|
|
184
195
|
openList.remove(startNode)
|
|
185
|
-
while len(path) < len(
|
|
196
|
+
while len(path) < len(rows_):
|
|
186
197
|
lastNode = path[-1]
|
|
187
198
|
distFn = lastNode.station.system.distanceTo
|
|
188
|
-
nearest = min(openList, key=lambda
|
|
199
|
+
nearest = min(openList, key=lambda r: distFn(r.station.system))
|
|
189
200
|
openList.remove(nearest)
|
|
190
201
|
path.append(nearest)
|
|
191
202
|
dist += distFn(nearest.station.system)
|
|
192
203
|
return (path, dist)
|
|
204
|
+
|
|
193
205
|
if cmdenv.near:
|
|
194
206
|
bestPath = walk(0, results.rows[0].dist)
|
|
195
207
|
else:
|
|
196
208
|
bestPath = (results.rows, float("inf"))
|
|
197
209
|
for i in range(len(results.rows)):
|
|
198
|
-
|
|
199
|
-
if
|
|
200
|
-
bestPath =
|
|
210
|
+
candidate = walk(i, 0)
|
|
211
|
+
if candidate[1] < bestPath[1]:
|
|
212
|
+
bestPath = candidate
|
|
201
213
|
results.rows[:] = bestPath[0]
|
|
202
|
-
|
|
214
|
+
|
|
203
215
|
if cmdenv.limit:
|
|
204
216
|
results.rows[:] = results.rows[:cmdenv.limit]
|
|
205
|
-
|
|
217
|
+
|
|
206
218
|
return results
|
|
207
219
|
|
|
220
|
+
|
|
208
221
|
######################################################################
|
|
209
222
|
# Transform result set into output
|
|
210
223
|
|