Skip to content

Commit 3507f5b

Browse files
committed
Add plugin entry points and plugin dependency sorting
1 parent d77da8d commit 3507f5b

11 files changed

Lines changed: 812 additions & 66 deletions

File tree

NOTICE.txt

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,59 @@ Files covered:
10901090
spyder/plugins/onlinehelp/pydoc_patch.py
10911091

10921092

1093+
-------------------------------------------------------------------------------
1094+
1095+
1096+
1097+
toposort 1.5
1098+
------------
1099+
1100+
1101+
Copyright 2014 True Blade Systems, Inc.
1102+
1103+
1104+
Author: Eric V. Smith | eric@trueblade.com | https://bitbucket.org/ericvsmith
1105+
Site: https://pypi.org/project/toposort/
1106+
Source: https://bitbucket.org/ericvsmith/toposort/src
1107+
License: Apache License 2.0 | https://www.apache.org/licenses/LICENSE-2.0
1108+
1109+
No modifications made.
1110+
1111+
1112+
Copyright 2014 True Blade Systems, Inc.
1113+
1114+
Licensed under the Apache License, Version 2.0 (the "License");
1115+
you may not use this file except in compliance with the License.
1116+
You may obtain a copy of the License at
1117+
1118+
http://www.apache.org/licenses/LICENSE-2.0
1119+
1120+
Unless required by applicable law or agreed to in writing, software
1121+
distributed under the License is distributed on an "AS IS" BASIS,
1122+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1123+
See the License for the specific language governing permissions and
1124+
limitations under the License.
1125+
1126+
1127+
Use the core functionlity to sort plugin dependencies.
1128+
1129+
1130+
See below for the full text of the Apache License, Version 2.0
1131+
1132+
The current toposort license can be viewed at:
1133+
https://bitbucket.org/ericvsmith/toposort/src/default/LICENSE.txt
1134+
1135+
The current version of the original files can be viewed at:
1136+
https://bitbucket.org/ericvsmith/toposort/src/default/toposort.py
1137+
1138+
1139+
Files covered:
1140+
1141+
spyder/utils/external/toposort/__init__.py
1142+
spyder/utils/external/toposort/toposort.py
1143+
spyder/utils/external/toposort/LICENSE.txt
1144+
1145+
10931146
===============================================================================
10941147

10951148

setup.py

Lines changed: 101 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -21,47 +21,52 @@
2121

2222
from __future__ import print_function
2323

24+
# Standard library imports
25+
from distutils.command.install_data import install_data
2426
import io
2527
import os
2628
import os.path as osp
2729
import subprocess
2830
import sys
2931
import shutil
3032

31-
from distutils.core import setup
32-
from distutils.command.install_data import install_data
33+
# Third party imports
34+
from setuptools import setup, find_packages
35+
from setuptools.command.install import install
3336

3437

35-
#==============================================================================
38+
# =============================================================================
3639
# Check for Python 3
37-
#==============================================================================
40+
# =============================================================================
3841
PY3 = sys.version_info[0] == 3
3942

4043

41-
#==============================================================================
44+
# =============================================================================
4245
# Minimal Python version sanity check
4346
# Taken from the notebook setup.py -- Modified BSD License
44-
#==============================================================================
47+
# =============================================================================
4548
v = sys.version_info
4649
if v[0] >= 3 and v[:2] < (3, 6):
4750
error = "ERROR: Spyder 5 requires Python version 3.6 or above."
4851
print(error, file=sys.stderr)
4952
sys.exit(1)
5053

5154

52-
#==============================================================================
55+
# =============================================================================
5356
# Constants
54-
#==============================================================================
57+
# =============================================================================
5558
NAME = 'spyder'
5659
LIBNAME = 'spyder'
5760
from spyder import __version__, __website_url__ #analysis:ignore
5861

5962

