Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sopel: fix TODOs related to Python 2 #2326

Merged
merged 3 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions sopel/modules/currency.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,7 @@ def exchange(bot, match):
LOGGER.error(err)
return

query = match.string

targets = query.split()
amount_in = targets.pop(0)
base = targets.pop(0)
targets.pop(0)

# TODO: Use this instead after dropping Python 2 support
# amount, base, _, *targets = query.split()
amount_in, base, _, *targets = match.string.split()

try:
amount = float(amount_in)
Expand Down
54 changes: 17 additions & 37 deletions sopel/plugins/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,17 @@
from __future__ import annotations

import abc
import imp
import importlib
import importlib.util
import inspect
import itertools
import os
import sys
from typing import Optional

from sopel import __version__ as release, loader
from . import exceptions

try:
reload = importlib.reload
except AttributeError:
# py2: no reload function
# TODO: imp is deprecated, to be removed when py2 support is dropped
reload = imp.reload


class AbstractPluginHandler(abc.ABC):
"""Base class for plugin handlers.
Expand Down Expand Up @@ -331,7 +325,7 @@ def reload(self):

This method assumes the plugin is already loaded.
"""
self._module = reload(self._module)
self._module = importlib.reload(self._module)

def is_loaded(self):
return self._module is not None
Expand Down Expand Up @@ -432,45 +426,31 @@ def __init__(self, filename):

if good_file:
name = os.path.basename(filename)[:-3]
module_type = imp.PY_SOURCE
spec = importlib.util.spec_from_file_location(
name,
filename,
)
elif good_dir:
name = os.path.basename(filename)
module_type = imp.PKG_DIRECTORY
spec = importlib.util.spec_from_file_location(
name,
os.path.join(filename, '__init__.py'),
submodule_search_locations=filename,
)
else:
raise exceptions.PluginError('Invalid Sopel plugin: %s' % filename)

self.filename = filename
self.path = filename
self.module_type = module_type
self.module_spec = spec

super().__init__(name)

def _load(self):
# The current implementation uses `imp.load_module` to perform the
# load action, which also reloads the module. However, `imp` is
# deprecated in Python 3, so that might need to be changed when the
# support for Python 2 is dropped.
#
# However, the solution for Python 3 is non-trivial, since the
# `importlib` built-in module does not have a similar function,
# therefore requires to dive into its public internals
# (``importlib.machinery`` and ``importlib.util``).
#
# All of that is doable, but represents a lot of work. As long as
# Python 2 is supported, we can keep it for now.
#
# TODO: switch to ``importlib`` when Python2 support is dropped.
if self.module_type == imp.PY_SOURCE:
with open(self.path) as mod:
description = ('.py', 'U', self.module_type)
mod = imp.load_module(self.name, mod, self.path, description)
elif self.module_type == imp.PKG_DIRECTORY:
description = ('', '', self.module_type)
mod = imp.load_module(self.name, None, self.path, description)
else:
raise TypeError('Unsupported module type')

return mod
module = importlib.util.module_from_spec(self.module_spec)
sys.modules[self.name] = module
self.module_spec.loader.exec_module(module)
return module

def get_meta_description(self):
"""Retrieve a meta description for the plugin.
Expand Down
11 changes: 5 additions & 6 deletions sopel/tests/mocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,13 @@ class MockIRCServer:
def __init__(self, bot, join_threads=True):
self.bot = bot
self.join_threads = join_threads
# TODO: `blocking` method args below should be made kwarg-ONLY in py3

@property
def chanserv(self):
"""ChanServ's message prefix."""
return 'ChanServ!ChanServ@services.'

def channel_joined(self, channel, users=None, blocking=None):
def channel_joined(self, channel, users=None, *, blocking=None):
"""Send events as if the bot just joined a channel.

:param str channel: channel to send message for
Expand Down Expand Up @@ -195,7 +194,7 @@ def channel_joined(self, channel, users=None, blocking=None):
for t in self.bot.running_triggers:
t.join()

def mode_set(self, channel, flags, users, blocking=None):
def mode_set(self, channel, flags, users, *, blocking=None):
"""Send a MODE event for a ``channel``

:param str channel: channel receiving the MODE event
Expand Down Expand Up @@ -237,7 +236,7 @@ def mode_set(self, channel, flags, users, blocking=None):
for t in self.bot.running_triggers:
t.join()

def join(self, user, channel, blocking=None):
def join(self, user, channel, *, blocking=None):
"""Send a ``channel`` JOIN event from ``user``.

:param user: factory for the user who joins the ``channel``
Expand Down Expand Up @@ -275,7 +274,7 @@ def join(self, user, channel, blocking=None):
for t in self.bot.running_triggers:
t.join()

def say(self, user, channel, text, blocking=None):
def say(self, user, channel, text, *, blocking=None):
"""Send a ``PRIVMSG`` to ``channel`` by ``user``.

:param user: factory for the user who sends a message to ``channel``
Expand Down Expand Up @@ -314,7 +313,7 @@ def say(self, user, channel, text, blocking=None):
for t in self.bot.running_triggers:
t.join()

def pm(self, user, text, blocking=None):
def pm(self, user, text, *, blocking=None):
"""Send a ``PRIVMSG`` to the bot by a ``user``.

:param user: factory for the user object who sends a message
Expand Down