tradedangerous 12.7.6__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.
- py.typed +1 -0
- trade.py +49 -0
- tradedangerous/__init__.py +43 -0
- tradedangerous/cache.py +1381 -0
- tradedangerous/cli.py +136 -0
- tradedangerous/commands/TEMPLATE.py +74 -0
- tradedangerous/commands/__init__.py +244 -0
- tradedangerous/commands/buildcache_cmd.py +102 -0
- tradedangerous/commands/buy_cmd.py +427 -0
- tradedangerous/commands/commandenv.py +372 -0
- tradedangerous/commands/exceptions.py +94 -0
- tradedangerous/commands/export_cmd.py +150 -0
- tradedangerous/commands/import_cmd.py +222 -0
- tradedangerous/commands/local_cmd.py +243 -0
- tradedangerous/commands/market_cmd.py +207 -0
- tradedangerous/commands/nav_cmd.py +252 -0
- tradedangerous/commands/olddata_cmd.py +270 -0
- tradedangerous/commands/parsing.py +221 -0
- tradedangerous/commands/rares_cmd.py +298 -0
- tradedangerous/commands/run_cmd.py +1521 -0
- tradedangerous/commands/sell_cmd.py +262 -0
- tradedangerous/commands/shipvendor_cmd.py +60 -0
- tradedangerous/commands/station_cmd.py +68 -0
- tradedangerous/commands/trade_cmd.py +181 -0
- tradedangerous/commands/update_cmd.py +67 -0
- tradedangerous/corrections.py +55 -0
- tradedangerous/csvexport.py +234 -0
- tradedangerous/db/__init__.py +27 -0
- tradedangerous/db/adapter.py +192 -0
- tradedangerous/db/config.py +107 -0
- tradedangerous/db/engine.py +259 -0
- tradedangerous/db/lifecycle.py +332 -0
- tradedangerous/db/locks.py +208 -0
- tradedangerous/db/orm_models.py +500 -0
- tradedangerous/db/paths.py +113 -0
- tradedangerous/db/utils.py +661 -0
- tradedangerous/edscupdate.py +565 -0
- tradedangerous/edsmupdate.py +474 -0
- tradedangerous/formatting.py +210 -0
- tradedangerous/fs.py +156 -0
- tradedangerous/gui.py +1146 -0
- tradedangerous/mapping.py +133 -0
- tradedangerous/mfd/__init__.py +103 -0
- tradedangerous/mfd/saitek/__init__.py +3 -0
- tradedangerous/mfd/saitek/directoutput.py +678 -0
- tradedangerous/mfd/saitek/x52pro.py +195 -0
- tradedangerous/misc/checkpricebounds.py +287 -0
- tradedangerous/misc/clipboard.py +49 -0
- tradedangerous/misc/coord64.py +83 -0
- tradedangerous/misc/csvdialect.py +57 -0
- tradedangerous/misc/derp-sentinel.py +35 -0
- tradedangerous/misc/diff-system-csvs.py +159 -0
- tradedangerous/misc/eddb.py +81 -0
- tradedangerous/misc/eddn.py +349 -0
- tradedangerous/misc/edsc.py +437 -0
- tradedangerous/misc/edsm.py +121 -0
- tradedangerous/misc/importeddbstats.py +54 -0
- tradedangerous/misc/prices-json-exp.py +179 -0
- tradedangerous/misc/progress.py +194 -0
- tradedangerous/plugins/__init__.py +249 -0
- tradedangerous/plugins/edcd_plug.py +371 -0
- tradedangerous/plugins/eddblink_plug.py +861 -0
- tradedangerous/plugins/edmc_batch_plug.py +133 -0
- tradedangerous/plugins/spansh_plug.py +2647 -0
- tradedangerous/prices.py +211 -0
- tradedangerous/submit-distances.py +422 -0
- tradedangerous/templates/Added.csv +37 -0
- tradedangerous/templates/Category.csv +17 -0
- tradedangerous/templates/RareItem.csv +143 -0
- tradedangerous/templates/TradeDangerous.sql +338 -0
- tradedangerous/tools.py +40 -0
- tradedangerous/tradecalc.py +1302 -0
- tradedangerous/tradedb.py +2320 -0
- tradedangerous/tradeenv.py +313 -0
- tradedangerous/tradeenv.pyi +109 -0
- tradedangerous/tradeexcept.py +131 -0
- tradedangerous/tradeorm.py +183 -0
- tradedangerous/transfers.py +192 -0
- tradedangerous/utils.py +243 -0
- tradedangerous/version.py +16 -0
- tradedangerous-12.7.6.dist-info/METADATA +106 -0
- tradedangerous-12.7.6.dist-info/RECORD +87 -0
- tradedangerous-12.7.6.dist-info/WHEEL +5 -0
- tradedangerous-12.7.6.dist-info/entry_points.txt +3 -0
- tradedangerous-12.7.6.dist-info/licenses/LICENSE +373 -0
- tradedangerous-12.7.6.dist-info/top_level.txt +2 -0
- tradegui.py +24 -0
tradedangerous/cli.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# --------------------------------------------------------------------
|
|
2
|
+
# Copyright (C) Oliver 'kfsone' Smith 2014 <oliver@kfs.org>:
|
|
3
|
+
# Copyright (C) Bernd 'Gazelle' Gollesch 2016, 2017
|
|
4
|
+
# Copyright (C) Jonathan 'eyeonus' Jones 2018, 2019
|
|
5
|
+
#
|
|
6
|
+
# You are free to use, redistribute, or even print and eat a copy of
|
|
7
|
+
# this software so long as you include this copyright notice.
|
|
8
|
+
# I guarantee there is at least one bug neither of us knew about.
|
|
9
|
+
# --------------------------------------------------------------------
|
|
10
|
+
# TradeDangerous :: Command Line App :: Main Module
|
|
11
|
+
#
|
|
12
|
+
# TradeDangerous is a powerful set of tools for traders in Frontier
|
|
13
|
+
# Development's game "Elite: Dangerous". It's main function is
|
|
14
|
+
# calculating the most profitable trades between either individual
|
|
15
|
+
# stations or working out "profit runs".
|
|
16
|
+
#
|
|
17
|
+
# I wrote TD because I realized that the best trade run - in terms
|
|
18
|
+
# of the "average profit per stop" was rarely as simple as going
|
|
19
|
+
# Chango -> Dahan -> Chango.
|
|
20
|
+
#
|
|
21
|
+
# E:D's economy is complex; sometimes you can make the most profit
|
|
22
|
+
# by trading one item A->B and flying a second item B->A.
|
|
23
|
+
# But more often you need to fly multiple stations, especially since
|
|
24
|
+
# as you are making money different trade options are coming into
|
|
25
|
+
# your affordable range.
|
|
26
|
+
#
|
|
27
|
+
# END USERS: If you are a user looking to find out how to use TD,
|
|
28
|
+
# please consult the file "README.md".
|
|
29
|
+
#
|
|
30
|
+
# DEVELOPERS: If you are a programmer who wants TD to do something
|
|
31
|
+
# cool, please see the TradeDB and TradeCalc modules. TD is designed
|
|
32
|
+
# to empower other programmers to do cool stuff.
|
|
33
|
+
|
|
34
|
+
import os
|
|
35
|
+
import sys
|
|
36
|
+
import traceback
|
|
37
|
+
|
|
38
|
+
from . import commands
|
|
39
|
+
from . import tradeexcept
|
|
40
|
+
from .commands import exceptions
|
|
41
|
+
from .plugins import PluginException
|
|
42
|
+
|
|
43
|
+
from . import tradedb
|
|
44
|
+
|
|
45
|
+
if "CPROF" in os.environ:
|
|
46
|
+
import cProfile
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def main(argv = None):
|
|
50
|
+
if not argv:
|
|
51
|
+
argv = sys.argv
|
|
52
|
+
if sys.hexversion < 0x30813F0:
|
|
53
|
+
raise SystemExit(
|
|
54
|
+
"Sorry: TradeDangerous requires Python 3.8.19 or higher.\n"
|
|
55
|
+
"For assistance, see:\n"
|
|
56
|
+
"\tBug Tracker: https://github.com/eyeonus/Trade-Dangerous/issues\n"
|
|
57
|
+
"\tDocumentation: https://github.com/eyeonus/Trade-Dangerous/wiki\n"
|
|
58
|
+
"\tEDForum Thread: https://forums.frontier.co.uk/showthread.php/441509\n"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
try:
|
|
63
|
+
if "CPROF" in os.environ:
|
|
64
|
+
cProfile.run("trade(argv)")
|
|
65
|
+
else:
|
|
66
|
+
trade(argv)
|
|
67
|
+
except PluginException as e:
|
|
68
|
+
print("PLUGIN ERROR: {}".format(e))
|
|
69
|
+
if 'EXCEPTIONS' in os.environ:
|
|
70
|
+
raise e
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
except tradeexcept.TradeException as e:
|
|
73
|
+
print("%s: %s" % (argv[0], str(e)))
|
|
74
|
+
if 'EXCEPTIONS' in os.environ:
|
|
75
|
+
raise e
|
|
76
|
+
sys.exit(1)
|
|
77
|
+
except (UnicodeEncodeError, UnicodeDecodeError):
|
|
78
|
+
print("-----------------------------------------------------------")
|
|
79
|
+
print("ERROR: Unexpected unicode error in the wild!")
|
|
80
|
+
print()
|
|
81
|
+
print(traceback.format_exc())
|
|
82
|
+
print(
|
|
83
|
+
"Please report this bug (http://github.com/eyeonus/Trade-Dangerous/issues). You may be "
|
|
84
|
+
"able to work around it by using the '-q' parameter. Windows "
|
|
85
|
+
"users may be able to use 'chcp.com 65001' to tell the console "
|
|
86
|
+
"you want to support UTF-8 characters."
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def trade(argv):
|
|
90
|
+
"""
|
|
91
|
+
This method represents the trade command.
|
|
92
|
+
"""
|
|
93
|
+
cmdIndex = commands.CommandIndex()
|
|
94
|
+
cmdenv = cmdIndex.parse(argv)
|
|
95
|
+
|
|
96
|
+
# Phase A: preflight/fast validation (must run before any heavy TradeDB load)
|
|
97
|
+
if (preflight := getattr(cmdenv, "preflight", None)) and callable(preflight):
|
|
98
|
+
preflight()
|
|
99
|
+
|
|
100
|
+
# Phase B: heavy init + execution
|
|
101
|
+
tdb = tradedb.TradeDB(cmdenv, load=cmdenv.wantsTradeDB)
|
|
102
|
+
if cmdenv.usesTradeData:
|
|
103
|
+
tsc = tdb.tradingStationCount
|
|
104
|
+
if tsc == 0:
|
|
105
|
+
raise exceptions.NoDataError(
|
|
106
|
+
"There is no trading data for ANY station in "
|
|
107
|
+
"the local database. Please enter or import "
|
|
108
|
+
"price data."
|
|
109
|
+
)
|
|
110
|
+
if tsc == 1:
|
|
111
|
+
raise exceptions.NoDataError(
|
|
112
|
+
"The local database only contains trading data "
|
|
113
|
+
"for one station. Please enter or import data "
|
|
114
|
+
"for additional stations."
|
|
115
|
+
)
|
|
116
|
+
if tsc < 8:
|
|
117
|
+
cmdenv.NOTE(
|
|
118
|
+
"The local database only contains trading data "
|
|
119
|
+
"for {} stations. Please enter or import data "
|
|
120
|
+
"for additional stations.".format(
|
|
121
|
+
tsc
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
results = cmdenv.run(tdb)
|
|
127
|
+
except tradeexcept.SimpleAbort as e:
|
|
128
|
+
cmdenv.console.print(f"\n{e}\n", style="red")
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
finally:
|
|
131
|
+
# always close tdb
|
|
132
|
+
tdb.close(final=True)
|
|
133
|
+
|
|
134
|
+
if results:
|
|
135
|
+
results.render()
|
|
136
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from .commandenv import ResultRow
|
|
5
|
+
from .parsing import ParseArgument # import specific helpers as needed
|
|
6
|
+
|
|
7
|
+
from tradedangerous.formatting import RowFormat
|
|
8
|
+
|
|
9
|
+
if typing.TYPE_CHECKING:
|
|
10
|
+
from tradedangerous import TradeDB, TradeORM, CommandEnv, CommandResults
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
######################################################################
|
|
14
|
+
# Parser config
|
|
15
|
+
|
|
16
|
+
help = 'Describe your command briefly here for the top-level --help.'
|
|
17
|
+
name = 'TEMPLATE' # name of your .py file excluding the _cmd
|
|
18
|
+
epilog = None # text to print at the bottom of --help
|
|
19
|
+
|
|
20
|
+
# Whether this command needs a TradeDB instance
|
|
21
|
+
wantsTradeDB = True
|
|
22
|
+
usesTradeData = False
|
|
23
|
+
|
|
24
|
+
# Parser wiring (keep tuples for consistency with loader)
|
|
25
|
+
arguments = (
|
|
26
|
+
ParseArgument("name", help="Example positional(s).", type=str, nargs="*"),
|
|
27
|
+
)
|
|
28
|
+
switches = (
|
|
29
|
+
ParseArgument("--flag", help="Example flag.", action="store_true", default=False),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Runtime API
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def run(
|
|
37
|
+
results: CommandResults,
|
|
38
|
+
cmdenv: CommandEnv,
|
|
39
|
+
tdb: TradeDB | TradeORM | None, # choose one
|
|
40
|
+
) -> CommandResults | bool | None: # choose one
|
|
41
|
+
"""
|
|
42
|
+
Implement code that validates arguments, collects and prepares
|
|
43
|
+
any data you will need to generate your results for the user.
|
|
44
|
+
|
|
45
|
+
If your command has finished and has no output to generate,
|
|
46
|
+
return None, otherwise return "results" to be forwarded to
|
|
47
|
+
the 'render' function.
|
|
48
|
+
|
|
49
|
+
DO NOT print() during 'run', this allows run() functions to
|
|
50
|
+
be re-used between modules and allows them to be used beyond
|
|
51
|
+
the trade.py command line - e.g. someone writing a TD GUI
|
|
52
|
+
will call run() and then render the results themselves.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
### TODO: Implement
|
|
56
|
+
row = ResultRow(example="ok")
|
|
57
|
+
results.rows.append(row)
|
|
58
|
+
return results
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def render(results: CommandResults, cmdenv: CommandEnv, tdb: TradeDB | TradeORM | None):
|
|
62
|
+
"""
|
|
63
|
+
If run() returns a truthy value, the trade.py code will then
|
|
64
|
+
call the corresponding render() function.
|
|
65
|
+
|
|
66
|
+
This is where you should generate any output from your command.
|
|
67
|
+
"""
|
|
68
|
+
fmt = RowFormat()
|
|
69
|
+
fmt.addColumn("Example", "<", 10, key=lambda r: getattr(r, "example", ""))
|
|
70
|
+
if not cmdenv.quiet:
|
|
71
|
+
hdr, ul = fmt.heading()
|
|
72
|
+
print(hdr, ul, sep="\n")
|
|
73
|
+
for row in results.rows:
|
|
74
|
+
print(fmt.format(row))
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
from .commandenv import CommandEnv
|
|
2
|
+
from textwrap import TextWrapper
|
|
3
|
+
|
|
4
|
+
import argparse # For parsing command line args.
|
|
5
|
+
import os
|
|
6
|
+
import pathlib
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from . import exceptions
|
|
10
|
+
from . import parsing
|
|
11
|
+
|
|
12
|
+
from . import buildcache_cmd
|
|
13
|
+
from . import buy_cmd
|
|
14
|
+
from . import export_cmd
|
|
15
|
+
from . import import_cmd
|
|
16
|
+
from . import local_cmd
|
|
17
|
+
from . import market_cmd
|
|
18
|
+
from . import nav_cmd
|
|
19
|
+
from . import olddata_cmd
|
|
20
|
+
from . import rares_cmd
|
|
21
|
+
from . import run_cmd
|
|
22
|
+
from . import sell_cmd
|
|
23
|
+
from . import shipvendor_cmd
|
|
24
|
+
from . import station_cmd
|
|
25
|
+
from . import trade_cmd
|
|
26
|
+
from . import update_cmd
|
|
27
|
+
|
|
28
|
+
from tradedangerous import version
|
|
29
|
+
from tradedangerous.tradeenv import ENV_DEFAULTS
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
thismodule = sys.modules[__name__]
|
|
33
|
+
|
|
34
|
+
commandIndex = {
|
|
35
|
+
cmd[0:cmd.find('_cmd')]: getattr(thismodule, cmd)
|
|
36
|
+
for cmd in thismodule.__dir__() if cmd.endswith("_cmd")
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
######################################################################
|
|
40
|
+
# Helpers
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class HelpAction(argparse.Action):
|
|
44
|
+
"""
|
|
45
|
+
argparse action helper for printing the argument usage,
|
|
46
|
+
because Python 3.4's argparse is ever-so subtly very broken.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __call__(self, parser, namespace, values, option_string = None):
|
|
50
|
+
raise exceptions.UsageError(
|
|
51
|
+
f"TradeDangerous v{version.__version__} help",
|
|
52
|
+
parser.format_help()
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def addArguments(group, options, required, topGroup = None):
|
|
57
|
+
"""
|
|
58
|
+
Registers a list of options to the specified group. Nodes
|
|
59
|
+
are either an instance of ParseArgument or a list of
|
|
60
|
+
ParseArguments. The list form is considered to be a
|
|
61
|
+
mutually exclusive group of arguments.
|
|
62
|
+
"""
|
|
63
|
+
for option in options:
|
|
64
|
+
if isinstance(option, parsing.MutuallyExclusiveGroup):
|
|
65
|
+
exGrp = (topGroup or group).add_mutually_exclusive_group()
|
|
66
|
+
parsing.registerParserHelpers(exGrp)
|
|
67
|
+
addArguments(exGrp, option.arguments, required, topGroup = group)
|
|
68
|
+
else:
|
|
69
|
+
assert required not in option.kwargs
|
|
70
|
+
if option.args[0][0] == '-':
|
|
71
|
+
group.add_argument(*(option.args), required = required, **(option.kwargs))
|
|
72
|
+
elif required:
|
|
73
|
+
group.add_argument(*(option.args), **(option.kwargs))
|
|
74
|
+
else:
|
|
75
|
+
group.add_argument(*(option.args), nargs = '?', **(option.kwargs))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _findFromFile(cmd, prefix = '.tdrc'):
|
|
79
|
+
if cmd:
|
|
80
|
+
# check the current directory, fall back to home
|
|
81
|
+
filename = f'{prefix}_{cmd}'
|
|
82
|
+
for dirname in '.', os.path.expanduser('~'):
|
|
83
|
+
cmdPath = pathlib.Path(dirname) / filename
|
|
84
|
+
if cmdPath.exists():
|
|
85
|
+
return cmdPath.resolve()
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class CommandIndex:
|
|
90
|
+
|
|
91
|
+
def usage(self, argv):
|
|
92
|
+
"""
|
|
93
|
+
Generate the outlying usage text for TD.
|
|
94
|
+
This tells the user the list of current
|
|
95
|
+
commands, generated programatically,
|
|
96
|
+
and the outlying command functionality.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
text = (
|
|
100
|
+
"Usage: {prog} <command>\n\n"
|
|
101
|
+
"Where <command> is one of:\n\n"
|
|
102
|
+
.format(prog = argv[0])
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Figure out the pre-indentation
|
|
106
|
+
cmdFmt = ' {:<12s} '
|
|
107
|
+
cmdFmtLen = len(cmdFmt.format(''))
|
|
108
|
+
tw = TextWrapper(
|
|
109
|
+
subsequent_indent = ' ' * (cmdFmtLen + 1),
|
|
110
|
+
width = 78,
|
|
111
|
+
drop_whitespace = True,
|
|
112
|
+
expand_tabs = True,
|
|
113
|
+
fix_sentence_endings = True,
|
|
114
|
+
break_long_words = False,
|
|
115
|
+
break_on_hyphens = True,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
lastCmdName = None
|
|
119
|
+
for cmdName, cmd in sorted(commandIndex.items()):
|
|
120
|
+
tw.initial_indent = cmdFmt.format(cmdName)
|
|
121
|
+
text += tw.fill(cmd.help) + "\n"
|
|
122
|
+
lastCmdName = cmdName
|
|
123
|
+
|
|
124
|
+
text += (
|
|
125
|
+
"\n"
|
|
126
|
+
f"Version {version.__version__}\n"
|
|
127
|
+
f"For additional help on a specific command, such as '{lastCmdName}' use\n"
|
|
128
|
+
f" {argv[0]} {lastCmdName} -h"
|
|
129
|
+
)
|
|
130
|
+
return text
|
|
131
|
+
|
|
132
|
+
def parse(self, argv, fromfile_prefix = '+'):
|
|
133
|
+
if len(argv) <= 1 or argv[1] == '--help' or argv[1] == '-h':
|
|
134
|
+
raise exceptions.UsageError(
|
|
135
|
+
"TradeDangerous provides a set of trade database "
|
|
136
|
+
"facilities for Elite:Dangerous.", self.usage(argv))
|
|
137
|
+
|
|
138
|
+
cmdName, cmdModule = argv[1].casefold(), None
|
|
139
|
+
try:
|
|
140
|
+
cmdModule = commandIndex[cmdName]
|
|
141
|
+
except KeyError:
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
if not cmdModule:
|
|
145
|
+
candidates = []
|
|
146
|
+
for name, module in commandIndex.items():
|
|
147
|
+
if name.startswith(cmdName):
|
|
148
|
+
candidates.append([name, module])
|
|
149
|
+
if not candidates:
|
|
150
|
+
raise exceptions.CommandLineError(
|
|
151
|
+
f"Unrecognized command, '{cmdName}'",
|
|
152
|
+
self.usage(argv)
|
|
153
|
+
)
|
|
154
|
+
if len(candidates) > 1:
|
|
155
|
+
candidate_names = ', '.join(c[0] for c in candidates)
|
|
156
|
+
raise exceptions.CommandLineError(
|
|
157
|
+
f"Ambiguous command, '{cmdName}', could match: {candidate_names}",
|
|
158
|
+
self.usage(argv)
|
|
159
|
+
)
|
|
160
|
+
argv[1] = cmdName = candidates[0][0]
|
|
161
|
+
cmdModule = candidates[0][1]
|
|
162
|
+
|
|
163
|
+
class ArgParser(argparse.ArgumentParser):
|
|
164
|
+
def error(self, message):
|
|
165
|
+
raise exceptions.CommandLineError(message, self.format_usage())
|
|
166
|
+
|
|
167
|
+
parser = ArgParser(
|
|
168
|
+
description = f"TradeDangerous v{version.__version__}: {cmdName}",
|
|
169
|
+
add_help = False,
|
|
170
|
+
allow_abbrev = True,
|
|
171
|
+
epilog = f"Version {version.__version__}.\nUse {argv[0]} {argv[1]} -h for more help",
|
|
172
|
+
fromfile_prefix_chars = fromfile_prefix,
|
|
173
|
+
)
|
|
174
|
+
parser.set_defaults(_editing = False)
|
|
175
|
+
parsing.registerParserHelpers(parser)
|
|
176
|
+
|
|
177
|
+
subParsers = parser.add_subparsers(title = 'Command Options')
|
|
178
|
+
subParser = subParsers.add_parser(cmdModule.name,
|
|
179
|
+
help = cmdModule.help,
|
|
180
|
+
add_help = False,
|
|
181
|
+
epilog = cmdModule.epilog,
|
|
182
|
+
)
|
|
183
|
+
parsing.registerParserHelpers(subParser)
|
|
184
|
+
|
|
185
|
+
arguments = cmdModule.arguments
|
|
186
|
+
if arguments:
|
|
187
|
+
argParser = subParser.add_argument_group('Required Arguments')
|
|
188
|
+
addArguments(argParser, arguments, True)
|
|
189
|
+
|
|
190
|
+
switches = cmdModule.switches
|
|
191
|
+
if switches:
|
|
192
|
+
switchParser = subParser.add_argument_group('Optional Switches')
|
|
193
|
+
addArguments(switchParser, switches, False)
|
|
194
|
+
|
|
195
|
+
# Arguments common to all subparsers.
|
|
196
|
+
stdArgs = subParser.add_argument_group('Common Switches')
|
|
197
|
+
stdArgs.add_argument('--help', '-h',
|
|
198
|
+
help = 'Show this help message and exit.',
|
|
199
|
+
action = HelpAction, nargs = 0,
|
|
200
|
+
)
|
|
201
|
+
stdArgs.add_argument('--debug', '-w',
|
|
202
|
+
help = 'Enable/raise level of diagnostic output.',
|
|
203
|
+
default = 0, required = False, action = 'count',
|
|
204
|
+
)
|
|
205
|
+
stdArgs.add_argument('--detail', '-v',
|
|
206
|
+
help = 'Increase level of detail in output.',
|
|
207
|
+
default = 0, required = False, action = 'count',
|
|
208
|
+
)
|
|
209
|
+
stdArgs.add_argument('--color', '-c',
|
|
210
|
+
help = 'Add color to output for enhanced readability.',
|
|
211
|
+
default = False, action = 'store_true',
|
|
212
|
+
)
|
|
213
|
+
stdArgs.add_argument('--quiet', '-q',
|
|
214
|
+
help = 'Reduce level of detail in output.',
|
|
215
|
+
default = 0, required = False, action = 'count',
|
|
216
|
+
)
|
|
217
|
+
stdArgs.add_argument('--db',
|
|
218
|
+
help = 'Specify location of the SQLite database.',
|
|
219
|
+
default = None, dest = 'dbFilename', type = str,
|
|
220
|
+
)
|
|
221
|
+
stdArgs.add_argument('--cwd', '-C',
|
|
222
|
+
help = 'Change the working directory file accesses are made from.',
|
|
223
|
+
type = str, required = False,
|
|
224
|
+
)
|
|
225
|
+
stdArgs.add_argument('--link-ly', '-L',
|
|
226
|
+
help = 'Maximum lightyears between systems to be considered linked.',
|
|
227
|
+
type = float,
|
|
228
|
+
default = ENV_DEFAULTS['maxSystemLinkLy'], dest = 'maxSystemLinkLy',
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
fromfilePath = _findFromFile(cmdModule.name)
|
|
232
|
+
if fromfilePath:
|
|
233
|
+
argv.insert(2, f'{fromfile_prefix}{fromfilePath}')
|
|
234
|
+
|
|
235
|
+
# Parse argv; optionally swallow unknown args/switches if the module allows it.
|
|
236
|
+
accept_unknown = getattr(cmdModule, 'acceptUnknown', False)
|
|
237
|
+
if accept_unknown:
|
|
238
|
+
properties, _unknown = parser.parse_known_args(argv[1:])
|
|
239
|
+
else:
|
|
240
|
+
properties = parser.parse_args(argv[1:])
|
|
241
|
+
|
|
242
|
+
parsed = CommandEnv(vars(properties), argv, cmdModule)
|
|
243
|
+
parsed.DEBUG0("Command line was: {}", argv)
|
|
244
|
+
return parsed
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from .exceptions import CommandLineError
|
|
5
|
+
from .parsing import ParseArgument
|
|
6
|
+
|
|
7
|
+
from tradedangerous.db.lifecycle import ensure_fresh_db
|
|
8
|
+
|
|
9
|
+
if typing.TYPE_CHECKING:
|
|
10
|
+
from tradedangerous import CommandEnv, CommandResults, TradeDB
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
######################################################################
|
|
14
|
+
# Parser config
|
|
15
|
+
|
|
16
|
+
help = 'Build TradeDangerous cache file from sources'
|
|
17
|
+
name = 'buildcache'
|
|
18
|
+
epilog = (
|
|
19
|
+
'TD will normally do this for you automatically whenever '
|
|
20
|
+
'it detects changes to one or more source file; most end-'
|
|
21
|
+
'users will never need to use this command.\n'
|
|
22
|
+
'N.B. This process is destructive: '
|
|
23
|
+
'any data in the .db that is not reflected in the '
|
|
24
|
+
'source files will be lost.'
|
|
25
|
+
)
|
|
26
|
+
wantsTradeDB = False # Cause we're about to frak with it.
|
|
27
|
+
arguments = [
|
|
28
|
+
]
|
|
29
|
+
switches = [
|
|
30
|
+
ParseArgument(
|
|
31
|
+
'--sql', default = None, dest = 'sqlFilename',
|
|
32
|
+
help = 'Specify SQL script to execute.',
|
|
33
|
+
),
|
|
34
|
+
ParseArgument(
|
|
35
|
+
'--prices', default = None, dest = 'pricesFilename',
|
|
36
|
+
help = 'Specify the prices file to load.',
|
|
37
|
+
),
|
|
38
|
+
ParseArgument(
|
|
39
|
+
'--force', '-f', default = False, action = 'store_true',
|
|
40
|
+
dest = 'force',
|
|
41
|
+
help = 'Overwrite existing file',
|
|
42
|
+
),
|
|
43
|
+
ParseArgument(
|
|
44
|
+
'--ignore-unknown', '-i',
|
|
45
|
+
default = False, action = 'store_true',
|
|
46
|
+
dest = 'ignoreUnknown',
|
|
47
|
+
help = (
|
|
48
|
+
"Data for systems, stations and items that are not "
|
|
49
|
+
"recognized is reported as warning but skipped."
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
######################################################################
|
|
55
|
+
# Helpers
|
|
56
|
+
|
|
57
|
+
######################################################################
|
|
58
|
+
# Perform query and populate result set
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def run(results: CommandResults, cmdenv: CommandEnv, tdb: TradeDB) -> bool:
|
|
62
|
+
"""
|
|
63
|
+
BRUTE-FORCE rebuild of the cache/database.
|
|
64
|
+
|
|
65
|
+
Semantics preserved:
|
|
66
|
+
- If DB exists and --force not given => error
|
|
67
|
+
- SQL file must exist
|
|
68
|
+
- Performs a full destructive rebuild
|
|
69
|
+
|
|
70
|
+
Implementation change:
|
|
71
|
+
- Delegates to tradedangerous.db.lifecycle.ensure_fresh_db with mode='force'
|
|
72
|
+
so all backend-specific checks and rebuild steps run via the central path.
|
|
73
|
+
"""
|
|
74
|
+
# Deprecation note: keep short and visible but non-fatal.
|
|
75
|
+
print("NOTE: 'buildcache' is deprecated. Prefer 'update' or importer plugins. "
|
|
76
|
+
"Proceeding with a forced rebuild via db.lifecycle.ensure_fresh_db().")
|
|
77
|
+
|
|
78
|
+
# Honor legacy safety: require --force to overwrite an existing DB file.
|
|
79
|
+
if not cmdenv.force and tdb.dbPath.exists():
|
|
80
|
+
raise CommandLineError(
|
|
81
|
+
f"SQLite3 database '{tdb.dbFilename}' already exists.\n"
|
|
82
|
+
"Either remove the file first or use the '-f/--force' option."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Ensure the SQL source exists (buildCache ultimately relies on this path).
|
|
86
|
+
if not tdb.sqlPath.exists():
|
|
87
|
+
raise CommandLineError(f"SQL File does not exist: {tdb.sqlFilename}")
|
|
88
|
+
|
|
89
|
+
# Force a rebuild through the lifecycle helper (works for both backends).
|
|
90
|
+
ensure_fresh_db(
|
|
91
|
+
backend=tdb.engine.dialect.name if getattr(tdb, "engine", None) else "sqlite",
|
|
92
|
+
engine=getattr(tdb, "engine", None),
|
|
93
|
+
data_dir=tdb.dataPath,
|
|
94
|
+
metadata=None,
|
|
95
|
+
mode="force",
|
|
96
|
+
tdb=tdb,
|
|
97
|
+
tdenv=cmdenv,
|
|
98
|
+
rebuild=True,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# We've done everything, there is no work for the caller to do.
|
|
102
|
+
return False
|