From f9a4b693620696fd3ac65905b635c4639c703b25 Mon Sep 17 00:00:00 2001 From: Vladimir Iakovlev Date: Sat, 2 Sep 2017 09:30:03 +0200 Subject: [PATCH] #N/A: Reorganize entrypoints --- setup.py | 4 +- tests/entrypoints/__init__.py | 0 tests/entrypoints/test_fix_command.py | 26 ++++++ .../{ => entrypoints}/test_not_configured.py | 12 +-- thefuck/entrypoints/__init__.py | 0 thefuck/entrypoints/alias.py | 20 +++++ thefuck/entrypoints/fix_command.py | 47 ++++++++++ thefuck/entrypoints/main.py | 29 +++++++ thefuck/{ => entrypoints}/not_configured.py | 12 +-- thefuck/main.py | 87 ------------------- thefuck/utils.py | 2 +- 11 files changed, 137 insertions(+), 102 deletions(-) create mode 100644 tests/entrypoints/__init__.py create mode 100644 tests/entrypoints/test_fix_command.py rename tests/{ => entrypoints}/test_not_configured.py (90%) create mode 100644 thefuck/entrypoints/__init__.py create mode 100644 thefuck/entrypoints/alias.py create mode 100644 thefuck/entrypoints/fix_command.py create mode 100644 thefuck/entrypoints/main.py rename thefuck/{ => entrypoints}/not_configured.py (92%) delete mode 100644 thefuck/main.py diff --git a/setup.py b/setup.py index afaeca7f..93c9fcfc 100755 --- a/setup.py +++ b/setup.py @@ -53,5 +53,5 @@ setup(name='thefuck', install_requires=install_requires, extras_require=extras_require, entry_points={'console_scripts': [ - 'thefuck = thefuck.main:main', - 'fuck = thefuck.not_configured:main']}) + 'thefuck = thefuck.entrypoints.main:main', + 'fuck = thefuck.entrypoints.not_configured:main']}) diff --git a/tests/entrypoints/__init__.py b/tests/entrypoints/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/entrypoints/test_fix_command.py b/tests/entrypoints/test_fix_command.py new file mode 100644 index 00000000..18431c46 --- /dev/null +++ b/tests/entrypoints/test_fix_command.py @@ -0,0 +1,26 @@ +import pytest +from mock import Mock +from thefuck.entrypoints.fix_command import _get_raw_command + + +class TestGetRawCommand(object): + def test_from_force_command_argument(self): + known_args = Mock(force_command=['git', 'brunch']) + assert _get_raw_command(known_args) == ['git', 'brunch'] + + def test_from_command_argument(self, os_environ): + os_environ['TF_HISTORY'] = None + known_args = Mock(force_command=None, + command=['sl']) + assert _get_raw_command(known_args) == ['sl'] + + @pytest.mark.parametrize('history, result', [ + ('git br', 'git br'), + ('git br\nfcuk', 'git br'), + ('git br\nfcuk\nls', 'ls'), + ('git br\nfcuk\nls\nfuk', 'ls')]) + def test_from_history(self, os_environ, history, result): + os_environ['TF_HISTORY'] = history + known_args = Mock(force_command=None, + command=None) + assert _get_raw_command(known_args) == [result] diff --git a/tests/test_not_configured.py b/tests/entrypoints/test_not_configured.py similarity index 90% rename from tests/test_not_configured.py rename to tests/entrypoints/test_not_configured.py index 9ae13ba5..79ed29f5 100644 --- a/tests/test_not_configured.py +++ b/tests/entrypoints/test_not_configured.py @@ -3,13 +3,13 @@ import json from six import StringIO from mock import MagicMock from thefuck.shells.generic import ShellConfiguration -from thefuck.not_configured import main +from thefuck.entrypoints.not_configured import main @pytest.fixture(autouse=True) def usage_tracker(mocker): return mocker.patch( - 'thefuck.not_configured._get_not_configured_usage_tracker_path', + 'thefuck.entrypoints.not_configured._get_not_configured_usage_tracker_path', new_callable=MagicMock) @@ -44,13 +44,13 @@ def _change_tracker(usage_tracker_io, pid): @pytest.fixture(autouse=True) def shell_pid(mocker): - return mocker.patch('thefuck.not_configured._get_shell_pid', + return mocker.patch('thefuck.entrypoints.not_configured._get_shell_pid', new_callable=MagicMock) @pytest.fixture(autouse=True) def shell(mocker): - shell = mocker.patch('thefuck.not_configured.shell', + shell = mocker.patch('thefuck.entrypoints.not_configured.shell', new_callable=MagicMock) shell.get_history.return_value = [] shell.how_to_configure.return_value = ShellConfiguration( @@ -63,7 +63,7 @@ def shell(mocker): @pytest.fixture(autouse=True) def shell_config(mocker): - path_mock = mocker.patch('thefuck.not_configured.Path', + path_mock = mocker.patch('thefuck.entrypoints.not_configured.Path', new_callable=MagicMock) return path_mock.return_value \ .expanduser.return_value \ @@ -73,7 +73,7 @@ def shell_config(mocker): @pytest.fixture(autouse=True) def logs(mocker): - return mocker.patch('thefuck.not_configured.logs', + return mocker.patch('thefuck.entrypoints.not_configured.logs', new_callable=MagicMock) diff --git a/thefuck/entrypoints/__init__.py b/thefuck/entrypoints/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/thefuck/entrypoints/alias.py b/thefuck/entrypoints/alias.py new file mode 100644 index 00000000..a21e1fef --- /dev/null +++ b/thefuck/entrypoints/alias.py @@ -0,0 +1,20 @@ +import six +from ..logs import warn +from ..shells import shell + + +def print_alias(known_args): + if six.PY2: + warn("The Fuck will drop Python 2 support soon, more details " + "https://github.com/nvbn/thefuck/issues/685") + + if known_args.enable_experimental_instant_mode: + if six.PY2: + warn("Instant mode not supported with Python 2") + alias = shell.app_alias(known_args.alias) + else: + alias = shell.instant_mode_alias(known_args.alias) + else: + alias = shell.app_alias(known_args.alias) + + print(alias) diff --git a/thefuck/entrypoints/fix_command.py b/thefuck/entrypoints/fix_command.py new file mode 100644 index 00000000..e3e3b01f --- /dev/null +++ b/thefuck/entrypoints/fix_command.py @@ -0,0 +1,47 @@ +from pprint import pformat +import os +import sys +from difflib import SequenceMatcher +from .. import logs, types, const +from ..conf import settings +from ..corrector import get_corrected_commands +from ..exceptions import EmptyCommand +from ..ui import select_command +from ..utils import get_alias, get_all_executables + + +def _get_raw_command(known_args): + if known_args.force_command: + return known_args.force_command + elif not os.environ.get('TF_HISTORY'): + return known_args.command + else: + history = os.environ['TF_HISTORY'].split('\n')[::-1] + alias = get_alias() + executables = get_all_executables() + for command in history: + diff = SequenceMatcher(a=alias, b=command).ratio() + if diff < const.DIFF_WITH_ALIAS or command in executables: + return [command] + + +def fix_command(known_args): + """Fixes previous command. Used when `thefuck` called without arguments.""" + settings.init(known_args) + with logs.debug_time('Total'): + logs.debug(u'Run with settings: {}'.format(pformat(settings))) + raw_command = _get_raw_command(known_args) + + try: + command = types.Command.from_raw_script(raw_command) + except EmptyCommand: + logs.debug('Empty command, nothing to do') + return + + corrected_commands = get_corrected_commands(command) + selected_command = select_command(corrected_commands) + + if selected_command: + selected_command.run(command) + else: + sys.exit(1) diff --git a/thefuck/entrypoints/main.py b/thefuck/entrypoints/main.py new file mode 100644 index 00000000..587c7716 --- /dev/null +++ b/thefuck/entrypoints/main.py @@ -0,0 +1,29 @@ +# Initialize output before importing any module, that can use colorama. +from ..system import init_output + +init_output() + +import os # noqa: E402 +import sys # noqa: E402 +from .. import logs # noqa: E402 +from ..argument_parser import Parser # noqa: E402 +from ..utils import get_installation_info # noqa: E402 +from .alias import print_alias # noqa: E402 +from .fix_command import fix_command # noqa: E402 + + +def main(): + parser = Parser() + known_args = parser.parse(sys.argv) + + if known_args.help: + parser.print_help() + elif known_args.version: + logs.version(get_installation_info().version, + sys.version.split()[0]) + elif known_args.command or 'TF_HISTORY' in os.environ: + fix_command(known_args) + elif known_args.alias: + print_alias(known_args) + else: + parser.print_usage() diff --git a/thefuck/not_configured.py b/thefuck/entrypoints/not_configured.py similarity index 92% rename from thefuck/not_configured.py rename to thefuck/entrypoints/not_configured.py index cbd6f6a6..3e01009b 100644 --- a/thefuck/not_configured.py +++ b/thefuck/entrypoints/not_configured.py @@ -1,5 +1,5 @@ # Initialize output before importing any module, that can use colorama. -from .system import init_output +from ..system import init_output init_output() @@ -8,11 +8,11 @@ import json # 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 -from .conf import settings # noqa: E402 -from .system import Path # noqa: E402 -from .utils import get_cache_dir # noqa: E402 +from .. import logs, const # noqa: E402 +from ..shells import shell # noqa: E402 +from ..conf import settings # noqa: E402 +from ..system import Path # noqa: E402 +from ..utils import get_cache_dir # noqa: E402 def _get_shell_pid(): diff --git a/thefuck/main.py b/thefuck/main.py deleted file mode 100644 index bdacad72..00000000 --- a/thefuck/main.py +++ /dev/null @@ -1,87 +0,0 @@ -# Initialize output before importing any module, that can use colorama. -from .system import init_output - -init_output() - -from pprint import pformat # noqa: E402 -import os # noqa: E402 -import sys # noqa: E402 -from difflib import SequenceMatcher # noqa: E402 -import six # noqa: E402 -from . import logs, types, const # noqa: E402 -from .shells import shell # noqa: E402 -from .conf import settings # noqa: E402 -from .corrector import get_corrected_commands # noqa: E402 -from .exceptions import EmptyCommand # noqa: E402 -from .ui import select_command # noqa: E402 -from .argument_parser import Parser # noqa: E402 -from .utils import (get_installation_info, get_alias, - get_all_executables) # noqa: E402 -from .logs import warn # noqa: E402 - - -def _get_raw_command(known_args): - if known_args.force_command: - return known_args.force_command - elif 'TF_HISTORY' not in os.environ: - return known_args.command - else: - history = os.environ['TF_HISTORY'].split('\n')[::-1] - alias = get_alias() - executables = get_all_executables() - for command in history: - diff = SequenceMatcher(a=alias, b=command).ratio() - if diff < const.DIFF_WITH_ALIAS or command in executables: - return [command] - - -def fix_command(known_args): - """Fixes previous command. Used when `thefuck` called without arguments.""" - settings.init(known_args) - with logs.debug_time('Total'): - logs.debug(u'Run with settings: {}'.format(pformat(settings))) - raw_command = _get_raw_command(known_args) - - try: - command = types.Command.from_raw_script(raw_command) - except EmptyCommand: - logs.debug('Empty command, nothing to do') - return - - corrected_commands = get_corrected_commands(command) - selected_command = select_command(corrected_commands) - - if selected_command: - selected_command.run(command) - else: - sys.exit(1) - - -def main(): - parser = Parser() - known_args = parser.parse(sys.argv) - - if known_args.help: - parser.print_help() - elif known_args.version: - logs.version(get_installation_info().version, - sys.version.split()[0]) - elif known_args.command or 'TF_HISTORY' in os.environ: - fix_command(known_args) - elif known_args.alias: - if six.PY2: - warn("The Fuck will drop Python 2 support soon, more details " - "https://github.com/nvbn/thefuck/issues/685") - - if known_args.enable_experimental_instant_mode: - if six.PY2: - warn("Instant mode not supported with Python 2") - alias = shell.app_alias(known_args.alias) - else: - alias = shell.instant_mode_alias(known_args.alias) - else: - alias = shell.app_alias(known_args.alias) - - print(alias) - else: - parser.print_usage() diff --git a/thefuck/utils.py b/thefuck/utils.py index 60bc2f5c..36e901a0 100644 --- a/thefuck/utils.py +++ b/thefuck/utils.py @@ -75,7 +75,7 @@ def default_settings(params): Usage: @default_settings({'apt': '/usr/bin/apt'}) - def match(command, settings): + def match(command): print(settings.apt) """