tradedangerous 11.5.3__py3-none-any.whl → 12.0.1__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.

Files changed (47) hide show
  1. tradedangerous/cache.py +567 -395
  2. tradedangerous/cli.py +2 -2
  3. tradedangerous/commands/TEMPLATE.py +25 -26
  4. tradedangerous/commands/__init__.py +8 -16
  5. tradedangerous/commands/buildcache_cmd.py +40 -10
  6. tradedangerous/commands/buy_cmd.py +57 -46
  7. tradedangerous/commands/commandenv.py +0 -2
  8. tradedangerous/commands/export_cmd.py +78 -50
  9. tradedangerous/commands/import_cmd.py +67 -31
  10. tradedangerous/commands/market_cmd.py +52 -19
  11. tradedangerous/commands/olddata_cmd.py +120 -107
  12. tradedangerous/commands/rares_cmd.py +122 -110
  13. tradedangerous/commands/run_cmd.py +118 -66
  14. tradedangerous/commands/sell_cmd.py +52 -45
  15. tradedangerous/commands/shipvendor_cmd.py +49 -234
  16. tradedangerous/commands/station_cmd.py +55 -485
  17. tradedangerous/commands/update_cmd.py +56 -420
  18. tradedangerous/csvexport.py +173 -162
  19. tradedangerous/db/__init__.py +27 -0
  20. tradedangerous/db/adapter.py +191 -0
  21. tradedangerous/db/config.py +95 -0
  22. tradedangerous/db/engine.py +246 -0
  23. tradedangerous/db/lifecycle.py +332 -0
  24. tradedangerous/db/locks.py +208 -0
  25. tradedangerous/db/orm_models.py +455 -0
  26. tradedangerous/db/paths.py +112 -0
  27. tradedangerous/db/utils.py +661 -0
  28. tradedangerous/gui.py +2 -2
  29. tradedangerous/plugins/eddblink_plug.py +387 -251
  30. tradedangerous/plugins/spansh_plug.py +2488 -821
  31. tradedangerous/prices.py +124 -142
  32. tradedangerous/templates/TradeDangerous.sql +6 -6
  33. tradedangerous/tradecalc.py +1227 -1109
  34. tradedangerous/tradedb.py +533 -384
  35. tradedangerous/tradeenv.py +12 -1
  36. tradedangerous/version.py +1 -1
  37. {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.1.dist-info}/METADATA +11 -7
  38. {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.1.dist-info}/RECORD +42 -38
  39. {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.1.dist-info}/WHEEL +1 -1
  40. tradedangerous/commands/update_gui.py +0 -721
  41. tradedangerous/jsonprices.py +0 -254
  42. tradedangerous/plugins/edapi_plug.py +0 -1071
  43. tradedangerous/plugins/journal_plug.py +0 -537
  44. tradedangerous/plugins/netlog_plug.py +0 -316
  45. {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.1.dist-info}/entry_points.txt +0 -0
  46. {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.1.dist-info/licenses}/LICENSE +0 -0
  47. {tradedangerous-11.5.3.dist-info → tradedangerous-12.0.1.dist-info}/top_level.txt +0 -0
