forked from spyder-ide/spyder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootstrap.py
executable file
·278 lines (224 loc) · 9.14 KB
/
bootstrap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2009- Spyder Project Contributors
#
# Distributed under the terms of the MIT License
# (see spyder/__init__.py for details)
# -----------------------------------------------------------------------------
"""
Bootstrap Spyder.
Detect environment and execute Spyder from source checkout.
See spyder-ide/spyder#741.
"""
# pylint: disable=C0103
# pylint: disable=C0412
# pylint: disable=C0413
# Standard library imports
import atexit
import argparse
import os
import os.path as osp
import pkg_resources
import shutil
import subprocess
import sys
import time
time_start = time.time()
# --- Parse command line
parser = argparse.ArgumentParser(
usage="python bootstrap.py [options] [-- spyder_options]",
epilog="""\
Arguments for Spyder's main script are specified after the --
symbol (example: `python bootstrap.py -- --hide-console`).
Type `python bootstrap.py -- --help` to read about Spyder
options.""")
parser.add_argument('--gui', default=None,
help="GUI toolkit: pyqt5 (for PyQt5) or pyside2 "
"(for PySide2)")
parser.add_argument('--show-console', action='store_true', default=False,
help="(Deprecated) Does nothing, now the default behavior "
"is to show the console")
parser.add_argument('--hide-console', action='store_true', default=False,
help="Hide parent console window (Windows only)")
parser.add_argument('--safe-mode', dest="safe_mode",
action='store_true', default=False,
help="Start Spyder with a clean configuration directory")
parser.add_argument('--no-apport', action='store_true', default=False,
help="Disable Apport exception hook (Ubuntu)")
parser.add_argument('--debug', action='store_true',
default=False, help="Run Spyder in debug mode")
parser.add_argument('--filter-log', default='',
help="Comma-separated module name hierarchies whose log "
"messages should be shown. e.g., "
"spyder.plugins.completion,spyder.plugins.editor")
parser.add_argument('spyder_options', nargs='*')
args = parser.parse_args()
# Store variable to be used in self.restart (restart spyder instance)
os.environ['SPYDER_BOOTSTRAP_ARGS'] = str(sys.argv[1:])
assert args.gui in (None, 'pyqt5', 'pyside2'), \
"Invalid GUI toolkit option '%s'" % args.gui
# Start Spyder with a clean configuration directory for testing purposes
if args.safe_mode:
os.environ['SPYDER_SAFE_MODE'] = 'True'
# Prepare arguments for Spyder's main script
sys.argv = [sys.argv[0]] + args.spyder_options
print("Executing Spyder from source checkout")
DEVPATH = osp.dirname(osp.abspath(__file__))
# To activate/deactivate certain things for development
os.environ['SPYDER_DEV'] = 'True'
# --- Test environment for surprises
# Warn if Spyder is located on non-ASCII path
# See spyder-ide/spyder#812.
try:
osp.join(DEVPATH, 'test')
except UnicodeDecodeError:
print("STOP: Spyder is located in the path with non-ASCII characters,")
print(" which is known to cause problems, see spyder-ide/spyder#812.")
try:
input = raw_input
except NameError:
pass
input("Press Enter to continue or Ctrl-C to abort...")
# Warn if we're running under 3rd party exception hook, such as
# apport_python_hook.py from Ubuntu
if sys.excepthook != sys.__excepthook__:
if sys.excepthook.__name__ != 'apport_excepthook':
print("WARNING: 3rd party Python exception hook is active: '%s'"
% sys.excepthook.__name__)
else:
if not args.no_apport:
print("WARNING: Ubuntu Apport exception hook is detected")
print(" Use --no-apport option to disable it")
else:
sys.excepthook = sys.__excepthook__
print("NOTICE: Ubuntu Apport exception hook is disabed")
# --- Continue
if args.debug:
# safety check - Spyder config should not be imported at this point
if "spyder.config.base" in sys.modules:
sys.exit("ERROR: Can't enable debug mode - Spyder is already imported")
print("0x. Switching debug mode on")
os.environ["SPYDER_DEBUG"] = "3"
if len(args.filter_log) > 0:
print("*. Displaying log messages only from the "
"following modules: {0}".format(args.filter_log))
os.environ["SPYDER_FILTER_LOG"] = args.filter_log
# this way of interaction suxx, because there is no feedback
# if operation is successful
# Add this path to the front of sys.path
sys.path.insert(0, DEVPATH)
print("*. Patched sys.path with %s" % DEVPATH)
# Add external dependencies subrepo paths to be the next entries
# (1, 2, etc) of sys.path
DEPS_PATH = osp.join(DEVPATH, 'external-deps')
i = 1
for path in os.listdir(DEPS_PATH):
external_dep_path = osp.join(DEPS_PATH, path)
sys.path.insert(i, external_dep_path)
print("*. Patched sys.path with %s" % external_dep_path)
i += 1
# Create an egg-info folder to declare the PyLS subrepo entry points.
pyls_submodule = osp.join(DEPS_PATH, 'python-lsp-server')
pyls_installation_dir = osp.join(pyls_submodule, '.installation-dir')
pyls_installation_egg = osp.join(
pyls_submodule, 'python_lsp_server.egg-info')
def remove_pyls_installation():
shutil.rmtree(pyls_installation_dir, ignore_errors=True)
shutil.rmtree(pyls_installation_egg, ignore_errors=True)
if osp.exists(pyls_installation_dir) or osp.exists(pyls_installation_egg):
# Remove any leftover installation from previous execution
print("*. Removing previous PyLSP local installation.")
remove_pyls_installation()
# Install PyLS locally
print("*. Installing PyLSP locally")
subprocess.check_output(
[sys.executable,
'-W',
'ignore',
'setup.py',
'develop',
'--no-deps',
'--install-dir',
pyls_installation_dir],
env={**os.environ, **{'PYTHONPATH': pyls_installation_dir}},
cwd=pyls_submodule
)
atexit.register(remove_pyls_installation)
print("*. Declaring completion providers")
# Register completion providers
fallback = pkg_resources.EntryPoint.parse(
'fallback = spyder.plugins.completion.providers.fallback.provider:'
'FallbackProvider')
snippets = pkg_resources.EntryPoint.parse(
'snippets = spyder.plugins.completion.providers.snippets.provider:'
'SnippetsProvider'
)
lsp = pkg_resources.EntryPoint.parse(
'lsp = spyder.plugins.completion.providers.languageserver.provider:'
'LanguageServerProvider'
)
kite = pkg_resources.EntryPoint.parse(
'kite = spyder.plugins.completion.providers.kite.provider:'
'KiteProvider'
)
# Create a fake Spyder distribution
d = pkg_resources.Distribution(__file__)
# Add the providers to the fake EntryPoint
d._ep_map = {
'spyder.completions': {
'fallback': fallback,
'snippets': snippets,
'lsp': lsp,
'kite': kite
}
}
# Add the fake distribution to the global working_set
pkg_resources.working_set.add(d, 'spyder')
# Selecting the GUI toolkit: PyQt5 if installed
if args.gui is None:
try:
import PyQt5 # analysis:ignore
print("*. PyQt5 is detected, selecting")
os.environ['QT_API'] = 'pyqt5'
except ImportError:
sys.exit("ERROR: No PyQt5 detected!")
else:
print("*. Skipping GUI toolkit detection")
os.environ['QT_API'] = args.gui
# Checking versions (among other things, this has the effect of setting the
# QT_API environment variable if this has not yet been done just above)
from spyder import get_versions
versions = get_versions(reporev=True)
print("*. Imported Spyder %s - Revision %s, Branch: %s" %
(versions['spyder'], versions['revision'], versions['branch']))
print(" [Python %s %dbits, Qt %s, %s %s on %s]" %
(versions['python'], versions['bitness'], versions['qt'],
versions['qt_api'], versions['qt_api_ver'], versions['system']))
# Check that we have the right qtpy version
from spyder.utils import programs
if not programs.is_module_installed('qtpy', '>=1.1.0'):
print("")
sys.exit("ERROR: Your qtpy version is outdated. Please install qtpy "
"1.1.0 or higher to be able to work with Spyder!")
# --- Executing Spyder
if args.show_console:
print("(Deprecated) --show console does nothing, now the default behavior "
"is to show the console, use --hide-console if you want to hide it")
if args.hide_console and os.name == 'nt':
print("*. Hiding parent console (Windows only)")
sys.argv.append("--hide-console") # Windows only: show parent console
# Reset temporary config directory if starting in --safe-mode
if args.safe_mode or os.environ.get('SPYDER_SAFE_MODE'):
from spyder.config.base import get_conf_path # analysis:ignore
conf_dir = get_conf_path()
if osp.isdir(conf_dir):
shutil.rmtree(conf_dir)
print("*. Running Spyder")
from spyder.app import start # analysis:ignore
time_lapse = time.time() - time_start
print("Bootstrap completed in "
+ time.strftime("%H:%M:%S.", time.gmtime(time_lapse))
# gmtime() converts float into tuple, but loses milliseconds
+ ("%.4f" % time_lapse).split('.')[1])
start.main()