1diff --git a/sopel/plugins/handlers.py b/sopel/plugins/handlers.py
2index 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
6
7 import imp
8 import importlib
9+import importlib.util
10 import inspect
11 import itertools
12 import os
13+import sys
14
15 from sopel import loader
16 from . import exceptions
17
18-try:
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
23- reload = imp.reload
24-
25
26 class AbstractPluginHandler(object):
27 """Base class for plugin handlers.
28@@ -301,7 +296,7 @@ class PyModulePlugin(AbstractPluginHandler):
29
30 This method assumes the plugin is already loaded.
31 """
32- self._module = reload(self._module)
33+ self._module = importlib.reload(self._module)
34
35 def is_loaded(self):
36 return self._module is not None
37@@ -402,45 +397,31 @@ class PyFilePlugin(PyModulePlugin):
38
39 if good_file:
40 name = os.path.basename(filename)[:-3]
41- module_type = imp.PY_SOURCE
42+ spec = importlib.util.spec_from_file_location(
43+ name,
44+ filename,
45+ )
46 elif good_dir:
47 name = os.path.basename(filename)
48- module_type = imp.PKG_DIRECTORY
49+ spec = importlib.util.spec_from_file_location(
50+ name,
51+ os.path.join(filename, '__init__.py'),
52+ submodule_search_locations=filename,
53+ )
54 else:
55 raise exceptions.PluginError('Invalid Sopel plugin: %s' % filename)
56
57 self.filename = filename
58 self.path = filename
59- self.module_type = module_type
60+ self.module_spec = spec
61
62 super(PyFilePlugin, self).__init__(name)
63
64 def _load(self):
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.
69- #
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``).
74- #
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.
77- #
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)
86- else:
87- raise TypeError('Unsupported module type')
88-
89- return mod
90+ module = importlib.util.module_from_spec(self.module_spec)
91+ sys.modules[self.name] = module
92+ self.module_spec.loader.exec_module(module)
93+ return module
94
95 def get_meta_description(self):
96 """Retrieve a meta description for the plugin.