@@ -1,429 +1,65 @@
1
- # Deprecated
2
- from .parsing import MutuallyExclusiveGroup, ParseArgument
3
- from ..tradeexcept import TradeException
4
- from .exceptions import CommandLineError
5
- from ..tradedb import System
6
- from .. import prices, cache
7
- import subprocess
8
- import os
9
- import sys
10
- import pathlib
11
-
12
- ######################################################################
13
- # Parser config
14
-
15
- help = 'Update prices for a station.'
16
- name = 'update'
17
- epilog = ("Generates a human-readable version of the price list for a given station "
18
- "and opens it in the specified text editor.\n"
19
- "The format is intended to closely resemble the presentation of the "
20
- "market in-game. If you change the order items are listed in, "
21
- "the order will be kept for future edits, making it easier to quickly "
22
- "check for changes.")
23
- wantsTradeDB = True
24
- arguments = [
25
- ParseArgument('starting', help = 'Name of the station to update.', type = str)
26
- ]
27
- switches = [
28
- ParseArgument('--timestamps', '-T',
29
- help = '[Text editing] Includes timestamps in the update.',
30
- action = 'store_true',
31
- default = False,
32
- ),
33
- ParseArgument('--all', '-A',
34
- help = 'List all known items.',
35
- action = 'store_true',
36
- default = False,
37
- ),
38
- ParseArgument('--use-demand', '-D',
39
- help = 'Unlock the "Demand" column in the GUI.',
40
- action = 'store_true',
41
- dest = 'useDemand',
42
- default = False,
43
- ),
44
- ParseArgument('--force-na', '-0',
45
- help = "Forces 'unk' supply to become 'n/a' by default",
46
- action = 'store_true',
47
- default = False,
48
- dest = 'forceNa',
49
- ),
50
- ParseArgument('--height', '-H',
51
- help = "[GUI] Specify height of the window",
52
- type = int,
53
- default = 800,
54
- ),
55
- ParseArgument('--front', '-F',
56
- help = (
57
- "[GUI] Keep the GUI infront of other windows; "
58
- "this allows you to put the window infront of "
59
- "the game UI if you run the game in windowed mode."
60
- ),
61
- action = 'store_true',
62
- default = False,
63
- dest = 'alwaysOnTop',
64
- ),
65
- ParseArgument('--window-x', '-wx',
66
- help = (
67
- "[GUI] Specify the window X position "
68
- "Use a negative value for a right-of-screen relative offset"
69
- ),
70
- default = -1,
71
- dest = 'windowX',
72
- type = int,
1
+ # tradedangerous/commands/update_cmd.py — DEPRECATED (no-op)
2
+ # This command no longer edits station price lists directly.
3
+ #
4
+ # How to maintain price/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
+ # This module accepts and ignores any arguments/switches and exits immediately.
10
+
11
+ from __future__ import annotations
12
+ from .parsing import ParseArgument
13
+
14
+ # ---- Command metadata ----
15
+ help = "DEPRECATED: no longer used. See deprecation banner when run."
16
+ name = "update"
17
+ epilog = None
18
+
19
+ # Swallow unknown switches/args (loader must honor this flag).
20
+ acceptUnknown = True
21
+
22
+ # No DB access is needed for this no-op command.
23
+ wantsTradeDB = False
24
+ usesTradeData = False
25
+
26
+ # Accept ANY number of positional args and ignore them (prevents parser errors).
27
+ arguments = (
28
+ ParseArgument(
29
+ "args",
30
+ help="(deprecated) ignored",
31
+ nargs="*",
32
+ type=str,
73
33
  ),
74
- ParseArgument('--window-y', '-wy',
75
- help = (
76
- "[GUI] Specify the window U position "
77
- "Use a negative value for a bottom-of-screen relative offset"
78
- ),
79
- default = 1,
80
- dest = 'windowY',
81
- type = int,
82
- ),
83
- MutuallyExclusiveGroup(
84
- ParseArgument('--gui', '-G',
85
- help = "Use the experimental built-in GUI",
86
- action = 'store_true',
87
- default = False,
88
- dest = 'gui',
89
- ),
90
- ParseArgument('--editor',
91
- help = 'Generates a text file containing the prices for '
92
- 'the station and loads it into the specified '
93
- 'text editor for you.',
94
- default = None,
95
- type = str,
96
- ),
97
- ParseArgument('--sublime',
98
- help = 'Like --editor but uses Sublime Text (2 or 3).',
99
- action = 'store_const', const = 'sublime', dest = 'editing',
100
- ),
101
- ParseArgument('--notepad',
102
- help = 'Like --editor but uses Notepad.',
103
- action = 'store_const', const = 'notepad', dest = 'editing',
104
- ),
105
- ParseArgument('--npp',
106
- help = 'Like --editor but uses Notepad++.',
107
- action = 'store_const', const = 'npp', dest = 'editing',
108
- ),
109
- ParseArgument('--vim',
110
- help = 'Like --editor but uses vim.',
111
- action = 'store_const', const = 'vim', dest = 'editing',
112
- ),
113
- )
114
- ]
115
-
116
- ######################################################################
117
- # Helpers
118
-
119
-
120
- class TemporaryFileExistsError(TradeException):
121
- pass
122
-
123
-
124
- def getTemporaryPath(cmdenv):
125
- tmpPath = pathlib.Path("prices.tmp")
126
- if tmpPath.exists():
127
- if not cmdenv.force:
128
- raise TemporaryFileExistsError(
129
- "Temporary file already exists: {}\n"
130
- "(Check you aren't already editing in another window"
131
- .format(tmpPath)
132
- )
133
- tmpPath.unlink()
134
- return tmpPath
135
-
136
-
137
- def saveTemporaryFile(tmpPath):
138
- if tmpPath.exists():
139
- lastPath = pathlib.Path("prices.last")
140
- if lastPath.exists():
141
- lastPath.unlink()
142
- tmpPath.rename(lastPath)
143
-
144
-
145
- def saveCopyOfChanges(cmdenv, dbFilename, stationID):
146
- if "APPEND_PRICES" in os.environ:
147
- mode = "a"
148
- else:
149
- mode = "w"
150
- dumpPath = pathlib.Path("updated.prices")
151
- with dumpPath.open(mode, encoding = 'utf-8') as dumpFile:
152
- # Remember the filename so we know we need to delete it.
153
- prices.dumpPrices(dbFilename,
154
- prices.Element.full | prices.Element.blanks,
155
- file = dumpFile,
156
- stationID = stationID,
157
- defaultZero = False,
158
- debug = cmdenv.debug,
159
- )
160
- if not cmdenv.quiet:
161
- print("- Copy of changes saved as '{}'".format(
162
- str(dumpPath)
163
- ))
164
-
165
-
166
- def getEditorPaths(cmdenv, editorName, envVar, windowsFolders, winExe, nixExe):
167
- cmdenv.DEBUG0("Locating {} editor", editorName)
168
- try:
169
- return os.environ[envVar]
170
- except KeyError:
171
- pass
172
-
173
- paths = []
174
-
175
- import platform
176
- system = platform.system()
177
- if system == 'Windows':
178
- binary = winExe
179
- for folder in ["Program Files", "Program Files (x86)"]:
180
- for version in windowsFolders:
181
- paths.append("{}\\{}\\{}".format(os.environ['SystemDrive'], folder, version))
182
- else:
183
- binary = nixExe
184
-
185
- try:
186
- paths += os.environ['PATH'].split(os.pathsep)
187
- except KeyError:
188
- pass
189
-
190
- for path in paths:
191
- candidate = os.path.join(path, binary)
192
- try:
193
- if pathlib.Path(candidate).exists():
194
- return candidate
195
- except OSError:
196
- pass
197
-
198
- raise CommandLineError(
199
- "ERROR: Unable to locate {} editor.\n"
200
- "Either specify the path to your editor with --editor "
201
- "or set the {} environment variable to point to it."
202
- .format(editorName, envVar)
34
+ )
35
+ # No switches; unknown switches will be ignored via acceptUnknown.
36
+ switches = tuple()
37
+
38
+
39
+ def _banner() -> str:
40
+ return (
41
+ "\n"
42
+ "=== DEPRECATION NOTICE: update =====================================\n"
43
+ "This command no longer edits station price lists and does not modify the DB.\n"
44
+ "• Import data via: trade import -P eddblink | -P spansh\n"
45
+ "• Solo/offline capture via EDMC: TradeDangerous DB-Update → https://github.com/bgol/UpdateTD\n"
46
+ "=====================================================================\n"
203
47
  )
204
48
 
205
49
 
206
- def editUpdate(tdb, cmdenv, stationID):
50
+ def run(results, cmdenv, tdb=None):
207
51
  """
208
- Dump the price data for a specific station to a file and
209
- launch the user's text editor to let them make changes
210
- to the file.
211
-
212
- If the user makes changes, re-load the file, update the
213
- database and regenerate the master .prices file.
52
+ No-op implementation: print banner and exit immediately.
53
+ All arguments/switches are ignored by design.
214
54
  """
215
-
216
- cmdenv.DEBUG0("'update' mode with editor. editor:{} station:{}",
217
- cmdenv.editor, cmdenv.origin)
218
-
219
- editor, editorArgs = cmdenv.editor, []
220
- if cmdenv.editing == 'sublime':
221
- cmdenv.DEBUG0("Sublime mode")
222
- editor = editor or \
223
- getEditorPaths(cmdenv,
224
- "sublime", "SUBLIME_EDITOR",
225
- ["Sublime Text 3", "Sublime Text 2"],
226
- "sublime_text.exe",
227
- "subl"
228
- )
229
- editorArgs += [ "--wait" ]
230
- elif cmdenv.editing == 'npp':
231
- cmdenv.DEBUG0("Notepad++ mode")
232
- editor = editor or \
233
- getEditorPaths(cmdenv,
234
- "notepad++", "NOTEPADPP_EDITOR",
235
- ["Notepad++"],
236
- "notepad++.exe",
237
- "notepad++"
238
- )
239
- if not cmdenv.quiet:
240
- print("NOTE: "
241
- "You'll need to exit Notepad++ when you are done.")
242
- elif cmdenv.editing == "vim":
243
- cmdenv.DEBUG0("VI iMproved mode")
244
- if not editor:
245
- # Hack... Hackity hack, hack, hack.
246
- # This has a disadvantage in that: we don't check for just "vim" (no .exe) under Windows
247
- vimDirs = [
248
- "Git\\share\\vim\\vim{}".format(vimVer)
249
- for vimVer in range(70, 75)
250
- ]
251
- editor = getEditorPaths(cmdenv,
252
- "vim",
253
- "EDITOR",
254
- vimDirs,
255
- "vim.exe",
256
- "vim"
257
- )
258
- elif cmdenv.editing == "notepad":
259
- cmdenv.DEBUG0("Notepad mode")
260
- editor = editor or "notepad.exe" # herp
261
-
55
+ banner = _banner()
262
56
  try:
263
- envArgs = os.environ["EDITOR_ARGS"]
264
- if envArgs:
265
- editorArgs += envArgs.split(' ')
266
- except KeyError:
267
- pass
268
-
269
- # Create a temporary text file with a list of the price data.
270
- tmpPath = getTemporaryPath(cmdenv)
271
-
272
- absoluteFilename = None
273
- dbFilename = tdb.dbFilename
274
- try:
275
- elementMask = prices.Element.basic | prices.Element.supply
276
- if cmdenv.timestamps:
277
- elementMask |= prices.Element.timestamp
278
- if cmdenv.all:
279
- elementMask |= prices.Element.blanks
280
- # Open the file and dump data to it.
281
- with tmpPath.open("w", encoding = 'utf-8') as tmpFile:
282
- # Remember the filename so we know we need to delete it.
283
- absoluteFilename = str(tmpPath.resolve())
284
- prices.dumpPrices(dbFilename, elementMask,
285
- file = tmpFile,
286
- stationID = stationID,
287
- defaultZero = cmdenv.forceNa,
288
- debug = cmdenv.debug
289
- )
290
-
291
- # Stat the file so we can determine if the user writes to it.
292
- # Use the most recent create/modified timestamp.
293
- preStat = tmpPath.stat()
294
- preStamp = max(preStat.st_mtime, preStat.st_ctime)
295
-
296
- # Launch the editor
297
- editorCommandLine = [ editor ] + editorArgs + [ absoluteFilename ]
298
- cmdenv.DEBUG0("Invoking [{}]", ' '.join(editorCommandLine))
299
- try:
300
- result = subprocess.call(editorCommandLine)
301
- except FileNotFoundError:
302
- raise CommandLineError(
303
- "Unable to launch requested editor: {}"
304
- .format(editorCommandLine)
305
- )
306
- if result != 0:
307
- raise CommandLineError(
308
- "NO DATA IMPORTED: "
309
- "Your editor exited with a 'failed' exit code ({})"
310
- .format(result)
311
- )
312
-
313
- # Did they update the file? Some editors destroy the file and rewrite it,
314
- # other files just write back to it, and some OSes do weird things with
315
- # these timestamps. That's why we have to use both mtime and ctime.
316
- postStat = tmpPath.stat()
317
- postStamp = max(postStat.st_mtime, postStat.st_ctime)
318
-
319
- if postStamp == preStamp:
320
- import random
321
- print("- No changes detected - doing nothing. {}".format(
322
- random.choice([
323
- "Brilliant!",
324
- "I'll get my coat.",
325
- "I ain't seen you.",
326
- "You ain't seen me",
327
- "... which was nice",
328
- "Bingo!",
329
- "Scorchio!",
330
- "Boutros, boutros, ghali!",
331
- "I'm Ed Winchester!",
332
- "Suit you, sir! Oh!"
333
- ])
334
- ))
335
- else:
336
- cache.importDataFromFile(tdb, cmdenv, tmpPath)
337
- saveCopyOfChanges(cmdenv, dbFilename, stationID)
338
-
339
- tmpPath.unlink()
340
- tmpPath = None
341
-
342
- except Exception as e:
343
- print("ERROR:", e)
344
- print()
345
- print("*** YOUR UPDATES WILL BE SAVED AS {} ***".format(
346
- "prices.last"
347
- ))
348
- # Save a copy
349
- if absoluteFilename and tmpPath:
350
- saveTemporaryFile(tmpPath)
351
- if "EXCEPTIONS" in os.environ:
352
- raise e
353
-
354
-
355
- def guidedUpdate(tdb, cmdenv):
356
- dbFilename = tdb.dbFilename
357
- stationID = cmdenv.startStation.ID
358
- tmpPath = getTemporaryPath(cmdenv)
359
-
360
- cur = tdb.query("""
361
- SELECT JULIANDAY('now') - JULIANDAY(MIN(modified)),
362
- JULIANDAY('now') - JULIANDAY(MAX(modified))
363
- FROM StationItem
364
- WHERE station_id = ?
365
- """, [stationID])
366
- oldest, newest = cur.fetchone()
367
- if oldest and newest:
368
- cmdenv.NOTE(
369
- "Current data {:.2f}-{:.2f} days old.",
370
- oldest, newest,
371
- )
372
-
373
- from .update_gui import render
374
- try:
375
- render(tdb, cmdenv, tmpPath)
376
- cmdenv.DEBUG0("Got results, importing")
377
- cache.importDataFromFile(tdb, cmdenv, tmpPath)
378
-
379
- saveCopyOfChanges(cmdenv, dbFilename, stationID)
380
-
381
- tmpPath.unlink()
382
- tmpPath = None
383
-
384
- except Exception as e:
385
- print("ERROR:", e)
386
- print()
387
- print("*** YOUR UPDATES WILL BE SAVED AS {} ***".format(
388
- "prices.last"
389
- ))
390
-
391
- if tmpPath:
392
- saveTemporaryFile(tmpPath)
393
- if "EXCEPTIONS" in os.environ:
394
- raise e
395
-
396
- ######################################################################
397
- # Perform query and populate result set
57
+ cmdenv.NOTE("{}", banner)
58
+ except Exception:
59
+ print(banner)
60
+ return None
398
61
 
399
62
 
400
- def run(results, cmdenv, tdb):
401
- place = cmdenv.origPlace
402
- if isinstance(place, System):
403
- system = place
404
- if len(system.stations) != 1:
405
- raise CommandLineError(
406
- "'{}' is a system, not a station.".format(
407
- system.name()
408
- ))
409
- cmdenv.startStation = system.stations[0]
410
- else:
411
- cmdenv.startStation = place
412
-
413
- if cmdenv.gui or (not cmdenv.editor and not cmdenv.editing):
414
- if not cmdenv.quiet:
415
- print(
416
- "NOTE:\n"
417
- ". Press CTRL-C here to abort edit, otherwise "
418
- "just close the update window to save.\n"
419
- ". '-F' makes the window show in-front of the "
420
- "E:D Window.\n"
421
- ". '-A' forces all items to be listed.\n",
422
- file = sys.stderr
423
- )
424
- guidedUpdate(tdb, cmdenv)
425
- else:
426
- # User specified one of the options to use an editor.
427
- editUpdate(tdb, cmdenv, cmdenv.startStation.ID)
428
-
429
- return None
63
+ def render(results, cmdenv, tdb=None):
64
+ # No output beyond the banner emitted in run().
65
+ return