1 diff --git a/sopel/plugins/handlers.py b/sopel/plugins/handlers.py
2 index 76902aa0..05f0279d 100644
3 --- a/sopel/plugins/handlers.py
4 +++ b/sopel/plugins/handlers.py
5 @@ -46,20 +46,15 @@ from __future__ import absolute_import, division, print_function, unicode_litera
15 from sopel import loader
16 from . import exceptions
19 - reload = importlib.reload
20 -except AttributeError:
21 - # py2: no reload function
22 - # TODO: imp is deprecated, to be removed when py2 support is dropped
26 class AbstractPluginHandler(object):
27 """Base class for plugin handlers.
28 @@ -301,7 +296,7 @@ class PyModulePlugin(AbstractPluginHandler):
30 This method assumes the plugin is already loaded.
32 - self._module = reload(self._module)
33 + self._module = importlib.reload(self._module)
36 return self._module is not None
37 @@ -402,45 +397,31 @@ class PyFilePlugin(PyModulePlugin):
40 name = os.path.basename(filename)[:-3]
41 - module_type = imp.PY_SOURCE
42 + spec = importlib.util.spec_from_file_location(
47 name = os.path.basename(filename)
48 - module_type = imp.PKG_DIRECTORY
49 + spec = importlib.util.spec_from_file_location(
51 + os.path.join(filename, '__init__.py'),
52 + submodule_search_locations=filename,
55 raise exceptions.PluginError('Invalid Sopel plugin: %s' % filename)
57 self.filename = filename
59 - self.module_type = module_type
60 + self.module_spec = spec
62 super(PyFilePlugin, self).__init__(name)
65 - # The current implementation uses `imp.load_module` to perform the
66 - # load action, which also reloads the module. However, `imp` is
67 - # deprecated in Python 3, so that might need to be changed when the
68 - # support for Python 2 is dropped.
70 - # However, the solution for Python 3 is non-trivial, since the
71 - # `importlib` built-in module does not have a similar function,
72 - # therefore requires to dive into its public internals
73 - # (``importlib.machinery`` and ``importlib.util``).
75 - # All of that is doable, but represents a lot of work. As long as
76 - # Python 2 is supported, we can keep it for now.
78 - # TODO: switch to ``importlib`` when Python2 support is dropped.
79 - if self.module_type == imp.PY_SOURCE:
80 - with open(self.path) as mod:
81 - description = ('.py', 'U', self.module_type)
82 - mod = imp.load_module(self.name, mod, self.path, description)
83 - elif self.module_type == imp.PKG_DIRECTORY:
84 - description = ('', '', self.module_type)
85 - mod = imp.load_module(self.name, None, self.path, description)
87 - raise TypeError('Unsupported module type')
90 + module = importlib.util.module_from_spec(self.module_spec)
91 + sys.modules[self.name] = module
92 + self.module_spec.loader.exec_module(module)
95 def get_meta_description(self):
96 """Retrieve a meta description for the plugin.