60-
#==============================================================================
63+
# =============================================================================
6164
# Auxiliary functions
62-
#==============================================================================
65+
# =============================================================================
6366
def get_package_data(name, extlist):
64-
"""Return data files for package *name* with extensions in *extlist*"""
67+
"""
68+
Return data files for package *name* with extensions in *extlist*.
69+
"""
6570
flist = []
6671
# Workaround to replace os.path.relpath (not available until Python 2.6):
6772
offset = len(name)+len(os.pathsep)
@@ -75,17 +80,22 @@ def get_package_data(name, extlist):
7580

7681

7782
def get_subpackages(name):
78-
"""Return subpackages of package *name*"""
83+
"""
84+
Return subpackages of package *name*.
85+
"""
7986
splist = []
8087
for dirpath, _dirnames, _filenames in os.walk(name):
8188
if 'tests' not in dirpath:
8289
if osp.isfile(osp.join(dirpath, '__init__.py')):
8390
splist.append(".".join(dirpath.split(os.sep)))
91+
8492
return splist
8593

8694

8795
def get_data_files():
88-
"""Return data_files in a platform dependent manner"""
96+
"""
97+
Return data_files in a platform dependent manner.
98+
"""
8999
if sys.platform.startswith('linux'):
90100
if PY3:
91101
data_files = [('share/applications', ['scripts/spyder3.desktop']),
@@ -99,19 +109,23 @@ def get_data_files():
99109
'img_src/spyder_reset.ico'])]
100110
else:
101111
data_files = []
112+
102113
return data_files
103114

104115

105116
def get_packages():
106-
"""Return package list"""
117+
"""
118+
Return package list.
119+
"""
107120
packages = get_subpackages(LIBNAME)
108121
return packages
109122

110123

111-
#==============================================================================
112-
# Make Linux detect Spyder desktop file
113-
#==============================================================================
114-
class MyInstallData(install_data):
124+
# =============================================================================
125+
# Make Linux detect Spyder desktop file (will not work with wheels)
126+
# =============================================================================
127+
class CustomInstallData(install_data):
128+
115129
def run(self):
116130
install_data.run(self)
117131
if sys.platform.startswith('linux'):
@@ -120,12 +134,14 @@ def run(self):
120134
except:
121135
print("ERROR: unable to update desktop database",
122136
file=sys.stderr)
123-
CMDCLASS = {'install_data': MyInstallData}
124137

125138

126-
#==============================================================================
139+
CMDCLASS = {'install_data': CustomInstallData}
140+
141+
142+
# =============================================================================
127143
# Main scripts
128-
#==============================================================================
144+
# =============================================================================
129145
# NOTE: the '[...]_win_post_install.py' script is installed even on non-Windows
130146
# platforms due to a bug in pip installation process
131147
# See spyder-ide/spyder#1158.
@@ -139,17 +155,18 @@ def run(self):
139155
if os.name == 'nt':
140156
SCRIPTS += ['spyder.bat']
141157

142-
#==============================================================================
158+
159+
# =============================================================================
143160
# Files added to the package
144-
#==============================================================================
161+
# =============================================================================
145162
EXTLIST = ['.pot', '.po', '.mo', '.svg', '.png', '.css', '.html', '.js',
146163
'.ini', '.txt', '.qss', '.ttf', '.json', '.rst', '.bloom',
147164
'.ico', '.gif', '.mp3', '.ogg', '.sfd', '.bat', '.sh']
148165

149166

150-
#==============================================================================
167+
# =============================================================================
151168
# Use Readme for long description
152-
#==============================================================================
169+
# =============================================================================
153170
with io.open('README.md', encoding='utf-8') as f:
154171
LONG_DESCRIPTION = f.read()
155172

