From 7c3e309763a062d2a574fa5aeda5b232704d108b Mon Sep 17 00:00:00 2001 From: Alexandre Detiste Date: Thu, 5 Dec 2024 08:42:44 +0100 Subject: [PATCH] remove Python2 support --- setup.py | 13 +++---------- tests/entrypoints/test_not_configured.py | 2 +- tests/rules/test_gem_unknown_command.py | 4 +++- tests/rules/test_ifconfig_device_not_found.py | 4 +++- tests/test_conf.py | 4 ++-- thefuck/conf.py | 3 +-- thefuck/entrypoints/alias.py | 8 +------- thefuck/entrypoints/not_configured.py | 4 +--- thefuck/output_readers/read_log.py | 6 ------ thefuck/output_readers/rerun.py | 4 ---- thefuck/rules/cd_correction.py | 3 --- thefuck/shells/fish.py | 6 +----- thefuck/shells/generic.py | 11 +---------- thefuck/specific/sudo.py | 3 +-- thefuck/utils.py | 18 +++++------------- 15 files changed, 23 insertions(+), 70 deletions(-) diff --git a/setup.py b/setup.py index 1105aef4..3ed3e252 100755 --- a/setup.py +++ b/setup.py @@ -22,11 +22,7 @@ else: long_description = '' version = sys.version_info[:2] -if version < (2, 7): - print('thefuck requires Python version 2.7 or later' + - ' ({}.{} detected).'.format(*version)) - sys.exit(-1) -elif (3, 0) < version < (3, 5): +if version < (3, 5): print('thefuck requires Python version 3.5 or later' + ' ({}.{} detected).'.format(*version)) sys.exit(-1) @@ -34,10 +30,7 @@ elif (3, 0) < version < (3, 5): VERSION = '3.32' install_requires = ['psutil', 'colorama', 'six'] -extras_require = {':python_version<"3.4"': ['pathlib2'], - ':python_version<"3.3"': ['backports.shutil_get_terminal_size'], - ':python_version<="2.7"': ['decorator<5', 'pyte<0.8.1'], - ':python_version>"2.7"': ['decorator', 'pyte'], +extras_require = {':python_version>"2.7"': ['decorator', 'pyte'], ":sys_platform=='win32'": ['win_unicode_console']} if sys.platform == "win32": @@ -63,7 +56,7 @@ setup(name='thefuck', 'tests', 'tests.*', 'release']), include_package_data=True, zip_safe=False, - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', + python_requires='>=3.5', install_requires=install_requires, extras_require=extras_require, scripts=scripts, diff --git a/tests/entrypoints/test_not_configured.py b/tests/entrypoints/test_not_configured.py index 79ed29f5..d8ca5afe 100644 --- a/tests/entrypoints/test_not_configured.py +++ b/tests/entrypoints/test_not_configured.py @@ -1,6 +1,6 @@ import pytest import json -from six import StringIO +from io import StringIO from mock import MagicMock from thefuck.shells.generic import ShellConfiguration from thefuck.entrypoints.not_configured import main diff --git a/tests/rules/test_gem_unknown_command.py b/tests/rules/test_gem_unknown_command.py index 3da0fa71..79e47270 100644 --- a/tests/rules/test_gem_unknown_command.py +++ b/tests/rules/test_gem_unknown_command.py @@ -1,5 +1,7 @@ +from io import BytesIO + import pytest -from six import BytesIO + from thefuck.rules.gem_unknown_command import match, get_new_command from thefuck.types import Command diff --git a/tests/rules/test_ifconfig_device_not_found.py b/tests/rules/test_ifconfig_device_not_found.py index 09d20b13..b9799be9 100644 --- a/tests/rules/test_ifconfig_device_not_found.py +++ b/tests/rules/test_ifconfig_device_not_found.py @@ -1,5 +1,7 @@ +from io import BytesIO + import pytest -from six import BytesIO + from thefuck.rules.ifconfig_device_not_found import match, get_new_command from thefuck.types import Command diff --git a/tests/test_conf.py b/tests/test_conf.py index e03473ab..d451d318 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -1,5 +1,5 @@ +import io import pytest -import six import os from mock import Mock from thefuck import const @@ -90,7 +90,7 @@ class TestInitializeSettingsFile(object): assert not settings_path_mock.open.called def test_create_if_doesnt_exists(self, settings): - settings_file = six.StringIO() + settings_file = io.StringIO() settings_path_mock = Mock( is_file=Mock(return_value=False), open=Mock(return_value=Mock( diff --git a/thefuck/conf.py b/thefuck/conf.py index 611ec84b..03c5bca9 100644 --- a/thefuck/conf.py +++ b/thefuck/conf.py @@ -1,7 +1,6 @@ import os import sys from warnings import warn -from six import text_type from . import const from .system import Path @@ -77,7 +76,7 @@ class Settings(dict): def _settings_from_file(self): """Loads settings from file.""" settings = load_source( - 'settings', text_type(self.user_dir.joinpath('settings.py'))) + 'settings', str(self.user_dir.joinpath('settings.py'))) return {key: getattr(settings, key) for key in const.DEFAULT_SETTINGS.keys() if hasattr(settings, key)} diff --git a/thefuck/entrypoints/alias.py b/thefuck/entrypoints/alias.py index c7094d4e..3fe86509 100644 --- a/thefuck/entrypoints/alias.py +++ b/thefuck/entrypoints/alias.py @@ -1,4 +1,3 @@ -import six from ..conf import settings from ..logs import warn from ..shells import shell @@ -6,16 +5,11 @@ from ..utils import which def _get_alias(known_args): - if six.PY2: - warn("The Fuck will drop Python 2 support soon, more details " - "https://github.com/nvbn/thefuck/issues/685") alias = shell.app_alias(known_args.alias) if known_args.enable_experimental_instant_mode: - if six.PY2: - warn("Instant mode requires Python 3") - elif not which('script'): + if not which('script'): warn("Instant mode requires `script` app") else: return shell.instant_mode_alias(known_args.alias) diff --git a/thefuck/entrypoints/not_configured.py b/thefuck/entrypoints/not_configured.py index f5d7e852..e28cef94 100644 --- a/thefuck/entrypoints/not_configured.py +++ b/thefuck/entrypoints/not_configured.py @@ -8,7 +8,6 @@ import os # noqa: E402 import json # noqa: E402 from tempfile import gettempdir # noqa: E402 import time # noqa: E402 -import six # noqa: E402 from psutil import Process # noqa: E402 from .. import logs, const # noqa: E402 from ..shells import shell # noqa: E402 @@ -38,8 +37,7 @@ def _record_first_run(): info = {'pid': _get_shell_pid(), 'time': time.time()} - mode = 'wb' if six.PY2 else 'w' - with _get_not_configured_usage_tracker_path().open(mode) as tracker: + with _get_not_configured_usage_tracker_path().open('w') as tracker: json.dump(info, tracker) diff --git a/thefuck/output_readers/read_log.py b/thefuck/output_readers/read_log.py index 0224a0dd..4c21787c 100644 --- a/thefuck/output_readers/read_log.py +++ b/thefuck/output_readers/read_log.py @@ -6,7 +6,6 @@ try: from shutil import get_terminal_size except ImportError: from backports.shutil_get_terminal_size import get_terminal_size -import six import pyte from ..exceptions import ScriptNotInLog from .. import const, logs @@ -40,8 +39,6 @@ def _group_by_calls(log): def _get_script_group_lines(grouped, script): - if six.PY2: - script = script.encode('utf-8') parts = shlex.split(script) @@ -77,9 +74,6 @@ def get_output(script): :rtype: str | None """ - if six.PY2: - logs.warn('Experimental instant mode is Python 3+ only') - return None if 'THEFUCK_OUTPUT_LOG' not in os.environ: logs.warn("Output log isn't specified") diff --git a/thefuck/output_readers/rerun.py b/thefuck/output_readers/rerun.py index b7ffe249..b50c0d3c 100644 --- a/thefuck/output_readers/rerun.py +++ b/thefuck/output_readers/rerun.py @@ -1,6 +1,5 @@ import os import shlex -import six from subprocess import Popen, PIPE, STDOUT from psutil import AccessDenied, Process, TimeoutExpired from .. import logs @@ -54,9 +53,6 @@ def get_output(script, expanded): env = dict(os.environ) env.update(settings.env) - if six.PY2: - expanded = expanded.encode('utf-8') - split_expand = shlex.split(expanded) is_slow = split_expand[0] in settings.slow_commands if split_expand else False with logs.debug_time(u'Call: {}; with env: {}; is slow: {}'.format( diff --git a/thefuck/rules/cd_correction.py b/thefuck/rules/cd_correction.py index dc45636a..204af26c 100644 --- a/thefuck/rules/cd_correction.py +++ b/thefuck/rules/cd_correction.py @@ -1,7 +1,6 @@ """Attempts to spellcheck and correct failed cd commands""" import os -import six from thefuck.specific.sudo import sudo_support from thefuck.rules import cd_mkdir from thefuck.utils import for_app, get_close_matches @@ -43,8 +42,6 @@ def get_new_command(command): if dest[0] == '': cwd = os.sep dest = dest[1:] - elif six.PY2: - cwd = os.getcwdu() else: cwd = os.getcwd() for directory in dest: diff --git a/thefuck/shells/fish.py b/thefuck/shells/fish.py index eb7e9153..28012149 100644 --- a/thefuck/shells/fish.py +++ b/thefuck/shells/fish.py @@ -2,7 +2,6 @@ from subprocess import Popen, PIPE from time import time import os import sys -import six from .. import logs from ..conf import settings from ..const import ARGUMENT_PLACEHOLDER @@ -123,7 +122,4 @@ class Fish(Generic): if os.path.isfile(history_file_name): with open(history_file_name, 'a') as history: entry = self._get_history_line(command_script) - if six.PY2: - history.write(entry.encode('utf-8')) - else: - history.write(entry) + history.write(entry) diff --git a/thefuck/shells/generic.py b/thefuck/shells/generic.py index aa81e2ac..59ff6b0f 100644 --- a/thefuck/shells/generic.py +++ b/thefuck/shells/generic.py @@ -1,7 +1,6 @@ import io import os import shlex -import six from collections import namedtuple from ..logs import warn from ..utils import memoize @@ -91,22 +90,14 @@ class Generic(object): return self.decode_utf8(splitted) def encode_utf8(self, command): - if six.PY2: - return command.encode('utf8') return command def decode_utf8(self, command_parts): - if six.PY2: - return [s.decode('utf8') for s in command_parts] return command_parts def quote(self, s): """Return a shell-escaped version of the string s.""" - - if six.PY2: - from pipes import quote - else: - from shlex import quote + from shlex import quote return quote(s) diff --git a/thefuck/specific/sudo.py b/thefuck/specific/sudo.py index ddc6d409..c00a35b7 100644 --- a/thefuck/specific/sudo.py +++ b/thefuck/specific/sudo.py @@ -1,4 +1,3 @@ -import six from decorator import decorator @@ -10,7 +9,7 @@ def sudo_support(fn, command): result = fn(command.update(script=command.script[5:])) - if result and isinstance(result, six.string_types): + if result and isinstance(result, str): return u'sudo {}'.format(result) elif isinstance(result, list): return [u'sudo {}'.format(x) for x in result] diff --git a/thefuck/utils.py b/thefuck/utils.py index 466e4ba5..05d145c5 100644 --- a/thefuck/utils.py +++ b/thefuck/utils.py @@ -4,7 +4,6 @@ import pickle import re import shelve import sys -import six from decorator import decorator from difflib import get_close_matches as difflib_get_close_matches from functools import wraps @@ -14,12 +13,8 @@ from .system import Path DEVNULL = open(os.devnull, 'w') -if six.PY2: - import anydbm - shelve_open_error = anydbm.error -else: - import dbm - shelve_open_error = dbm.error +import dbm +shelve_open_error = dbm.error def memoize(fn): @@ -121,13 +116,13 @@ def get_all_executables(): tf_alias = get_alias() tf_entry_points = ['thefuck', 'fuck'] - bins = [exe.name.decode('utf8') if six.PY2 else exe.name + bins = [exe.name for path in os.environ.get('PATH', '').split(os.pathsep) if include_path_in_search(path) for exe in _safe(lambda: list(Path(path).iterdir()), []) if not _safe(exe.is_dir, True) and exe.name not in tf_entry_points] - aliases = [alias.decode('utf8') if six.PY2 else alias + aliases = [alias for alias in shell.get_aliases() if alias != tf_alias] return bins + aliases @@ -339,9 +334,6 @@ def format_raw_script(raw_script): :rtype: basestring """ - if six.PY2: - script = ' '.join(arg.decode('utf-8') for arg in raw_script) - else: - script = ' '.join(raw_script) + script = ' '.join(raw_script) return script.lstrip()