Skip to content

Commit

Permalink
Merge pull request #3210 from Nodd/flask_plugin_model
Browse files Browse the repository at this point in the history
PR: Follow the Flask plugin model instead of namespace packages
  • Loading branch information
ccordoba12 authored Jun 11, 2016
2 parents a1f0541 + 3b3c9c0 commit e4959e5
Show file tree
Hide file tree
Showing 54 changed files with 86 additions and 165 deletions.
2 changes: 1 addition & 1 deletion continuous_integration/travis/modules_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ for f in spyderlib/*/*/*.py; do
done

# Spyderplugins
for f in spyplugins/ui/*/widgets/*.py; do
for f in spyder_*/widgets/*.py; do
python "$f"
if [ $? -ne 0 ]; then
exit 1
Expand Down
6 changes: 3 additions & 3 deletions gettext_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

if __name__ == "__main__":
do_compile("spyderlib")
do_compile("pylint", "spyplugins/ui/pylint")
do_compile("profiler", "spyplugins/ui/profiler")
do_compile("breakpoints", "spyplugins/ui/breakpoints")
do_compile("pylint", "spyder_pylint")
do_compile("profiler", "spyder_profiler")
do_compile("breakpoints", "spyder_breakpoints")
19 changes: 9 additions & 10 deletions gettext_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@

if __name__ == "__main__":
do_rescan("spyderlib")
do_rescan_files(["spyplugins/ui/pylint/pylint.py",
"spyplugins/ui/pylint/widgets/pylintgui.py"],
"pylint", "spyplugins/ui/pylint")
do_rescan_files(["spyplugins/ui/profiler/profiler.py",
"spyplugins/ui/profiler/widgets/profilergui.py"],
"profiler", "spyplugins/ui/profiler")
do_rescan_files(["spyplugins/ui/breakpoints/breakpoints.py",
"spyplugins/ui/breakpoints/widgets/breakpointsgui.py"],
"breakpoints", "spyplugins/ui/breakpoints")

do_rescan_files(["spyder_pylint/pylint.py",
"spyder_pylint/widgets/pylintgui.py"],
"pylint", "spyder_pylint")
do_rescan_files(["spyder_profiler/profiler.py",
"spyder_profiler/widgets/profilergui.py"],
"profiler", "spyder_profiler")
do_rescan_files(["spyder_breakpoints/breakpoints.py",
"spyder_breakpoints/widgets/breakpointsgui.py"],
"breakpoints", "spyder_breakpoints")
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ def run(self):
platforms=['any'],
packages=get_packages(),
package_data={LIBNAME: get_package_data(LIBNAME, EXTLIST),
'spyplugins': get_package_data('spyplugins', EXTLIST),
'spyder_breakpoints': get_package_data('spyder_breakpoints', EXTLIST),
'spyder_profiler': get_package_data('spyder_profiler', EXTLIST),
'spyder_pylint': get_package_data('spyder_pylint', EXTLIST),
'spyder_io_dcm': get_package_data('spyder_io_dcm', EXTLIST),
'spyder_io_hdf5': get_package_data('spyder_io_hdf5', EXTLIST),
},
scripts=[osp.join('scripts', fname) for fname in SCRIPTS],
data_files=get_data_files(),
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from spyderlib.py3compat import to_text_string, is_text_string
from .widgets.breakpointsgui import BreakpointWidget

_ = get_translation("breakpoints", "spyplugins.ui.breakpoints")
_ = get_translation("breakpoints", "spyder_breakpoints")


class Breakpoints(BreakpointWidget, SpyderPluginMixin):
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .widgets.profilergui import (ProfilerWidget, is_profiler_installed)


_ = get_translation("profiler", "spyplugins.ui.profiler")
_ = get_translation("profiler", "spyder_profiler")


class ProfilerConfigPage(PluginConfigPage):
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
2 changes: 1 addition & 1 deletion spyplugins/ui/pylint/pylint.py → spyder_pylint/pylint.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from .widgets.pylintgui import (PYLINT_PATH, PylintWidget)


_ = get_translation("pylint", "spyplugins.ui.pylint")
_ = get_translation("pylint", "spyder_pylint")


class PylintConfigPage(PluginConfigPage):
Expand Down
File renamed without changes.
File renamed without changes.
175 changes: 65 additions & 110 deletions spyderlib/otherplugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,80 +8,69 @@
Spyder third-party plugins configuration management
"""

import importlib
import os
import os.path as osp
import sys
import traceback

# Local imports
from spyderlib.config.base import get_conf_path
from spyderlib.py3compat import PY2, PY3, PY33
from spyderlib.py3compat import PY2

if PY2:
import imp
else:
import importlib


def _get_spyderplugins(plugin_path, base_namespace, plugins_namespace,
modnames, modlist):
"""Scan the directory `plugin_path` for plugins_namespace package and
loads its submodules."""
namespace_path = osp.join(plugin_path, base_namespace, plugins_namespace)
PLUGIN_PREFIX = "spyder_"
IO_PREFIX = PLUGIN_PREFIX + "io_"

if not osp.exists(namespace_path):
return

dirs = []
for d in os.listdir(namespace_path):
path = osp.join(namespace_path, d)
if osp.isdir(path):
dirs.append(path)

for dirname in dirs:
name = osp.basename(dirname)
if name == "__pycache__":
continue
_import_plugin(name, base_namespace, plugins_namespace,
namespace_path, modnames, modlist)
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(), "spyplugins")
if not osp.isdir(user_plugin_path):
os.makedirs(user_plugin_path)

modlist, modnames = [], []

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
# 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):
if is_io and not name.startswith(IO_PREFIX):
continue
if not name.startswith(PLUGIN_PREFIX) or name.startswith(IO_PREFIX):
continue

# Import the plugin
_import_plugin(name, plugin_path, modnames, modlist)

def _import_plugin(name, base_namespace, plugin_namespace, namespace_path,
modnames, modlist):
"""Import the plugin `plugins_namsepace`.`name`, add it to `modlist` and
adds its name to `modnames`."""
module_name = "{0}.{1}.{2}".format(base_namespace, plugin_namespace, name)

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(namespace_path, name, 'locale')
mock.LOCALEPATH = osp.join(plugin_path, 'locale')
sys.modules[module_name] = mock
module = None
if PY33:
loader = importlib.machinery.PathFinder.find_module(
name, [namespace_path])
if loader:
module = loader.load_module(name)
elif PY3:
spec = importlib.machinery.PathFinder.find_spec(name,
[namespace_path])
if spec:
module = spec.loader.load_module(name)
else:
info = imp.find_module(name, [namespace_path])
if info:
module = imp.load_module(module_name, *info)

module = _import_module_from_path(module_name, plugin_path)

# Then restore the actual loaded module instead of the mock
if module:
Expand All @@ -94,68 +83,34 @@ def _import_plugin(name, base_namespace, plugin_namespace, namespace_path,
traceback.print_exc(file=sys.stderr)


def create_userplugins_files(path):
"""
Create userplugins namespace dirs and files if not present in .spyder* dir
"""
if not osp.isdir(path):
os.makedirs(path)

init_file = "__init__.py"
init_file_content = """# -*- coding: utf-8 -*-
'''
'spyplugins' makes uses of namespace packages to keep different plugins
organized in the sitepackages directory and in the user directory.
def _import_module_from_path(module_name, plugin_path):
"""Imports `module_name` from `plugin_path`.
Spyder plugins can be of 'io' type or 'ui' type. Each type also makes use
of namespace packages.
For more information on namespace packages visit:
- https://www.python.org/dev/peps/pep-0382/
- https://www.python.org/dev/peps/pep-0420/
'''
# Declare as a namespace package
__import__('pkg_resources').declare_namespace(__name__)
"""
data = ""
new_path = osp.join(path, init_file)
if osp.isfile(new_path):
with open(new_path, "r") as f:
data = f.read()

if not (osp.isfile(new_path) and data == init_file_content):
with open(new_path, "w") as f:
f.write(init_file_content)


def get_spyderplugins_mods(io=False):
"""Import modules from plugins package and return the list"""
base_namespace = "spyplugins"

if io:
plugins_namespace = "io"
else:
plugins_namespace = "ui"

namespace = '.'.join([base_namespace, plugins_namespace])

# Import parent module
importlib.import_module(namespace)

# Create user directory
user_conf_path = get_conf_path()
user_plugin_basepath = osp.join(user_conf_path, base_namespace)
user_plugin_path = osp.join(user_conf_path, base_namespace,
plugins_namespace)

create_userplugins_files(user_plugin_basepath)
create_userplugins_files(user_plugin_path)
Return None if no module is found.
"""
module = None
if PY2:
info = imp.find_module(module_name, [plugin_path])
if info:
module = imp.load_module(module_name, *info)
elif sys.version_info[0:2] <= (3, 3):
loader = importlib.machinery.PathFinder.find_module(
module_name,
[plugin_path])
if loader:
module = loader.load_module(module_name)
else: # Python 3.4+
spec = importlib.machinery.PathFinder.find_spec(
module_name,
[plugin_path])
if spec:
module = spec.loader.load_module(module_name)
return module

modlist, modnames = [], []

# The user plugins directory is given the priority when looking for modules
for plugin_path in [user_conf_path] + sys.path:
_get_spyderplugins(plugin_path, base_namespace, plugins_namespace,
modnames, modlist)
return modlist
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
1 change: 0 additions & 1 deletion spyderlib/py3compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

PY2 = sys.version[0] == '2'
PY3 = sys.version[0] == '3'
PY33 = sys.version_info[0:2] >= (3, 3)

#==============================================================================
# Data types
Expand Down
12 changes: 0 additions & 12 deletions spyplugins/__init__.py

This file was deleted.

12 changes: 0 additions & 12 deletions spyplugins/io/__init__.py

This file was deleted.

12 changes: 0 additions & 12 deletions spyplugins/ui/__init__.py

This file was deleted.

0 comments on commit e4959e5

Please sign in to comment.