@@ -165,7 +182,7 @@ def run(self):
165182
long_description_content_type='text/markdown',
166183
download_url=__website_url__ + "#fh5co-download",
167184
author="The Spyder Project Contributors",
168-
author_email="spyderlib@googlegroups.com",
185+
author_email="info@spyder-ide.org",
169186
url=__website_url__,
170187
license='MIT',
171188
keywords='PyQt5 editor console widgets IDE science data analysis IPython',
@@ -174,32 +191,26 @@ def run(self):
174191
package_data={LIBNAME: get_package_data(LIBNAME, EXTLIST)},
175192
scripts=[osp.join('scripts', fname) for fname in SCRIPTS],
176193
data_files=get_data_files(),
177-
classifiers=['License :: OSI Approved :: MIT License',
178-
'Operating System :: MacOS',
179-
'Operating System :: Microsoft :: Windows',
180-
'Operating System :: POSIX :: Linux',
181-
'Programming Language :: Python :: 2',
182-
'Programming Language :: Python :: 2.7',
183-
'Programming Language :: Python :: 3',
184-
'Programming Language :: Python :: 3.4',
185-
'Programming Language :: Python :: 3.5',
186-
'Programming Language :: Python :: 3.6',
187-
'Programming Language :: Python :: 3.7',
188-
'Development Status :: 5 - Production/Stable',
189-
'Intended Audience :: Education',
190-
'Intended Audience :: Science/Research',
191-
'Intended Audience :: Developers',
192-
'Topic :: Scientific/Engineering',
193-
'Topic :: Software Development :: Widget Sets'],
194-
cmdclass=CMDCLASS)
194+
classifiers=[
195+
'License :: OSI Approved :: MIT License',
196+
'Operating System :: MacOS',
197+
'Operating System :: Microsoft :: Windows',
198+
'Operating System :: POSIX :: Linux',
199+
'Programming Language :: Python :: 3',
200+
'Programming Language :: Python :: 3.6',
201+
'Programming Language :: Python :: 3.7',
202+
'Programming Language :: Python :: 3.8',
203+
'Development Status :: 5 - Production/Stable',
204+
'Intended Audience :: Education',
205+
'Intended Audience :: Science/Research',
206+
'Intended Audience :: Developers',
207+
'Topic :: Scientific/Engineering',
208+
'Topic :: Software Development :: Widget Sets',
209+
],
210+
cmdclass=CMDCLASS,
211+
)
195212

196213

197-
#==============================================================================
198-
# Setuptools deps
199-
#==============================================================================
200-
if any(arg == 'bdist_wheel' for arg in sys.argv):
201-
import setuptools # analysis:ignore
202-
203214
install_requires = [
204215
'applaunchservices>=0.1.7;platform_system=="Darwin"',
205216
'atomicwrites>=1.2.0',
@@ -264,21 +275,49 @@ def run(self):
264275
],
265276
}
266277

267-
if 'setuptools' in sys.modules:
268-
setup_args['install_requires'] = install_requires
269-
setup_args['extras_require'] = extras_require
270278

271-
setup_args['entry_points'] = {
272-
'gui_scripts': [
273-
'{} = spyder.app.start:main'.format(
274-
'spyder3' if PY3 else 'spyder')
275-
]
276-
}
279+
spyder_plugins_entry_points = [
280+
'appearance = spyder.plugins.appearance.plugin:Appearance',
281+
'breakpoints = spyder.plugins.breakpoints.plugin:Breakpoints',
282+
'code_completion = spyder.plugins.completions.plugin:CodeCompletion',
283+
'core = spyder.plugins.core.plugin:Core',
284+
'editor = spyder.plugins.editor.plugin:Editor',
285+
'explorer = spyder.plugins.explorer.plugin:Explorer',
286+
'fallback_completion = spyder.plugins.fallback.plugin:FallbackCompletion',
287+
'findinfiles = spyder.plugins.findinfiles.plugin:FindInFiles',
288+
'help = spyder.plugins.help.plugin:Help',
289+
'history = spyder.plugins.history.plugin:HistoryLog',
290+
'ipythonconsole = spyder.plugins.ipythonconsole.plugin:IPythonConsole',
291+
'kite_completion = spyder.plugins.kite.plugin:LanguageServerCompletion',
292+
'onlinehelp = spyder.plugins.onlinehelp.plugin:OnlineHelp',
293+
'outlineexplorer = spyder.plugins.outlineexplorer.plugin:OutlineExplorer',
294+
'plots = spyder.plugins.plots.plugin:Plots',
295+
'profiler = spyder.plugins.profiler.plugin:Profiler',
296+
'projects = spyder.plugins.projects.plugin:Projects',
297+
'pylint = spyder.plugins.pylint.plugin:Pylint',
298+
('lsp_completion = spyder.plugins.languageserver.plugin:'
299+
'LanguageServerCompletion'),
300+
'python = spyder.plugins.python.plugin:Python',
301+
('variableexplorer = spyder.plugins.variableexplorer.plugin:'
302+
'VariableExplorer'),
303+
('workingdirectory = spyder.plugins.workingdirectory.plugin:'
304+
'WorkingDirectory'),
305+
]
306+
277307

