tradedangerous 11.0.2__py3-none-any.whl → 11.0.4__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 +9 -9
- tradedangerous/cli.py +8 -7
- tradedangerous/commands/parsing.py +4 -4
- tradedangerous/csvexport.py +1 -0
- tradedangerous/formatting.py +7 -6
- tradedangerous/misc/edsc.py +1 -13
- tradedangerous/misc/edsm.py +1 -13
- tradedangerous/plugins/eddblink_plug.py +152 -158
- tradedangerous/plugins/spansh_plug.py +17 -14
- tradedangerous/submit-distances.py +1 -24
- tradedangerous/transfers.py +5 -75
- tradedangerous/version.py +1 -1
- {tradedangerous-11.0.2.dist-info → tradedangerous-11.0.4.dist-info}/METADATA +1 -1
- {tradedangerous-11.0.2.dist-info → tradedangerous-11.0.4.dist-info}/RECORD +18 -18
- {tradedangerous-11.0.2.dist-info → tradedangerous-11.0.4.dist-info}/LICENSE +0 -0
- {tradedangerous-11.0.2.dist-info → tradedangerous-11.0.4.dist-info}/WHEEL +0 -0
- {tradedangerous-11.0.2.dist-info → tradedangerous-11.0.4.dist-info}/entry_points.txt +0 -0
- {tradedangerous-11.0.2.dist-info → tradedangerous-11.0.4.dist-info}/top_level.txt +0 -0
tradedangerous/cache.py
CHANGED
|
@@ -206,7 +206,7 @@ class MultipleItemEntriesError(DuplicateKeyError):
|
|
|
206
206
|
super().__init__(fromFile, lineNo, 'item', item, prevLineNo)
|
|
207
207
|
|
|
208
208
|
|
|
209
|
-
class
|
|
209
|
+
class InvalidLineError(BuildCacheBaseException):
|
|
210
210
|
"""
|
|
211
211
|
Raised when an invalid line is read.
|
|
212
212
|
Attributes:
|
|
@@ -258,7 +258,7 @@ def parseSupply(pricesFile: Path, lineNo: int, category: str, reading: str) -> t
|
|
|
258
258
|
# High <- 'H';
|
|
259
259
|
if reading == '?':
|
|
260
260
|
return -1, -1
|
|
261
|
-
|
|
261
|
+
if reading == '-':
|
|
262
262
|
return 0, 0
|
|
263
263
|
|
|
264
264
|
# extract the left most digits into unit and the last character into the level reading.
|
|
@@ -604,13 +604,13 @@ def processPrices(tdenv: TradeEnv, priceFile: Path, db: sqlite3.Connection, defa
|
|
|
604
604
|
if text.startswith('@'):
|
|
605
605
|
matches = systemStationRe.match(text)
|
|
606
606
|
if not matches:
|
|
607
|
-
raise
|
|
607
|
+
raise InvalidLineError(priceFile, lineNo, "Unrecognized '@' line", text)
|
|
608
608
|
changeStation(matches)
|
|
609
609
|
continue
|
|
610
610
|
|
|
611
611
|
if not stationID:
|
|
612
612
|
# Need a station to process any other type of line.
|
|
613
|
-
raise
|
|
613
|
+
raise InvalidLineError(priceFile, lineNo, "Expecting '@ SYSTEM / Station' line", text)
|
|
614
614
|
if stationID == DELETED:
|
|
615
615
|
# Ignore all values from a deleted station/system.
|
|
616
616
|
continue
|
|
@@ -625,7 +625,7 @@ def processPrices(tdenv: TradeEnv, priceFile: Path, db: sqlite3.Connection, defa
|
|
|
625
625
|
# ## "Item sell buy ..." lines.
|
|
626
626
|
matches = newItemPriceRe.match(text)
|
|
627
627
|
if not matches:
|
|
628
|
-
raise
|
|
628
|
+
raise InvalidLineError(priceFile, lineNo, "Unrecognized line/syntax", text)
|
|
629
629
|
|
|
630
630
|
processItemLine(matches)
|
|
631
631
|
|
|
@@ -639,7 +639,7 @@ def processPrices(tdenv: TradeEnv, priceFile: Path, db: sqlite3.Connection, defa
|
|
|
639
639
|
"if you /need/ to persist them."
|
|
640
640
|
)
|
|
641
641
|
|
|
642
|
-
stations = tuple((ID,) for ID in processedStations
|
|
642
|
+
stations = tuple((ID,) for ID in processedStations)
|
|
643
643
|
return stations, items, zeros, newItems, updtItems, ignItems, numSys
|
|
644
644
|
|
|
645
645
|
|
|
@@ -649,9 +649,9 @@ def processPrices(tdenv: TradeEnv, priceFile: Path, db: sqlite3.Connection, defa
|
|
|
649
649
|
def processPricesFile(tdenv: TradeEnv, db: sqlite3.Connection, pricesPath: Path, pricesFh: Optional[TextIO] = None, defaultZero: bool = False) -> None:
|
|
650
650
|
tdenv.DEBUG0("Processing Prices file '{}'", pricesPath)
|
|
651
651
|
|
|
652
|
-
with pricesFh or pricesPath.open('r', encoding='utf-8') as
|
|
652
|
+
with (pricesFh or pricesPath.open('r', encoding='utf-8')) as fh:
|
|
653
653
|
stations, items, zeros, newItems, updtItems, ignItems, numSys = processPrices(
|
|
654
|
-
tdenv,
|
|
654
|
+
tdenv, fh, db, defaultZero
|
|
655
655
|
)
|
|
656
656
|
|
|
657
657
|
if not tdenv.mergeImport:
|
|
@@ -907,7 +907,7 @@ def processImportFile(tdenv, db, importPath, tableName):
|
|
|
907
907
|
try:
|
|
908
908
|
db.execute(sql_stmt, linein)
|
|
909
909
|
importCount += 1
|
|
910
|
-
except Exception as e:
|
|
910
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
911
911
|
tdenv.WARN(
|
|
912
912
|
"*** INTERNAL ERROR: {err}\n"
|
|
913
913
|
"CSV File: {file}:{line}\n"
|
tradedangerous/cli.py
CHANGED
|
@@ -32,34 +32,35 @@
|
|
|
32
32
|
# to empower other programmers to do cool stuff.
|
|
33
33
|
|
|
34
34
|
import os
|
|
35
|
+
import sys
|
|
35
36
|
import traceback
|
|
36
37
|
|
|
37
38
|
from . import commands
|
|
39
|
+
from . import tradeexcept
|
|
38
40
|
from .commands import exceptions
|
|
39
41
|
from .plugins import PluginException
|
|
40
42
|
|
|
41
|
-
|
|
42
43
|
from . import tradedb
|
|
43
44
|
|
|
45
|
+
if "CPROF" in os.environ:
|
|
46
|
+
import cProfile
|
|
47
|
+
|
|
44
48
|
|
|
45
49
|
def main(argv = None):
|
|
46
|
-
import sys
|
|
47
50
|
if not argv:
|
|
48
51
|
argv = sys.argv
|
|
49
|
-
if sys.hexversion <
|
|
52
|
+
if sys.hexversion < 0x03070000:
|
|
50
53
|
raise SystemExit(
|
|
51
|
-
"Sorry: TradeDangerous requires Python 3.
|
|
54
|
+
"Sorry: TradeDangerous requires Python 3.7 or higher.\n"
|
|
52
55
|
"For assistance, see:\n"
|
|
53
56
|
"\tBug Tracker: https://github.com/eyeonus/Trade-Dangerous/issues\n"
|
|
54
57
|
"\tDocumentation: https://github.com/eyeonus/Trade-Dangerous/wiki\n"
|
|
55
58
|
"\tEDForum Thread: https://forums.frontier.co.uk/showthread.php/441509\n"
|
|
56
59
|
)
|
|
57
|
-
from . import tradeexcept
|
|
58
60
|
|
|
59
61
|
try:
|
|
60
62
|
try:
|
|
61
63
|
if "CPROF" in os.environ:
|
|
62
|
-
import cProfile
|
|
63
64
|
cProfile.run("trade(argv)")
|
|
64
65
|
else:
|
|
65
66
|
trade(argv)
|
|
@@ -79,7 +80,7 @@ def main(argv = None):
|
|
|
79
80
|
print()
|
|
80
81
|
print(traceback.format_exc())
|
|
81
82
|
print(
|
|
82
|
-
"Please report this bug (http://
|
|
83
|
+
"Please report this bug (http://github.com/eyeonus/Trade-Dangerous/issues). You may be "
|
|
83
84
|
"able to work around it by using the '-q' parameter. Windows "
|
|
84
85
|
"users may be able to use 'chcp.com 65001' to tell the console "
|
|
85
86
|
"you want to support UTF-8 characters."
|
|
@@ -60,7 +60,7 @@ class PadSizeArgument(int):
|
|
|
60
60
|
'dest': 'padSize',
|
|
61
61
|
'metavar': 'PADSIZES',
|
|
62
62
|
'type': 'padsize',
|
|
63
|
-
'choices': '
|
|
63
|
+
'choices': 'SsMmLl?',
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
|
|
@@ -153,7 +153,7 @@ class PlanetaryArgument(int):
|
|
|
153
153
|
'dest': 'planetary',
|
|
154
154
|
'metavar': 'PLANETARY',
|
|
155
155
|
'type': 'planetary',
|
|
156
|
-
'choices': '
|
|
156
|
+
'choices': 'YyNn?',
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
|
|
@@ -181,7 +181,7 @@ class FleetCarrierArgument(int):
|
|
|
181
181
|
'dest': 'fleet',
|
|
182
182
|
'metavar': 'FLEET',
|
|
183
183
|
'type': 'fleet',
|
|
184
|
-
'choices': '
|
|
184
|
+
'choices': 'YyNn?',
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
class OdysseyArgument(int):
|
|
@@ -208,7 +208,7 @@ class OdysseyArgument(int):
|
|
|
208
208
|
'dest': 'odyssey',
|
|
209
209
|
'metavar': 'ODYSSEY',
|
|
210
210
|
'type': 'odyssey',
|
|
211
|
-
'choices': '
|
|
211
|
+
'choices': 'YyNn?',
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
|
tradedangerous/csvexport.py
CHANGED
tradedangerous/formatting.py
CHANGED
|
@@ -8,7 +8,9 @@ import itertools
|
|
|
8
8
|
import typing
|
|
9
9
|
|
|
10
10
|
if typing.TYPE_CHECKING:
|
|
11
|
-
from typing import Any,
|
|
11
|
+
from typing import Any, Optional
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
class ColumnFormat:
|
|
14
16
|
"""
|
|
@@ -197,8 +199,7 @@ if __name__ == '__main__':
|
|
|
197
199
|
print("Simple usage:")
|
|
198
200
|
present()
|
|
199
201
|
|
|
200
|
-
print()
|
|
201
|
-
print("Adding age ColumnFormat:")
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
present()
|
|
202
|
+
#print()
|
|
203
|
+
#print("Adding age ColumnFormat:")
|
|
204
|
+
#rowFmt.append(after='Name', col=ColumnFormat("Age", '>', 3, pre='|', post='|', key=lambda row: row['age']))
|
|
205
|
+
#present()
|
tradedangerous/misc/edsc.py
CHANGED
|
@@ -4,19 +4,7 @@ from collections import namedtuple
|
|
|
4
4
|
from urllib.request import Request, urlopen
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
|
-
|
|
8
|
-
try:
|
|
9
|
-
import requests
|
|
10
|
-
except ImportError as e:
|
|
11
|
-
import pip
|
|
12
|
-
print("ERROR: Unable to load the Python 'requests' package.")
|
|
13
|
-
approval = input(
|
|
14
|
-
"Do you want me to try and install it with the package manager (y/n)? "
|
|
15
|
-
)
|
|
16
|
-
if approval.lower() != 'y':
|
|
17
|
-
raise e
|
|
18
|
-
pip.main(["install", "--upgrade", "requests"])
|
|
19
|
-
import requests
|
|
7
|
+
import requests
|
|
20
8
|
|
|
21
9
|
|
|
22
10
|
def edsc_log(apiCall, params, jsonData=None, error=None):
|
tradedangerous/misc/edsm.py
CHANGED
|
@@ -6,19 +6,7 @@ uses EDSM - https://www.edsm.net/api
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
|
-
|
|
10
|
-
try:
|
|
11
|
-
import requests
|
|
12
|
-
except ImportError as e:
|
|
13
|
-
import pip
|
|
14
|
-
print("ERROR: Unable to load the Python 'requests' package.")
|
|
15
|
-
approval = input(
|
|
16
|
-
"Do you want me to try and install it with the package manager (y/n)? "
|
|
17
|
-
)
|
|
18
|
-
if approval.lower() != 'y':
|
|
19
|
-
raise e
|
|
20
|
-
pip.main(["install", "--upgrade", "requests"])
|
|
21
|
-
import requests
|
|
9
|
+
import requests
|
|
22
10
|
|
|
23
11
|
|
|
24
12
|
def edsm_log(apiCall, url, params, jsonData=None, error=None):
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"""
|
|
2
|
+
Import plugin that uses data files from
|
|
3
|
+
https://elite.tromador.com/ to update the Database.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
5
6
|
import certifi
|
|
6
7
|
import csv
|
|
7
8
|
import datetime
|
|
@@ -10,42 +11,48 @@ import os
|
|
|
10
11
|
import sqlite3
|
|
11
12
|
import ssl
|
|
12
13
|
import time
|
|
14
|
+
import typing
|
|
13
15
|
|
|
14
16
|
from urllib import request
|
|
15
|
-
from calendar import timegm
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
|
|
18
19
|
from .. import plugins, cache, transfers
|
|
19
20
|
from ..misc import progress as pbar
|
|
20
21
|
from ..plugins import PluginException
|
|
21
22
|
|
|
23
|
+
|
|
24
|
+
if typing.TYPE_CHECKING:
|
|
25
|
+
from typing import Optional
|
|
26
|
+
from .. tradeenv import TradeEnv
|
|
27
|
+
|
|
28
|
+
|
|
22
29
|
# Constants
|
|
23
30
|
BASE_URL = os.environ.get('TD_SERVER') or "https://elite.tromador.com/files/"
|
|
24
31
|
CONTEXT=ssl.create_default_context(cafile=certifi.where())
|
|
25
32
|
|
|
26
33
|
|
|
27
|
-
def
|
|
34
|
+
def _request_url(url, headers=None):
|
|
28
35
|
data = None
|
|
29
36
|
if headers:
|
|
30
37
|
data = bytes(json.dumps(headers), encoding="utf-8")
|
|
31
38
|
|
|
32
|
-
return request.urlopen(request.Request(url, data=data), context=CONTEXT)
|
|
39
|
+
return request.urlopen(request.Request(url, data=data), context=CONTEXT, timeout=90)
|
|
33
40
|
|
|
34
41
|
|
|
35
42
|
class DecodingError(PluginException):
|
|
36
43
|
pass
|
|
37
44
|
|
|
38
45
|
|
|
39
|
-
def
|
|
46
|
+
def _file_line_count(from_file: Path, bufsize: int = 128 * 1024) -> int:
|
|
40
47
|
""" counts the number of newline characters in a given file. """
|
|
41
|
-
# Pre-allocate a buffer so we'
|
|
42
|
-
# capture it's counting method so we don't have to keep looking that up on
|
|
43
|
-
# large files.
|
|
48
|
+
# Pre-allocate a buffer so we aren't putting pressure on the garbage collector.
|
|
44
49
|
buf = bytearray(bufsize)
|
|
50
|
+
|
|
51
|
+
# Capture it's counting method, so we don't have to keep looking that up on
|
|
52
|
+
# large files.
|
|
45
53
|
counter = buf.count
|
|
46
|
-
|
|
54
|
+
|
|
47
55
|
total = 0
|
|
48
|
-
|
|
49
56
|
with from_file.open("rb") as fh:
|
|
50
57
|
# Capture the 'readinto' method to avoid lookups.
|
|
51
58
|
reader = fh.readinto
|
|
@@ -60,10 +67,46 @@ def file_line_count(from_file: Path, bufsize: int = 128 * 1024) -> int:
|
|
|
60
67
|
# when 0 <= read < bufsize we're on the last page of the
|
|
61
68
|
# file, so we need to take a slice of the buffer, which creates
|
|
62
69
|
# a new object and thus we also have to lookup count. it's trivial
|
|
63
|
-
# but if you have to do it 10,000x it's
|
|
70
|
+
# but if you have to do it 10,000x it's definitely not a rounding error.
|
|
64
71
|
return total + buf[:read].count(b'\n')
|
|
65
72
|
|
|
66
73
|
|
|
74
|
+
def _count_listing_entries(tdenv: TradeEnv, listings: Path) -> int:
|
|
75
|
+
""" Calculates the number of entries in a listing file by counting the lines. """
|
|
76
|
+
if not listings.exists():
|
|
77
|
+
tdenv.NOTE("File not found, aborting: {}", listings)
|
|
78
|
+
return 0
|
|
79
|
+
|
|
80
|
+
tdenv.DEBUG0(f"Getting total number of entries in {listings}...")
|
|
81
|
+
count = _file_line_count(listings)
|
|
82
|
+
if count <= 1:
|
|
83
|
+
if count == 1:
|
|
84
|
+
tdenv.DEBUG0("Listing count of 1 suggests nothing but a header")
|
|
85
|
+
else:
|
|
86
|
+
tdenv.DEBUG0("Listings file is empty, nothing to do.")
|
|
87
|
+
return 0
|
|
88
|
+
|
|
89
|
+
return count + 1 # kfsone: Doesn't the header already make this + 1?
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _make_item_id_lookup(tdenv: TradeEnv, db: sqlite3.Cursor) -> frozenset[int]:
|
|
93
|
+
""" helper: retrieve the list of commodities in database. """
|
|
94
|
+
tdenv.DEBUG0("Getting list of commodities...")
|
|
95
|
+
return frozenset(cols[0] for cols in db.execute("SELECT item_id FROM Item"))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _make_station_id_lookup(tdenv: TradeEnv, db: sqlite3.Cursor) -> frozenset[int]:
|
|
99
|
+
""" helper: retrieve the list of station IDs in database. """
|
|
100
|
+
tdenv.DEBUG0("Getting list of stations...")
|
|
101
|
+
return frozenset(cols[0] for cols in db.execute("SELECT station_id FROM Station"))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _collect_station_modified_times(tdenv: TradeEnv, db: sqlite3.Cursor) -> dict[int, int]:
|
|
105
|
+
""" helper: build a list of the last modified time for all stations by id. """
|
|
106
|
+
tdenv.DEBUG0("Getting last-update times for stations...")
|
|
107
|
+
return dict(db.execute("SELECT station_id, strftime('%s', MIN(modified)) FROM StationItem GROUP BY station_id"))
|
|
108
|
+
|
|
109
|
+
|
|
67
110
|
class ImportPlugin(plugins.ImportPluginBase):
|
|
68
111
|
"""
|
|
69
112
|
Plugin that downloads data from eddb.
|
|
@@ -113,61 +156,25 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
113
156
|
def now(self):
|
|
114
157
|
return datetime.datetime.now()
|
|
115
158
|
|
|
116
|
-
def execute(self, sql_cmd, args = None):
|
|
117
|
-
cur = self.tdb.getDB().cursor()
|
|
118
|
-
|
|
119
|
-
self.tdenv.DEBUG2(f"SQL-Statement:\n'{sql_cmd},{args}'")
|
|
120
|
-
success = False
|
|
121
|
-
result = None
|
|
122
|
-
while not success:
|
|
123
|
-
try:
|
|
124
|
-
if args:
|
|
125
|
-
result = cur.execute(sql_cmd, args)
|
|
126
|
-
else:
|
|
127
|
-
result = cur.execute(sql_cmd)
|
|
128
|
-
success = True
|
|
129
|
-
except sqlite3.OperationalError as e:
|
|
130
|
-
if "locked" not in str(e):
|
|
131
|
-
success = True
|
|
132
|
-
raise sqlite3.OperationalError(e)
|
|
133
|
-
else:
|
|
134
|
-
print("(execute) Database is locked, waiting for access.", end = "\r")
|
|
135
|
-
time.sleep(1)
|
|
136
|
-
return result
|
|
137
|
-
|
|
138
|
-
@staticmethod
|
|
139
|
-
def fetchIter(cursor, arraysize = 1000):
|
|
140
|
-
"""
|
|
141
|
-
An iterator that uses fetchmany to keep memory usage down
|
|
142
|
-
and speed up the time to retrieve the results dramatically.
|
|
143
|
-
"""
|
|
144
|
-
while True:
|
|
145
|
-
results = cursor.fetchmany(arraysize)
|
|
146
|
-
if not results:
|
|
147
|
-
break
|
|
148
|
-
for result in results:
|
|
149
|
-
yield result
|
|
150
|
-
|
|
151
|
-
|
|
152
159
|
def downloadFile(self, path):
|
|
153
160
|
"""
|
|
154
161
|
Fetch the latest dumpfile from the website if newer than local copy.
|
|
155
162
|
"""
|
|
156
163
|
|
|
157
164
|
def openURL(url):
|
|
158
|
-
return
|
|
165
|
+
return _request_url(url, headers = {'User-Agent': 'Trade-Dangerous'})
|
|
159
166
|
|
|
160
|
-
if path
|
|
161
|
-
localPath = self.tdb.dataPath
|
|
167
|
+
if path not in (self.liveListingsPath, self.listingsPath):
|
|
168
|
+
localPath = Path(self.tdb.dataPath, path)
|
|
162
169
|
else:
|
|
163
|
-
localPath = self.dataPath
|
|
170
|
+
localPath = Path(self.dataPath, path)
|
|
164
171
|
|
|
165
172
|
url = BASE_URL + str(path)
|
|
166
173
|
|
|
167
174
|
self.tdenv.NOTE("Checking for update to '{}'.", path)
|
|
168
175
|
try:
|
|
169
176
|
response = openURL(url)
|
|
170
|
-
except Exception as e:
|
|
177
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
171
178
|
self.tdenv.WARN("Problem with download:\n URL: {}\n Error: {}", BASE_URL + str(path), str(e))
|
|
172
179
|
return False
|
|
173
180
|
|
|
@@ -190,148 +197,137 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
190
197
|
Purges systems from the System table that do not have any stations claiming to be in them.
|
|
191
198
|
Keeps table from becoming too large because of fleet carriers moving to unpopulated systems.
|
|
192
199
|
"""
|
|
193
|
-
|
|
200
|
+
db = self.tdb.getDB()
|
|
194
201
|
self.tdenv.NOTE("Purging Systems with no stations: Start time = {}", self.now())
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
202
|
+
|
|
203
|
+
db.execute("PRAGMA foreign_keys = OFF")
|
|
204
|
+
|
|
205
|
+
self.tdenv.DEBUG0("Saving systems with stations.... " + str(self.now()) + "\t\t\t\t", end="\r")
|
|
206
|
+
db.execute("DROP TABLE IF EXISTS System_copy")
|
|
207
|
+
db.execute("""CREATE TABLE System_copy AS SELECT * FROM System
|
|
201
208
|
WHERE system_id IN (SELECT system_id FROM Station)
|
|
202
209
|
""")
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
|
|
211
|
+
self.tdenv.DEBUG0("Erasing table and reinserting kept systems.... " + str(self.now()) + "\t\t\t\t", end="\r")
|
|
212
|
+
db.execute("DELETE FROM System")
|
|
213
|
+
db.execute("INSERT INTO System SELECT * FROM System_copy")
|
|
214
|
+
|
|
215
|
+
self.tdenv.DEBUG0("Removing copy.... " + str(self.now()) + "\t\t\t\t", end="\r")
|
|
216
|
+
db.execute("PRAGMA foreign_keys = ON")
|
|
217
|
+
db.execute("DROP TABLE IF EXISTS System_copy")
|
|
218
|
+
|
|
219
|
+
db.commit()
|
|
220
|
+
|
|
212
221
|
self.tdenv.NOTE("Finished purging Systems. End time = {}", self.now())
|
|
213
222
|
|
|
214
|
-
def commit(self):
|
|
215
|
-
success = False
|
|
216
|
-
while not success:
|
|
217
|
-
try:
|
|
218
|
-
self.tdb.getDB().commit()
|
|
219
|
-
success = True
|
|
220
|
-
except sqlite3.OperationalError:
|
|
221
|
-
print("(commit) Database is locked, waiting for access.", end = "\r")
|
|
222
|
-
time.sleep(1)
|
|
223
|
-
|
|
224
223
|
def importListings(self, listings_file):
|
|
225
224
|
"""
|
|
226
|
-
Updates the market data (AKA the StationItem table) using
|
|
225
|
+
Updates the market data (AKA the StationItem table) using listings_file
|
|
227
226
|
Writes directly to database.
|
|
228
227
|
"""
|
|
228
|
+
listings_path = Path(self.dataPath, listings_file).absolute()
|
|
229
|
+
from_live = listings_path != Path(self.dataPath, self.listingsPath).absolute()
|
|
230
|
+
self.tdenv.NOTE("Processing market data from {}: Start time = {}. Live = {}", listings_file, self.now(), from_live)
|
|
229
231
|
|
|
230
|
-
self.tdenv
|
|
231
|
-
if not
|
|
232
|
-
self.tdenv.NOTE("File not found, aborting: {}", (self.dataPath / listings_file))
|
|
232
|
+
total = _count_listing_entries(self.tdenv, listings_path)
|
|
233
|
+
if not total:
|
|
233
234
|
return
|
|
235
|
+
|
|
236
|
+
stmt_unliven_station = """UPDATE StationItem SET from_live = 0 WHERE station_id = ?"""
|
|
237
|
+
stmt_flush_station = """DELETE from StationItem WHERE station_id = ?"""
|
|
238
|
+
stmt_add_listing = """
|
|
239
|
+
INSERT OR IGNORE INTO StationItem (
|
|
240
|
+
station_id, item_id, modified, from_live,
|
|
241
|
+
demand_price, demand_units, demand_level,
|
|
242
|
+
supply_price, supply_units, supply_level
|
|
243
|
+
)
|
|
244
|
+
VALUES (
|
|
245
|
+
?, ?, datetime(?, 'unixepoch'), ?,
|
|
246
|
+
?, ?, ?,
|
|
247
|
+
?, ?, ?
|
|
248
|
+
)
|
|
249
|
+
"""
|
|
234
250
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
self.tdenv.
|
|
240
|
-
listings_path = Path(self.dataPath, listings_file)
|
|
241
|
-
total += file_line_count(listings_path)
|
|
242
|
-
|
|
243
|
-
liveStmt = """UPDATE StationItem
|
|
244
|
-
SET from_live = 0
|
|
245
|
-
WHERE station_id = ?"""
|
|
246
|
-
|
|
247
|
-
delStmt = "DELETE from StationItem WHERE station_id = ?"
|
|
248
|
-
|
|
249
|
-
listingStmt = """INSERT OR IGNORE INTO StationItem
|
|
250
|
-
(station_id, item_id, modified,
|
|
251
|
-
demand_price, demand_units, demand_level,
|
|
252
|
-
supply_price, supply_units, supply_level, from_live)
|
|
253
|
-
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"""
|
|
254
|
-
|
|
255
|
-
self.tdenv.DEBUG0("Getting list of commodities...")
|
|
256
|
-
items = [cols[0] for cols in self.execute("SELECT item_id FROM Item ORDER BY item_id")]
|
|
257
|
-
|
|
258
|
-
self.tdenv.DEBUG0("Getting list of stations...")
|
|
259
|
-
stationList = {
|
|
260
|
-
stationID
|
|
261
|
-
for (stationID,) in self.execute("SELECT station_id FROM Station")
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
stationItems = dict(self.execute('SELECT station_id, UNIXEPOCH(modified) FROM StationItem').fetchall())
|
|
251
|
+
# Fetch all the items IDS
|
|
252
|
+
db = self.tdb.getDB()
|
|
253
|
+
item_lookup = _make_item_id_lookup(self.tdenv, db.cursor())
|
|
254
|
+
station_lookup = _make_station_id_lookup(self.tdenv, db.cursor())
|
|
255
|
+
last_station_update_times = _collect_station_modified_times(self.tdenv, db.cursor())
|
|
265
256
|
|
|
257
|
+
cur_station = None
|
|
266
258
|
self.tdenv.DEBUG0("Processing entries...")
|
|
267
259
|
with listings_path.open("r", encoding="utf-8", errors="ignore") as fh:
|
|
268
260
|
prog = pbar.Progress(total, 50)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
cur_station = -1
|
|
261
|
+
|
|
262
|
+
cursor: Optional[sqlite3.Cursor] = db.cursor()
|
|
272
263
|
|
|
273
|
-
for listing in
|
|
274
|
-
|
|
275
|
-
# Do a commit and close the DB every 2%.
|
|
276
|
-
# This ensures the listings are put in the DB and the WAL is cleared.
|
|
277
|
-
self.commit()
|
|
278
|
-
self.tdb.close()
|
|
264
|
+
for listing in csv.DictReader(fh):
|
|
265
|
+
prog.increment(1, postfix = lambda value, total: f" {(value / total * 100):.0f}% {value} / {total}")
|
|
279
266
|
|
|
280
267
|
station_id = int(listing['station_id'])
|
|
281
|
-
if station_id not in
|
|
268
|
+
if station_id not in station_lookup:
|
|
282
269
|
continue
|
|
283
270
|
|
|
271
|
+
listing_time = int(listing['collected_at'])
|
|
272
|
+
|
|
284
273
|
if station_id != cur_station:
|
|
285
|
-
|
|
286
|
-
|
|
274
|
+
# commit anything from the previous station, get a new cursor
|
|
275
|
+
db.commit()
|
|
276
|
+
cur_station, skip_station, cursor = station_id, False, db.cursor()
|
|
287
277
|
|
|
288
278
|
# Check if listing already exists in DB and needs updated.
|
|
289
|
-
|
|
279
|
+
last_modified: int = int(last_station_update_times.get(station_id, 0))
|
|
280
|
+
if last_modified:
|
|
290
281
|
# When the listings.csv data matches the database, update to make from_live == 0.
|
|
291
|
-
if
|
|
292
|
-
self.tdenv.DEBUG1(f"Marking {cur_station} as no longer 'live'.")
|
|
293
|
-
|
|
282
|
+
if listing_time == last_modified and not from_live:
|
|
283
|
+
self.tdenv.DEBUG1(f"Marking {cur_station} as no longer 'live' (old={last_modified}, listing={listing_time}).")
|
|
284
|
+
cursor.execute(stmt_unliven_station, (cur_station,))
|
|
285
|
+
skip_station = True
|
|
286
|
+
continue
|
|
287
|
+
|
|
294
288
|
# Unless the import file data is newer, nothing else needs to be done for this station,
|
|
295
289
|
# so the rest of the listings for this station can be skipped.
|
|
296
|
-
if
|
|
297
|
-
|
|
290
|
+
if listing_time <= last_modified:
|
|
291
|
+
skip_station = True
|
|
298
292
|
continue
|
|
299
293
|
|
|
300
294
|
# The data from the import file is newer, so we need to delete the old data for this station.
|
|
301
|
-
self.tdenv.DEBUG1(f"Deleting old listing data for {cur_station}.")
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
del stationItems[station_id]
|
|
305
|
-
|
|
295
|
+
self.tdenv.DEBUG1(f"Deleting old listing data for {cur_station} (old={last_modified}, listing={listing_time}).")
|
|
296
|
+
cursor.execute(stmt_flush_station, (cur_station,))
|
|
297
|
+
last_station_update_times[station_id] = listing_time
|
|
306
298
|
|
|
307
|
-
|
|
299
|
+
# station skip lasts until we change station id.
|
|
300
|
+
if skip_station:
|
|
308
301
|
continue
|
|
309
302
|
|
|
310
303
|
# Since this station is not being skipped, get the data and prepare for insertion into the DB.
|
|
311
304
|
item_id = int(listing['commodity_id'])
|
|
312
305
|
# listings.csv includes rare items, which we are ignoring.
|
|
313
|
-
if item_id not in
|
|
306
|
+
if item_id not in item_lookup:
|
|
314
307
|
continue
|
|
315
|
-
|
|
308
|
+
|
|
316
309
|
demand_price = int(listing['sell_price'])
|
|
317
310
|
demand_units = int(listing['demand'])
|
|
318
|
-
demand_level = int(listing
|
|
311
|
+
demand_level = int(listing.get('demand_bracket') or '-1')
|
|
319
312
|
supply_price = int(listing['buy_price'])
|
|
320
313
|
supply_units = int(listing['supply'])
|
|
321
|
-
supply_level = int(listing
|
|
314
|
+
supply_level = int(listing.get('supply_bracket') or '-1')
|
|
322
315
|
|
|
323
316
|
self.tdenv.DEBUG1(f"Inserting new listing data for {station_id}.")
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
317
|
+
cursor.execute(stmt_add_listing, (
|
|
318
|
+
station_id, item_id, listing_time, from_live,
|
|
319
|
+
demand_price, demand_units, demand_level,
|
|
320
|
+
supply_price, supply_units, supply_level,
|
|
321
|
+
))
|
|
327
322
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
323
|
+
prog.clear()
|
|
324
|
+
|
|
325
|
+
# Do a final commit to be sure
|
|
326
|
+
db.commit()
|
|
327
|
+
|
|
328
|
+
self.tdenv.NOTE("Optimizing database...")
|
|
329
|
+
db.execute("VACUUM")
|
|
330
|
+
self.tdb.close()
|
|
335
331
|
|
|
336
332
|
self.tdenv.NOTE("Finished processing market data. End time = {}", self.now())
|
|
337
333
|
|
|
@@ -347,14 +343,13 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
347
343
|
# have been passed, enable 'listings'.
|
|
348
344
|
default = True
|
|
349
345
|
for option in self.options:
|
|
350
|
-
|
|
351
|
-
if option not in ('force', 'skipvend'):
|
|
346
|
+
if option not in ('force', 'skipvend', 'purge'):
|
|
352
347
|
default = False
|
|
353
348
|
if default:
|
|
354
349
|
self.options["listings"] = True
|
|
355
350
|
|
|
356
|
-
# We can probably safely assume that the plugin
|
|
357
|
-
# the
|
|
351
|
+
# We can probably safely assume that the plugin
|
|
352
|
+
# has never been run if the db file doesn't exist.
|
|
358
353
|
if not (self.tdb.dataPath / Path("TradeDangerous.db")).exists():
|
|
359
354
|
self.options["clean"] = True
|
|
360
355
|
|
|
@@ -497,7 +492,6 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
497
492
|
|
|
498
493
|
if self.getOption("purge"):
|
|
499
494
|
self.purgeSystems()
|
|
500
|
-
# self.commit()
|
|
501
495
|
|
|
502
496
|
if self.getOption("listings"):
|
|
503
497
|
if self.downloadFile(self.listingsPath) or self.getOption("force"):
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
+
""" Plugin for importing data from spansh """
|
|
1
2
|
from __future__ import annotations
|
|
2
3
|
|
|
4
|
+
from collections import namedtuple
|
|
3
5
|
from contextlib import contextmanager
|
|
4
6
|
from datetime import datetime, timedelta
|
|
5
7
|
from pathlib import Path
|
|
8
|
+
from rich.progress import Progress
|
|
6
9
|
|
|
10
|
+
from .. import plugins, cache, transfers, csvexport, corrections
|
|
11
|
+
|
|
12
|
+
import sqlite3
|
|
7
13
|
import sys
|
|
8
14
|
import time
|
|
9
15
|
import typing
|
|
10
|
-
|
|
16
|
+
|
|
17
|
+
import ijson
|
|
18
|
+
|
|
11
19
|
if sys.version_info.major == 3 and sys.version_info.minor >= 10:
|
|
12
20
|
from dataclasses import dataclass
|
|
13
21
|
else:
|
|
14
22
|
dataclass = False # pylint: disable=invalid-name
|
|
15
23
|
|
|
16
|
-
from rich.progress import Progress
|
|
17
|
-
import ijson
|
|
18
|
-
import sqlite3
|
|
19
|
-
|
|
20
|
-
from .. import plugins, cache, transfers, csvexport, corrections
|
|
21
|
-
|
|
22
24
|
if typing.TYPE_CHECKING:
|
|
23
|
-
from typing import Any,
|
|
25
|
+
from typing import Any, Optional
|
|
26
|
+
from collections.abc import Iterable
|
|
24
27
|
from .. tradeenv import TradeEnv
|
|
25
28
|
|
|
26
29
|
SOURCE_URL = 'https://downloads.spansh.co.uk/galaxy_stations.json'
|
|
@@ -237,11 +240,11 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
237
240
|
def commit(self, *, force: bool = False) -> None:
|
|
238
241
|
""" Perform a commit if required, but try not to do a crazy amount of committing. """
|
|
239
242
|
if not force and not self.need_commit:
|
|
240
|
-
return
|
|
243
|
+
return
|
|
241
244
|
|
|
242
245
|
if not force and self.commit_limit > 0:
|
|
243
246
|
self.commit_limit -= 1
|
|
244
|
-
return
|
|
247
|
+
return
|
|
245
248
|
|
|
246
249
|
db = self.tdb.getDB()
|
|
247
250
|
db.commit()
|
|
@@ -392,7 +395,7 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
392
395
|
categories.setdefault(commodity.category, []).append(commodity)
|
|
393
396
|
return categories
|
|
394
397
|
|
|
395
|
-
def execute(self, query: str, *params, commitable: bool = False) ->
|
|
398
|
+
def execute(self, query: str, *params, commitable: bool = False) -> sqlite3.Cursor:
|
|
396
399
|
""" helper method that performs retriable queries and marks the transaction as needing to commit
|
|
397
400
|
if the query is commitable."""
|
|
398
401
|
if commitable:
|
|
@@ -404,14 +407,14 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
404
407
|
except sqlite3.OperationalError as ex:
|
|
405
408
|
if "no transaction is active" in str(ex):
|
|
406
409
|
self.print(f"no transaction for {query}")
|
|
407
|
-
|
|
410
|
+
raise
|
|
408
411
|
if not attempts:
|
|
409
412
|
raise
|
|
410
413
|
attempts -= 1
|
|
411
414
|
self.print(f'Retrying query \'{query}\': {ex!s}')
|
|
412
415
|
time.sleep(1)
|
|
413
416
|
|
|
414
|
-
def executemany(self, query: str, data: Iterable[Any], *, commitable: bool = False) ->
|
|
417
|
+
def executemany(self, query: str, data: Iterable[Any], *, commitable: bool = False) -> sqlite3.Cursor:
|
|
415
418
|
""" helper method that performs retriable queries and marks the transaction as needing to commit
|
|
416
419
|
if the query is commitable."""
|
|
417
420
|
if commitable:
|
|
@@ -423,7 +426,7 @@ class ImportPlugin(plugins.ImportPluginBase):
|
|
|
423
426
|
except sqlite3.OperationalError as ex:
|
|
424
427
|
if "no transaction is active" in str(ex):
|
|
425
428
|
self.print(f"no transaction for {query}")
|
|
426
|
-
|
|
429
|
+
raise
|
|
427
430
|
if not attempts:
|
|
428
431
|
raise
|
|
429
432
|
attempts -= 1
|
|
@@ -16,6 +16,7 @@ import argparse
|
|
|
16
16
|
import os
|
|
17
17
|
import random
|
|
18
18
|
import re
|
|
19
|
+
import requests
|
|
19
20
|
import sys
|
|
20
21
|
import tradedb
|
|
21
22
|
import tradeenv
|
|
@@ -23,30 +24,6 @@ import tradeenv
|
|
|
23
24
|
from misc.edsc import StarSubmission, StarSubmissionResult, SubmissionError
|
|
24
25
|
from misc.clipboard import SystemNameClip
|
|
25
26
|
|
|
26
|
-
try:
|
|
27
|
-
import requests
|
|
28
|
-
except ImportError as e:
|
|
29
|
-
print("""ERROR: Unable to load the Python 'requests' package.
|
|
30
|
-
|
|
31
|
-
This script uses a Python module/package called 'requests' to allow
|
|
32
|
-
it to talk to the EDSC web service. This package is not installed
|
|
33
|
-
by default, but it can be installed with Python's package manager (pip).
|
|
34
|
-
|
|
35
|
-
You can either install/update it yourself, e.g.:
|
|
36
|
-
|
|
37
|
-
pip install --upgrade requests
|
|
38
|
-
|
|
39
|
-
or if you like, I can try and install it for you now
|
|
40
|
-
""")
|
|
41
|
-
approval = input(
|
|
42
|
-
"Do you want me to try and install it with the package manager (y/n)? "
|
|
43
|
-
)
|
|
44
|
-
if approval.lower() != 'y':
|
|
45
|
-
print("You didn't type 'y' so I'm giving up.")
|
|
46
|
-
raise e
|
|
47
|
-
import pip
|
|
48
|
-
pip.main(["install", "--upgrade", "requests"])
|
|
49
|
-
import requests # noqa: F401
|
|
50
27
|
|
|
51
28
|
standardStars = [
|
|
52
29
|
"SOL",
|
tradedangerous/transfers.py
CHANGED
|
@@ -1,82 +1,15 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
|
|
1
5
|
from collections import deque
|
|
2
6
|
from pathlib import Path
|
|
3
7
|
from .tradeexcept import TradeException
|
|
4
|
-
|
|
5
|
-
import csv
|
|
6
|
-
import json
|
|
7
8
|
from .misc import progress as pbar
|
|
8
|
-
import platform # noqa: F401
|
|
9
9
|
from . import fs
|
|
10
|
-
import time
|
|
11
|
-
import subprocess
|
|
12
|
-
import sys
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
import requests
|
|
16
|
-
__requests = requests
|
|
17
|
-
except ImportError:
|
|
18
|
-
__requests = None
|
|
11
|
+
import requests
|
|
19
12
|
|
|
20
|
-
def import_requests():
|
|
21
|
-
global __requests
|
|
22
|
-
if __requests:
|
|
23
|
-
return __requests
|
|
24
|
-
|
|
25
|
-
if platform.system() == 'Linux':
|
|
26
|
-
extra = (
|
|
27
|
-
"Ubuntu users: You may be able to install 'pip'\n"
|
|
28
|
-
"with 'apt-get install python3-pip' and requests with\n"
|
|
29
|
-
"'pip3 install --upgrade requests'.\n"
|
|
30
|
-
)
|
|
31
|
-
elif platform.system() == 'Windows':
|
|
32
|
-
extra = (
|
|
33
|
-
"\n\nThe requests package can be installed with\n"
|
|
34
|
-
"'pip3 install --upgrade requests'.\n\n"
|
|
35
|
-
"If requests is installed, you may have bits\n"
|
|
36
|
-
"of 32-bit and 64-bit Python installed.\n"
|
|
37
|
-
"Consider using control panel to uninstall Python,\n"
|
|
38
|
-
"delete the Python folder (usually C:\\Python34\\),\n"
|
|
39
|
-
"and then re-install Python.\n"
|
|
40
|
-
)
|
|
41
|
-
else:
|
|
42
|
-
extra = ""
|
|
43
|
-
|
|
44
|
-
print(
|
|
45
|
-
"ERROR: Unable to load the Python 'requests' package.\n" + extra
|
|
46
|
-
)
|
|
47
|
-
approval = input(
|
|
48
|
-
"I can try and install the package automatically using 'pip'.\n"
|
|
49
|
-
"Try to install 'requests' now (y/n)? "
|
|
50
|
-
)
|
|
51
|
-
# Idiot-proofing: take just the first character in case the user typed
|
|
52
|
-
# 'YES' (upper or lower case) instead of 'Y'.
|
|
53
|
-
if approval[0:1].lower() != 'y':
|
|
54
|
-
raise TradeException("Missing package: 'requests'")
|
|
55
|
-
|
|
56
|
-
try:
|
|
57
|
-
import pip # noqa: F401 # pylint: disable=unused-import
|
|
58
|
-
except ImportError as e:
|
|
59
|
-
raise TradeException(
|
|
60
|
-
"Python 3.4.2 includes a package manager called 'pip', "
|
|
61
|
-
"except it doesn't appear to be installed on your system:\n"
|
|
62
|
-
"{}{}".format(str(e), extra)
|
|
63
|
-
) from None
|
|
64
|
-
|
|
65
|
-
# Let's use "The most reliable approach, and the one that is fully supported."
|
|
66
|
-
# Especially since the old way produces an error for me on Python 3.6:
|
|
67
|
-
# "AttributeError: 'module' object has no attribute 'main'"
|
|
68
|
-
# pip.main(["install", "--upgrade", "requests"])
|
|
69
|
-
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'requests'])
|
|
70
|
-
|
|
71
|
-
try:
|
|
72
|
-
import requests # pylint: disable=redefined-outer-name
|
|
73
|
-
__requests = requests
|
|
74
|
-
except ImportError as e:
|
|
75
|
-
raise TradeException(
|
|
76
|
-
f"The requests module did not install correctly ({e}).{extra}"
|
|
77
|
-
) from None
|
|
78
|
-
|
|
79
|
-
return __requests
|
|
80
13
|
|
|
81
14
|
######################################################################
|
|
82
15
|
# Helpers
|
|
@@ -125,7 +58,6 @@ def download(
|
|
|
125
58
|
function to call on the first line
|
|
126
59
|
"""
|
|
127
60
|
|
|
128
|
-
requests = import_requests() # pylint: disable=redefined-outer-name
|
|
129
61
|
tdenv.NOTE("Requesting {}".format(url))
|
|
130
62
|
req = requests.get(url, headers=headers or None, stream=True, timeout=timeout)
|
|
131
63
|
req.raise_for_status()
|
|
@@ -238,7 +170,6 @@ def get_json_data(url, *, timeout: int = 90):
|
|
|
238
170
|
Displays a progress bar as it downloads.
|
|
239
171
|
"""
|
|
240
172
|
|
|
241
|
-
requests = import_requests() # pylint: disable=redefined-outer-name
|
|
242
173
|
req = requests.get(url, stream=True, timeout=timeout)
|
|
243
174
|
|
|
244
175
|
totalLength = req.headers.get('content-length')
|
|
@@ -279,7 +210,6 @@ class CSVStream:
|
|
|
279
210
|
self.url = url
|
|
280
211
|
self.tdenv = tdenv
|
|
281
212
|
if not url.startswith("file:///"):
|
|
282
|
-
requests = import_requests() # pylint: disable=redefined-outer-name
|
|
283
213
|
self.req = requests.get(self.url, stream=True, timeout=timeout)
|
|
284
214
|
self.lines = self.req.iter_lines()
|
|
285
215
|
else:
|
tradedangerous/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tradedangerous
|
|
3
|
-
Version: 11.0.
|
|
3
|
+
Version: 11.0.4
|
|
4
4
|
Summary: Trade-Dangerous is a set of powerful trading tools for Elite Dangerous, organized around one of the most powerful trade run optimizers available.
|
|
5
5
|
Home-page: https://github.com/eyeonus/Trade-Dangerous
|
|
6
6
|
Author: eyeonus
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
tradedangerous/__init__.py,sha256=bwsbE_GyCNsuyGDKnfXAg0RD-ewsWHliySJ5QfCK7h8,1166
|
|
2
|
-
tradedangerous/cache.py,sha256=
|
|
3
|
-
tradedangerous/cli.py,sha256=
|
|
2
|
+
tradedangerous/cache.py,sha256=mROADjtCtSWkvR6crdl7SycBH0AjuaceagUj-x9RZDM,36071
|
|
3
|
+
tradedangerous/cli.py,sha256=dLekZ3MTbn9XcSGtE532qZF3iSnsb5G-ddQyErwTv9o,4559
|
|
4
4
|
tradedangerous/corrections.py,sha256=_WLgo1IBWoskrrPFeshRwCOeJ2BeJb_x4tDQ0JdAo-s,1340
|
|
5
|
-
tradedangerous/csvexport.py,sha256=
|
|
5
|
+
tradedangerous/csvexport.py,sha256=_19bGVnCGJPzvx_8DzLGOs4rqx8Asn7eCVdXKdKu92E,8653
|
|
6
6
|
tradedangerous/edscupdate.py,sha256=G8N-j61MZbCgY07WIVK23CCw6eMPE3WkraXHeARt9QE,17297
|
|
7
7
|
tradedangerous/edsmupdate.py,sha256=jpDUxUkDKxlG_gS3qWy5fg9p3mBPC-akU2pHSlfTPkI,14915
|
|
8
|
-
tradedangerous/formatting.py,sha256
|
|
8
|
+
tradedangerous/formatting.py,sha256=-FdlH1yMKPkqhpCtKmbl0chbyZ1VjKZsZ8OLc8v-Knc,6927
|
|
9
9
|
tradedangerous/fs.py,sha256=_5OJHIRy_M-WFHEZO4g2EIgqDxdrz4s8tcdDmgG7NME,2494
|
|
10
10
|
tradedangerous/gui.py,sha256=DFsF5zATr-lyJShL6t5kPKvcLLJYkICurzBz0WBa-oQ,43676
|
|
11
11
|
tradedangerous/jsonprices.py,sha256=GAaNbfEs1LX_F5f69MiEhHIEwoGZtubGC8EQ9MM4B9A,6878
|
|
12
12
|
tradedangerous/mapping.py,sha256=eGBQeYPD04Kq_ygZCDRafKMGz9EnxSgXUzQU-u78_2A,4049
|
|
13
13
|
tradedangerous/prices.py,sha256=JqiDVrtvvPd5pqE3HdwOHOuFgdAbOR-pt0GLD3ZIXM8,7425
|
|
14
|
-
tradedangerous/submit-distances.py,sha256=
|
|
14
|
+
tradedangerous/submit-distances.py,sha256=EMpqxXFauo3oaR9OAnHCHCsrqwABK1nZdmg92m62zrk,11560
|
|
15
15
|
tradedangerous/tools.py,sha256=pp-4WtA12SVaaQHFJFOMTF7EDFRCU2mQeOhC4xoXmEk,1331
|
|
16
16
|
tradedangerous/trade.py,sha256=nGiTFj9ZrqeN9Xad3z8e4MpA2fNqYAcYMrZnwpnuus4,1938
|
|
17
17
|
tradedangerous/tradecalc.py,sha256=A7peEMiaCjlwFvReSq3E7_Ar0shUoFedQi83ZmOc7uY,42075
|
|
@@ -19,9 +19,9 @@ tradedangerous/tradedb.py,sha256=3nGB55dYs4igP3U3J4Ye1-M6Kt9A4xPAMmnX7JEDW7w,722
|
|
|
19
19
|
tradedangerous/tradeenv.py,sha256=SDzRC6ERYZzzb_I6uexmFpFJJrnbzXa-1ogYt_GH26w,10576
|
|
20
20
|
tradedangerous/tradeexcept.py,sha256=aZ-Y31MbkjF7lmAzBAbaMsPPE7FEEfuf4gaX2GvriDk,368
|
|
21
21
|
tradedangerous/tradegui.py,sha256=q2HdIdoyeLUpeF2X0hVIGn7sU6T4zOzq1HN0zGvZdyE,788
|
|
22
|
-
tradedangerous/transfers.py,sha256=
|
|
22
|
+
tradedangerous/transfers.py,sha256=88gIvXpjd8T6NLxBrBRzmH2IfUmDDtiMcDTrc7qF3OI,7830
|
|
23
23
|
tradedangerous/utils.py,sha256=PUPvAEqUyxYGqqQa0b_yfLAvq8YVUxK6HfdS-CxM-Lo,5186
|
|
24
|
-
tradedangerous/version.py,sha256=
|
|
24
|
+
tradedangerous/version.py,sha256=VIRNV1KJN_g_ByHP19vQGbhe4W2DtWVHoyZrEjvMkaI,646
|
|
25
25
|
tradedangerous/commands/TEMPLATE.py,sha256=MOE69xsZPHPIMBQ-LXicfsOlCZdy-2gPX_nlnwYYil8,2026
|
|
26
26
|
tradedangerous/commands/__init__.py,sha256=3gz2cnXNZNkV1gtZh0dOnCRxBkQHbeIyysRe3bM2WEE,9516
|
|
27
27
|
tradedangerous/commands/buildcache_cmd.py,sha256=_8vKu9e3tQy0HEPrnG8Ts0OoQ_kF6gZPQ9EOfTUd73w,2179
|
|
@@ -34,7 +34,7 @@ tradedangerous/commands/local_cmd.py,sha256=tf7YMGX-vaVGNO2lvQF9EvQEN3Wj7DE9-NTS
|
|
|
34
34
|
tradedangerous/commands/market_cmd.py,sha256=Ig16zDuksywiiF3Exps6UuM-ZhqgbXqkW6Lu2s9xQf0,5411
|
|
35
35
|
tradedangerous/commands/nav_cmd.py,sha256=v245L1MxiUliITUgvWeeB4cL4UdkNO8n0CiP6ztrV54,8460
|
|
36
36
|
tradedangerous/commands/olddata_cmd.py,sha256=6rpPRRs4kLhV9c0sogmctVAjta7v0L0Deu999spXY2s,7888
|
|
37
|
-
tradedangerous/commands/parsing.py,sha256=
|
|
37
|
+
tradedangerous/commands/parsing.py,sha256=RUnCnML59IOXYI6jEljE5lrE_WKcDmFFqKF1JVJg9A0,6725
|
|
38
38
|
tradedangerous/commands/rares_cmd.py,sha256=L_QoW2zIZTU9Jpavt_K2fZyu8T153nUSuVqIiz4uksQ,9207
|
|
39
39
|
tradedangerous/commands/run_cmd.py,sha256=HtvxKfD2ef_fUCDdUzBv9yRwd2gBOqIq4hzUAOLgcyU,47650
|
|
40
40
|
tradedangerous/commands/sell_cmd.py,sha256=RI8T1DWaBuQkYSy2Pjoo0Kxy5n9UgRTqtlSBE0Vg1SI,7943
|
|
@@ -54,26 +54,26 @@ tradedangerous/misc/derp-sentinel.py,sha256=22zyl26Q8XHvq8IJZDinJ3oKudUnByDoQ3Wi
|
|
|
54
54
|
tradedangerous/misc/diff-system-csvs.py,sha256=67K5BEDFYWCSJY17EjkUzNaLX8sOlP9aQ5US6f8WjPw,4931
|
|
55
55
|
tradedangerous/misc/eddb.py,sha256=mHHMIyyuJRHBtBgSou-z7rfNXkajWvvWghRPk3D5jE4,1812
|
|
56
56
|
tradedangerous/misc/eddn.py,sha256=RNoLCxFfEgktMPZB6k2BUxd3aM5Z6LqYi4WhI4jrRdQ,12149
|
|
57
|
-
tradedangerous/misc/edsc.py,sha256=
|
|
58
|
-
tradedangerous/misc/edsm.py,sha256=
|
|
57
|
+
tradedangerous/misc/edsc.py,sha256=SN_da9qZ7H8ozibyhoFVB8nAvwBDPF3Z_PMlt70J2Ro,14367
|
|
58
|
+
tradedangerous/misc/edsm.py,sha256=equDwO1SY3QTsoJIb3LjiHes4C8Dejaap_TMpYlCm8o,2910
|
|
59
59
|
tradedangerous/misc/importeddbstats.py,sha256=iLAcrFzdwiMm_MnUuaHcT_xGgZF8pfEEd1qljhhWJTU,1787
|
|
60
60
|
tradedangerous/misc/prices-json-exp.py,sha256=Fpm62ugP35ZBqnRs6ekYfS3GoDFYmvLD3b3SFJfaMOI,4944
|
|
61
61
|
tradedangerous/misc/progress.py,sha256=NKvKP1OSCTpItc1CNxDuEH2A1oGJ6aWSyCdPSAjsG9E,2120
|
|
62
62
|
tradedangerous/plugins/__init__.py,sha256=TL-OIptlqNENKhoFqkFeBJn_vSw8L0pVaDJgjhaTj7A,7860
|
|
63
63
|
tradedangerous/plugins/edapi_plug.py,sha256=5nqBYmjUceAt-KTfiBn7IEl443R1SsGLDmfVXgbcyms,42262
|
|
64
64
|
tradedangerous/plugins/edcd_plug.py,sha256=JuDtuEM_mN9Sz2H09-qYizM-9N3cuNjgvQy7Y-wHwKw,14412
|
|
65
|
-
tradedangerous/plugins/eddblink_plug.py,sha256=
|
|
65
|
+
tradedangerous/plugins/eddblink_plug.py,sha256=EWJrVn5twwPVT-vGicmWuL4NAwf69G_0mw9lnjzn1Xw,21606
|
|
66
66
|
tradedangerous/plugins/edmc_batch_plug.py,sha256=rrP_lFFxWsba8DPEo0WF2EdCiMoRC7tCT8z62MIvtIo,4173
|
|
67
67
|
tradedangerous/plugins/journal_plug.py,sha256=5HMyoxQ7z42qj7NiL8rDxSyTN9gKikoQjyWzJLD-SYQ,23746
|
|
68
68
|
tradedangerous/plugins/netlog_plug.py,sha256=yUl47l9xt3kGj9oSiY_FZaDGdnQj63oa9MBtSeIy1Zo,13469
|
|
69
|
-
tradedangerous/plugins/spansh_plug.py,sha256=
|
|
69
|
+
tradedangerous/plugins/spansh_plug.py,sha256=FmOJcYq6-ENYdVNRN96kYdskeqZ4IqzjEsyCYm6hVXI,26762
|
|
70
70
|
tradedangerous/templates/Added.csv,sha256=8o54civQCcS9y7_DBo0GX196XWRbbREQqKDYTKibsgQ,649
|
|
71
71
|
tradedangerous/templates/Category.csv,sha256=8xwUDcBZE25T6x6dZGlRUMTCqeDLt3a9LXU5h6hRHV8,250
|
|
72
72
|
tradedangerous/templates/RareItem.csv,sha256=F1RhRnTD82PiwrVUO-ai2ErGH2PTqNnQaDw5mcgljXs,10483
|
|
73
73
|
tradedangerous/templates/TradeDangerous.sql,sha256=VlQK7QGtEi2brGtWaIZDvKmbJ_vLocD4CJ8h_6kKptU,7808
|
|
74
|
-
tradedangerous-11.0.
|
|
75
|
-
tradedangerous-11.0.
|
|
76
|
-
tradedangerous-11.0.
|
|
77
|
-
tradedangerous-11.0.
|
|
78
|
-
tradedangerous-11.0.
|
|
79
|
-
tradedangerous-11.0.
|
|
74
|
+
tradedangerous-11.0.4.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
75
|
+
tradedangerous-11.0.4.dist-info/METADATA,sha256=wtvXMMQTXzopIxDvS5GcaFubPfU2pDHlM3T6csHiTlY,4435
|
|
76
|
+
tradedangerous-11.0.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
77
|
+
tradedangerous-11.0.4.dist-info/entry_points.txt,sha256=pSwa-q0ob443uiKux7xFKYQl8uen66iDTnjdrQhNLx8,92
|
|
78
|
+
tradedangerous-11.0.4.dist-info/top_level.txt,sha256=bF29i-oEltmNICgElEKxNsg83oahJvxg3a7YrxZi9Rk,15
|
|
79
|
+
tradedangerous-11.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|