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,721 +0,0 @@
1
- # Deprecated
2
- import tkinter as tk
3
- import tkinter.messagebox as mbox
4
- import sqlite3
5
- import re
6
-
7
- """
8
- This is a crude attempt at a GUI for updating trade prices.
9
- It needs a lot of love to be less... Shitty.
10
-
11
- TODO:
12
- . Add a way to add a new line,
13
- . Add a way to reorder lines,
14
- . Add a Save button,
15
- . Add pre-exit validation (and don't exit if there's a problem),
16
-
17
- Thanks to Bryan Okler for solving the focus tracking issue:
18
- http://stackoverflow.com/questions/27055936/python3-tk-scrollbar-and-focus
19
-
20
- """
21
-
22
- updateUiHelp = (
23
- "ABOUT THE EDITOR:\n"
24
- "The columns shown here represent the columns in the "
25
- "in-game Commodites Market UI and are in the same order.\n"
26
- "\n"
27
- "WHAT TO ENTER:\n"
28
- "Leave items blank if they are NOT listed in the game UI.\n"
29
- "\n"
30
- "'Demand' is disabled unless you use '--use-demand'.\n"
31
- "\n"
32
- "'Supply' should be:\n"
33
- " '-' or '0' if no units are available,\n"
34
- " empty or '?' if the level is unknown,\n"
35
- " or the amount of supply followed by L, M or H.\n"
36
- "E.g.\n"
37
- " 1L, 50M, 3000H.\n"
38
- "\n"
39
- "SAVING:\n"
40
- "To save your data, click one of the window's close buttons.\n"
41
- "\n"
42
- "NAVIGATION:\n"
43
- "- Use Tab, Shift-Tab, Up/Down Arrow and Enter to navigate.\n"
44
- )
45
-
46
- class Item:
47
- """ Describe a listed, tradeable item """
48
-
49
- def __init__(self, ID, catID, name, displayNo):
50
- self.ID, self.catID, self.name = ID, catID, name
51
- self.displayNo = displayNo
52
-
53
-
54
- class ScrollingCanvas(tk.Frame):
55
- """
56
- Tk.Canvas with scrollbar.
57
- """
58
-
59
- def __init__(self, parent):
60
- super().__init__(parent)
61
- self.parent = parent
62
-
63
- self.canvas = canvas = tk.Canvas(self, borderwidth=0)
64
- canvas.grid(row=0, column=0)
65
- canvas.grid_rowconfigure(0, weight=1)
66
- canvas.grid_columnconfigure(0, weight=1)
67
-
68
- vsb = tk.Scrollbar(parent,
69
- orient=tk.VERTICAL,
70
- command=canvas.yview)
71
- vsb.grid(row=0, column=1)
72
- vsb.pack(side="right", fill=tk.BOTH, expand=False)
73
-
74
- canvas.configure(yscrollcommand=vsb.set)
75
- canvas.configure(yscrollincrement=4)
76
-
77
- self.interior = interior = tk.Frame(canvas)
78
- canvas.create_window(0, 0, window=interior, anchor="nw", tags="interior")
79
- canvas.bind("<Configure>", self.onConfigure)
80
- interior.rowconfigure(0, weight=1)
81
- interior.columnconfigure(0, weight=1)
82
- interior.columnconfigure(1, weight=1)
83
- interior.columnconfigure(2, weight=1)
84
- interior.columnconfigure(3, weight=1)
85
- interior.columnconfigure(4, weight=1)
86
-
87
- canvas.grid(row=0, column=0)
88
- canvas.pack(side="left", fill=tk.BOTH, expand=True)
89
-
90
- self.bind_all("<MouseWheel>", self.onMouseWheel)
91
- canvas.bind_all("<FocusIn>", self.scrollIntoView)
92
-
93
- self.pack(side="left", fill=tk.BOTH, expand=True)
94
-
95
-
96
- def onConfigure(self, event):
97
- """ Handle resizing """
98
-
99
- self.canvas.configure(scrollregion=self.interior.bbox("all"))
100
-
101
-
102
- def onMouseWheel(self, event):
103
- """ Translate mouse wheel inputs to scroll bar motions """
104
-
105
- self.canvas.yview_scroll(int(-1 * (event.delta/4)), "units")
106
-
107
-
108
- def scrollIntoView(self, event):
109
- """ Scroll so that a given widget is in focus """
110
-
111
- canvas = self.canvas
112
- widget_top = event.widget.winfo_y()
113
- widget_bottom = widget_top + event.widget.winfo_height()
114
- canvas_top = canvas.canvasy(0)
115
- canvas_bottom = canvas_top + canvas.winfo_height()
116
-
117
- if widget_bottom >= canvas_bottom:
118
- delta = int(canvas_bottom - widget_bottom)
119
- canvas.yview_scroll(-delta, "units")
120
- elif widget_top < canvas_top:
121
- delta = int(widget_top - canvas_top)
122
- canvas.yview_scroll(delta, "units")
123
-
124
-
125
- class UpdateGUI(ScrollingCanvas):
126
- """
127
- Implements a tk canvas which displays an editor
128
- for TradeDangerous Price Updates
129
- """
130
-
131
- def __init__(self, parent, tdb, tdenv):
132
- super().__init__(parent)
133
-
134
- width = tdenv.width or 640
135
- height = tdenv.height or 640
136
- sticky = 1 if tdenv.alwaysOnTop else 0
137
-
138
- self.tdb = tdb
139
- self.tdenv = tdenv
140
-
141
- self.rowNo = 0
142
- self.colNo = 0
143
- self.items = {}
144
- self.categories = []
145
- self.itemList = []
146
- self.itemDisplays = []
147
- self.results = None
148
- self.headings = []
149
-
150
- self.createWidgets()
151
-
152
- self.focusOn(0, 0)
153
-
154
- parent.geometry("{}x{}{:+n}{:+n}".format(
155
- width+16, height,
156
- tdenv.windowX,
157
- tdenv.windowY,
158
- ))
159
-
160
- # Allow the window to be always-on-top
161
- parent.wm_attributes("-topmost", sticky)
162
-
163
-
164
- def selectWidget(self, widget, newValue=None):
165
- if newValue is not None:
166
- widget.val.set(newValue)
167
- widget.focus_set()
168
- widget.selection_range(0, tk.END)
169
-
170
-
171
- def focusOn(self, displayNo, pos):
172
- """ Set focus to a widget and select the text in it """
173
-
174
- row = self.itemDisplays[displayNo]
175
- widget = row[pos][0]
176
- self.selectWidget(widget)
177
-
178
-
179
- def setValue(self, row, pos, value):
180
- row[pos][1].set(value)
181
- return value
182
-
183
-
184
- def getValue(self, row, pos):
185
- return row[pos][1].get()
186
-
187
-
188
- def validateRow(self, row):
189
- paying = row[0][1].get()
190
- if not paying or paying == "0":
191
- paying = ""
192
- for col in row:
193
- col[1].set("")
194
- row[1][0].configure(state=tk.DISABLED)
195
- row[2][0].configure(state=tk.DISABLED)
196
- else:
197
- row[1][0].configure(state=tk.NORMAL)
198
- if self.tdenv.useDemand:
199
- row[2][0].configure(state=tk.NORMAL)
200
- else:
201
- row[2][0].configure(state=tk.DISABLED)
202
- row[2][1].set("")
203
-
204
- asking = row[1][1].get()
205
- if asking == "0":
206
- row[1][1].set("")
207
- asking = ""
208
- if not asking:
209
- row[3][0].configure(state=tk.DISABLED)
210
- row[3][1].set("")
211
- else:
212
- row[3][0].configure(state=tk.NORMAL)
213
- if not row[3][1].get():
214
- row[3][1].set("?")
215
-
216
-
217
- def checkValueAgainstStats(self, widget, stats):
218
- widget.configure(bg = 'white')
219
- minCr, avgCr, maxCr = stats
220
- if not avgCr:
221
- return True
222
-
223
- cr = int(widget.val.get())
224
-
225
- if cr < int(minCr / 1.01) and cr < int(avgCr * 0.7):
226
- widget.bell()
227
- ok = mbox.askokcancel(
228
- "Very low price",
229
- "The price you entered is very low.\n"
230
- "\n"
231
- "Your input was: {}\n"
232
- "Previous low..: {}\n"
233
- "\n"
234
- "Is it correct?".format(
235
- cr, minCr,
236
- ))
237
- if not ok:
238
- self.selectWidget(widget, "")
239
- return False
240
- widget.configure(bg = '#ff8080')
241
-
242
- if cr >= (maxCr * 1.01) and int(cr * 0.7) > avgCr:
243
- widget.bell()
244
- ok = mbox.askokcancel(
245
- "Very high price",
246
- "The price you entered is very high.\n"
247
- "\n"
248
- "Your input was..: {}\n"
249
- "Previous highest: {}\n"
250
- "\n"
251
- "Is it correct?".format(
252
- cr, maxCr,
253
- ))
254
- if not ok:
255
- self.selectWidget(widget, "")
256
- return False
257
- widget.configure(bg = '#8080ff')
258
-
259
- return True
260
-
261
-
262
- def validate(self, widget):
263
- """ For checking the contents of a widget. """
264
- item, row, pos = widget.item, widget.row, widget.pos
265
-
266
- value = widget.val.get()
267
- re.sub(" +", "", value)
268
- re.sub(",", "", value)
269
- widget.val.set(value)
270
-
271
- self.validateRow(row)
272
-
273
- if pos == 0:
274
- if not value or value == "0":
275
- widget.val.set("")
276
- return True
277
-
278
- if not re.match(r'^\d+$', value):
279
- mbox.showerror(
280
- "Invalid Paying price",
281
- "Price must be an numeric value (e.g. 1234)"
282
- )
283
- return False
284
-
285
- # is it lower than the value?
286
- demandStats = self.demandStats[item.ID]
287
- if not self.checkValueAgainstStats(widget, demandStats):
288
- return False
289
-
290
- if pos <= 1:
291
- if not value or value == "0":
292
- widget.val.set("")
293
- return True
294
-
295
- if not re.match(r'^\d+$', value):
296
- mbox.showerror(
297
- "Invalid Paying price",
298
- "Price must be an numeric value (e.g. 1234)"
299
- )
300
- return False
301
-
302
- if pos == 1:
303
- # Don't allow crazy difference between prices
304
- paying = int(row[0][1].get())
305
- asking = int(row[1][1].get())
306
-
307
- if asking < paying:
308
- widget.bell()
309
- mbox.showerror(
310
- "I DOUBT THAT!",
311
- "Stations never pay more for an item than "
312
- "they sell it for.",
313
- )
314
- return False
315
-
316
- supplyStats = self.supplyStats[item.ID]
317
- if not self.checkValueAgainstStats(widget, supplyStats):
318
- return False
319
-
320
- # https://forums.frontier.co.uk/showthread.php?t=34986&p=1162429&viewfull=1#post1162429
321
- # It seems that stations usually pay within 25% of the
322
- # asking price as a buy-back price. If the user gives
323
- # us something out of those bounds, check with them.
324
- if paying < int(asking * 0.70) or \
325
- paying < asking - 250:
326
- widget.bell()
327
- ok = mbox.askokcancel(
328
- "Are you sure about that?",
329
- "You've indicated that the station is:\n"
330
- " PAYING: {:>10n}cr\n"
331
- " ASKING: {:>10n}cr\n"
332
- "for {}.\n"
333
- "\n"
334
- "This is outside of expected tolerances, "
335
- "please check the numbers.\n"
336
- "\n"
337
- "If the numbers are correct, click OK and "
338
- "please post a screenshot of the market UI "
339
- "to the TD thread "
340
- "(http://kfs.org/td/thread)."
341
- .format(
342
- paying, asking,
343
- widget.item.name
344
- ),
345
- default=mbox.CANCEL,
346
- parent=widget,
347
- )
348
- if not ok:
349
- self.selectWidget(widget, "")
350
- return False
351
-
352
- return True
353
-
354
- if pos == 3:
355
- value = widget.val.get()
356
- if value == "0":
357
- value = "-"
358
- if value == "":
359
- value = "?"
360
- re.sub(",", "", value)
361
- widget.val.set(value)
362
- if re.match(r'^(-|\?|\d+[LlMmHh\?])$', value):
363
- return True
364
- mbox.showerror(
365
- "Invalid supply value",
366
- "If the item is in-supply, this field should "
367
- "be the number of units followed by one of 'L', "
368
- "'M' or 'H'.\n"
369
- "\n"
370
- "If the item is out-of-supply, use '-' or '0'.\n"
371
- "\n"
372
- "EXAMPLE: If the UI says '2341 LOW', type '2341L'.\n"
373
- )
374
- widget.val.set("?")
375
- self.selectWidget(widget)
376
- return False
377
-
378
- return True
379
-
380
-
381
- def onShiftTab(self, event):
382
- """ Process user pressing Shift+TAB """
383
-
384
- widget = event.widget
385
- if not self.validate(widget):
386
- return "break"
387
- if widget.pos > 0 or widget.item.displayNo > 0:
388
- # Natural flow
389
- return
390
-
391
- self.parent.bell()
392
- return "break"
393
-
394
-
395
- def onTab(self, event):
396
- """ Process user pressing TAB """
397
-
398
- widget = event.widget
399
- if not self.validate(widget):
400
- return "break"
401
- if widget.pos + 1 < len(widget.row):
402
- return
403
- if widget.item.displayNo + 1 < len(self.itemDisplays):
404
- return
405
- self.parent.bell()
406
- return "break"
407
-
408
-
409
- def onReturn(self, event):
410
- """
411
- When the user hits <Return>, advance to
412
- the first cell on the next line, or if
413
- we are at the bottom of the list, beep.
414
- """
415
-
416
- widget = event.widget
417
- if not self.validate(widget):
418
- return "break"
419
- # advance to the first entry on the next row
420
- newDisplayNo = widget.item.displayNo + 1
421
- if newDisplayNo >= len(self.itemDisplays):
422
- self.parent.bell()
423
- return "break"
424
-
425
- self.focusOn(newDisplayNo, 0)
426
-
427
-
428
- def onUp(self, event):
429
- """ Handle the user pressing up, go up a row """
430
-
431
- widget = event.widget
432
- if not self.validate(widget):
433
- return "break"
434
- # can we go up a line?
435
- if widget.item.displayNo <= 0:
436
- self.parent.bell()
437
- return "break"
438
-
439
- self.focusOn(widget.item.displayNo - 1, widget.pos)
440
-
441
-
442
- def onDown(self, event):
443
- """ Handle the user pressing down, go down a row """
444
-
445
- widget = event.widget
446
- if not self.validate(widget):
447
- return "break"
448
- # can we go up a line?
449
- newDisplayNo = widget.item.displayNo + 1
450
- if newDisplayNo >= len(self.itemDisplays):
451
- self.parent.bell()
452
- return "break"
453
-
454
- self.focusOn(newDisplayNo, widget.pos)
455
-
456
-
457
- def endRow(self):
458
- self.rowNo += 1
459
- self.colNo = 0
460
-
461
-
462
- def addWidget(self, widget, **kwargs):
463
- widget.grid(row=self.rowNo, column=self.colNo, **kwargs)
464
- self.colNo += 1
465
- return widget
466
-
467
-
468
- def addLabel(self, text):
469
- lab = tk.Label(self.interior, text=text)
470
- return self.addWidget(lab, sticky='W', padx=16)
471
-
472
-
473
- def addSection(self, text):
474
- widget = tk.Label(self.interior, text=text, fg='blue')
475
- widget.grid(row=self.rowNo, column=0, columnspan=5, sticky='W')
476
- self.endRow()
477
- return widget
478
-
479
-
480
- def addInput(self, item, defValue, row):
481
- pos = len(row)
482
-
483
- inputVal = tk.StringVar()
484
- inputVal.set(str(defValue))
485
-
486
- inputEl = tk.Entry(self.interior,
487
- width=10,
488
- justify=tk.RIGHT,
489
- textvariable=inputVal)
490
- inputEl.item = item
491
- inputEl.row = row
492
- inputEl.pos = pos
493
- inputEl.val = inputVal
494
-
495
- inputEl.bind('<Shift-Key-Tab>', self.onShiftTab)
496
- inputEl.bind('<Key-Tab>', self.onTab)
497
- inputEl.bind('<Key-Return>', self.onReturn)
498
- inputEl.bind('<Key-Down>', self.onDown)
499
- inputEl.bind('<Key-Up>', self.onUp)
500
- inputEl.bind('<FocusOut>', lambda evt: self.validateRow(evt.widget.row))
501
- self.addWidget(inputEl, sticky='E')
502
- row.append((inputEl, inputVal))
503
-
504
-
505
- def addHeadings(self):
506
- def addHeading(text):
507
- self.headings.append(text)
508
- lab = tk.Label(self.interior, text=text, fg='blue')
509
- self.addWidget(lab, sticky='W', padx=16)
510
- addHeading("Item")
511
- addHeading("Paying")
512
- addHeading("Asking")
513
- addHeading("Demand")
514
- addHeading("Supply")
515
- addHeading("AvgPay")
516
- addHeading("AvgAsk")
517
- self.endRow()
518
-
519
-
520
- def addItemRow(self, ID, catID, itemName, paying, asking, demand, supply):
521
- row = []
522
-
523
- displayNo = len(self.itemDisplays)
524
- item = Item(ID, catID, itemName, displayNo)
525
- self.items[itemName] = item
526
- self.itemList.append(item)
527
-
528
- demandStats = self.demandStats[item.ID]
529
- supplyStats = self.supplyStats[item.ID]
530
-
531
- self.addLabel(item.name.upper())
532
- self.addInput(item, paying, row)
533
- self.addInput(item, asking, row)
534
- self.addInput(item, demand, row)
535
- self.addInput(item, supply, row)
536
- self.addLabel(demandStats[1])
537
- self.addLabel(supplyStats[1])
538
-
539
- self.itemDisplays.append(row)
540
-
541
- self.endRow()
542
-
543
-
544
- def createWidgets(self):
545
- self.addHeadings()
546
-
547
- tdb, tdenv = self.tdb, self.tdenv
548
- station = tdenv.startStation
549
- self.parent.title(station.name())
550
-
551
- db = tdb.getDB()
552
- db.row_factory = sqlite3.Row
553
- cur = db.cursor()
554
-
555
- self.categories = self.tdb.categoryByID
556
-
557
- # Do we have entries for this station?
558
- cur.execute("""
559
- SELECT COUNT(*)
560
- FROM StationItem
561
- WHERE station_id = ?
562
- """, [station.ID])
563
- self.newStation = False if int(cur.fetchone()[0]) else True
564
-
565
- cur.execute("""
566
- SELECT item.item_id,
567
- IFNULL(MIN(demand_price), 0),
568
- IFNULL(AVG(demand_price), 0),
569
- IFNULL(MAX(demand_price), 0)
570
- FROM Item
571
- LEFT OUTER JOIN StationItem AS si
572
- ON (
573
- item.item_id = si.item_id
574
- AND si.demand_price > 0
575
- )
576
- GROUP BY 1
577
- """)
578
- self.demandStats = {
579
- ID: [ minCr, int(avgCr), maxCr ]
580
- for ID, minCr, avgCr, maxCr in cur
581
- }
582
- cur.execute("""
583
- SELECT item.item_id,
584
- IFNULL(MIN(supply_price), 0),
585
- IFNULL(AVG(supply_price), 0),
586
- IFNULL(MAX(supply_price), 0)
587
- FROM Item
588
- LEFT OUTER JOIN StationItem AS si
589
- ON (
590
- item.item_id = si.item_id
591
- AND si.supply_price > 0
592
- )
593
- GROUP BY 1
594
- """)
595
- self.supplyStats = {
596
- ID: [ minCr, int(avgCr), maxCr ]
597
- for ID, minCr, avgCr, maxCr in cur
598
- }
599
-
600
- if self.newStation and not tdenv.all:
601
- def splashScreen():
602
- mbox.showinfo(
603
- "New Station!",
604
- "There is currently no price data for this station "
605
- "in the database!\n\n" + updateUiHelp,
606
- parent=self,
607
- )
608
- self.itemDisplays[0][0][0].focus_set()
609
- self.parent.after(750, splashScreen)
610
-
611
- # if the user specified "--all", force listing of all items
612
- fetchAll = (self.newStation or tdenv.all)
613
- siJoin = "LEFT OUTER" if fetchAll else "INNER"
614
- stmt = """
615
- SELECT item.category_id AS catID,
616
- item.item_id AS ID,
617
- item.name AS name,
618
- IFNULL(si.demand_price, '') AS paying,
619
- IFNULL(si.supply_price, '') AS asking,
620
- IFNULL(si.demand_units, 0) AS demandUnits,
621
- IFNULL(si.demand_level, 0) AS demandLevel,
622
- IFNULL(si.supply_units, 0) AS supplyUnits,
623
- IFNULL(si.supply_level, 0) AS supplyLevel
624
- FROM (
625
- Category AS cat
626
- INNER JOIN Item item
627
- USING (category_id)
628
- ) {siJoin} JOIN
629
- StationItem si ON (
630
- si.item_id = item.item_id AND si.station_id = ?
631
- )
632
- ORDER BY cat.name, item.ui_order
633
- """.format(siJoin=siJoin)
634
- tdenv.DEBUG1("sql: {}; bind: {}", stmt, station.ID)
635
- cur.execute(stmt, [station.ID])
636
-
637
- def describeSupply(units, level):
638
- if not level:
639
- return ""
640
- if units == -1 and level == -1:
641
- return "?"
642
- if level == -1:
643
- return "{}?".format(units)
644
- return "{}{}".format(units, ['L', 'M', 'H'][level-1])
645
-
646
- lastCat = None
647
- for row in cur:
648
- cat = row["catID"]
649
- if cat != lastCat:
650
- self.addSection(self.categories[cat].name())
651
- lastCat = cat
652
- itemName = row["name"]
653
- paying, asking = row["paying"], row["asking"]
654
- demand = describeSupply(row["demandUnits"], row["demandLevel"])
655
- supply = describeSupply(row["supplyUnits"], row["supplyLevel"])
656
- self.addItemRow(row["ID"], cat, itemName, paying, asking, demand, supply)
657
-
658
-
659
- for row in self.itemDisplays:
660
- self.validateRow(row)
661
-
662
-
663
- def getResults(self):
664
- lastCat = None
665
-
666
- txt = (
667
- "# Generated by TDGUI\n"
668
- "\n"
669
- "@ {stn}\n".format(
670
- stn=self.tdenv.startStation.name(),
671
- )
672
- )
673
- for item in self.itemList:
674
- if item.catID != lastCat:
675
- lastCat = item.catID
676
- txt += (" + {}\n".format(self.categories[lastCat].dbname))
677
-
678
- row = self.itemDisplays[item.displayNo]
679
- rowvals = [ val[1].get() for val in row ]
680
-
681
- itemName = item.name
682
- paying = int(rowvals[0] or 0)
683
- asking = int(rowvals[1] or 0)
684
- demand = rowvals[2]
685
- supply = rowvals[3]
686
-
687
- if not paying and not asking:
688
- demand, supply = "-", "-"
689
- else:
690
- if paying and not demand:
691
- demand = "?"
692
-
693
- if asking == 0:
694
- supply = "-"
695
- elif not supply:
696
- supply = "?"
697
- elif re.match(r"^\d+$", supply):
698
- if int(supply) != 0:
699
- supply += '?'
700
-
701
- txt += (" {item:<30s} "
702
- "{paying:>10} "
703
- "{asking:>10} "
704
- "{demand:>10} "
705
- "{supply:>10}\n".format(
706
- item=itemName,
707
- paying=paying,
708
- asking=asking,
709
- demand=demand,
710
- supply=supply
711
- ))
712
- self.results = txt
713
-
714
-
715
- def render(tdb, tdenv, tmpPath):
716
- parent = tk.Tk()
717
- gui = UpdateGUI(parent, tdb, tdenv)
718
- gui.mainloop()
719
- gui.getResults()
720
- with tmpPath.open("w", encoding="utf-8") as fh:
721
- print(gui.results, file=fh)