278-
setup_args.pop('scripts', None)
308+
setup_args['install_requires'] = install_requires
309+
setup_args['extras_require'] = extras_require
310+
setup_args['entry_points'] = {
311+
'gui_scripts': [
312+
'{} = spyder.app.start:main'.format(
313+
'spyder3' if PY3 else 'spyder')
314+
],
315+
'spyder.plugins': spyder_plugins_entry_points,
316+
}
317+
setup_args.pop('scripts', None)
279318

280319

281-
#==============================================================================
320+
# =============================================================================
282321
# Main setup
283-
#==============================================================================
322+
# =============================================================================
284323
setup(**setup_args)

spyder/api/plugins.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,7 +1411,7 @@ def add_application_status_widget(self, name, widget):
14111411
# TODO: Check widget class
14121412
# TODO: Check existence
14131413
status_bar = self._main.statusBar()
1414-
status_bar.addWidget(widget)
1414+
status_bar.insertPermanentWidget(0, widget)
14151415
self._main._STATUS_WIDGETS[name] = widget
14161416

14171417
def get_application_status_widget(self, name):

spyder/app/mainwindow.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,11 @@
199199
MENU_SEPARATOR, set_menu_icons)
200200
from spyder.otherplugins import get_spyderplugins_mods
201201
from spyder.app import tour
202+
from spyder.app.solver import find_external_plugins, solve_plugin_dependencies
202203

203204
# Spyder API Imports
204205
from spyder.api.exceptions import SpyderAPIError
205-
from spyder.api.plugins import Plugins, SpyderDockablePlugin
206+
from spyder.api.plugins import Plugins, SpyderPluginV2, SpyderDockablePlugin
206207

207208
#==============================================================================
208209
# Third-party library imports
@@ -1132,6 +1133,8 @@ def create_edit_action(text, tr_text, icon):
11321133
self.console.set_exit_function(self.closing)
11331134
self.register_plugin(self.console)
11341135

1136+
# TODO: Load and register the rest of the plugins using new API
1137+
11351138
# Code completion client initialization
11361139
self.set_splash(_("Starting code completion manager..."))
11371140
from spyder.plugins.completion.plugin import CompletionManager
@@ -1308,6 +1311,21 @@ def create_edit_action(text, tr_text, icon):
13081311
print("%s: %s" % (mod, str(error)), file=STDERR)
13091312
traceback.print_exc(file=STDERR)
13101313

1314+
# New API: Load and register external plugins
1315+
external_plugins = find_external_plugins()
1316+
plugin_deps = solve_plugin_dependencies(external_plugins.values())
1317+
for plugin_class in plugin_deps:
1318+
if issubclass(plugin_class, SpyderPluginV2):
1319+
try:
1320+
plugin_instance = plugin_class(
1321+
self,
1322+
configuration=CONF,
1323+
)
1324+
self.register_plugin(plugin_instance)
1325+
except Exception as error:
1326+
print("%s: %s" % (plugin_class, str(error)), file=STDERR)
1327+
traceback.print_exc(file=STDERR)
1328+
13111329
self.set_splash(_("Setting up main window..."))
13121330

13131331
# Help menu

0 commit comments

Comments
 (0)