/
otherplugins.py
128 lines (102 loc) · 4.09 KB
/
otherplugins.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
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
"""
Spyder third-party plugins configuration management.
"""
# Standard library imports
import importlib
import logging
import os
import os.path as osp
import sys
import traceback
# Local imports
from spyder.config.base import get_conf_path
from spyder.py3compat import to_text_string
# Constants
logger = logging.getLogger(__name__)
USER_PLUGIN_DIR = "plugins"
PLUGIN_PREFIX = "spyder_"
IO_PREFIX = PLUGIN_PREFIX + "io_"
def get_spyderplugins_mods(io=False):
"""Import modules from plugins package and return the list"""
# Create user directory
user_plugin_path = osp.join(get_conf_path(), USER_PLUGIN_DIR)
if not osp.isdir(user_plugin_path):
os.makedirs(user_plugin_path)
modlist, modnames = [], []
# The user plugins directory is given the priority when looking for modules
for plugin_path in [user_plugin_path] + sys.path:
_get_spyderplugins(plugin_path, io, modnames, modlist)
return modlist
def _get_spyderplugins(plugin_path, is_io, modnames, modlist):
"""Scan the directory `plugin_path` for plugin packages and loads them."""
if not osp.isdir(plugin_path):
return
for name in os.listdir(plugin_path):
# This is needed in order to register the spyder_io_hdf5 plugin.
# See spyder-ide/spyder#4487.
# Is this a Spyder plugin?
if not name.startswith(PLUGIN_PREFIX):
continue
# Ensure right type of plugin
if is_io and not name.startswith(IO_PREFIX):
continue
# Skip names that end in certain suffixes
forbidden_suffixes = ['dist-info', 'egg.info', 'egg-info', 'egg-link',
'kernels']
if any([name.endswith(s) for s in forbidden_suffixes]):
continue
# Import the plugin
_import_plugin(name, plugin_path, modnames, modlist)
def _import_plugin(module_name, plugin_path, modnames, modlist):
"""Import the plugin `module_name` from `plugin_path`, add it to `modlist`
and adds its name to `modnames`.
"""
if module_name in modnames:
return
try:
# First add a mock module with the LOCALEPATH attribute so that the
# helper method can find the locale on import
mock = _ModuleMock()
mock.LOCALEPATH = osp.join(plugin_path, module_name, 'locale')
sys.modules[module_name] = mock
if osp.isdir(osp.join(plugin_path, module_name)):
module = _import_module_from_path(module_name, plugin_path)
else:
module = None
# Then restore the actual loaded module instead of the mock
if module and getattr(module, 'PLUGIN_CLASS', False):
sys.modules[module_name] = module
modlist.append(module)
modnames.append(module_name)
except Exception as e:
sys.stderr.write("ERROR: 3rd party plugin import failed for "
"`{0}`\n".format(module_name))
traceback.print_exc(file=sys.stderr)
def _import_module_from_path(module_name, plugin_path):
"""Imports `module_name` from `plugin_path`.
Return None if no module is found.
"""
module = None
try:
spec = importlib.machinery.PathFinder.find_spec(
module_name,
[plugin_path])
if spec:
module = spec.loader.load_module(module_name)
except Exception as err:
debug_message = ("plugin: '{module_name}' load failed with `{err}`"
"").format(module_name=module_name,
err=to_text_string(err))
logger.debug(debug_message)
return module
class _ModuleMock():
"""This mock module is added to sys.modules on plugin load to add the
location of the LOCALEDATA so that the module loads succesfully.
Once loaded the module is replaced by the actual loaded module object.
"""
pass