mirror of
https://github.com/nvbn/thefuck.git
synced 2025-04-13 06:10:46 +01:00
Remove obscure SortedCorrectedCommandsSequence
This commit is contained in:
parent
1fb6dd925b
commit
bf80d97062
@ -3,7 +3,8 @@ from pathlib import PosixPath, Path
|
|||||||
from mock import Mock
|
from mock import Mock
|
||||||
from thefuck import corrector, conf
|
from thefuck import corrector, conf
|
||||||
from tests.utils import Rule, Command, CorrectedCommand
|
from tests.utils import Rule, Command, CorrectedCommand
|
||||||
from thefuck.corrector import make_corrected_commands, get_corrected_commands, is_rule_enabled
|
from thefuck.corrector import make_corrected_commands, get_corrected_commands,\
|
||||||
|
is_rule_enabled, organize_commands
|
||||||
|
|
||||||
|
|
||||||
def test_load_rule(mocker):
|
def test_load_rule(mocker):
|
||||||
@ -111,3 +112,13 @@ def test_get_corrected_commands(mocker):
|
|||||||
mocker.patch('thefuck.corrector.get_rules', return_value=rules)
|
mocker.patch('thefuck.corrector.get_rules', return_value=rules)
|
||||||
assert [cmd.script for cmd in get_corrected_commands(command)] \
|
assert [cmd.script for cmd in get_corrected_commands(command)] \
|
||||||
== ['test!', 'test@', 'test;']
|
== ['test!', 'test@', 'test;']
|
||||||
|
|
||||||
|
|
||||||
|
def test_organize_commands():
|
||||||
|
"""Ensures that the function removes duplicates and sorts commands."""
|
||||||
|
commands = [CorrectedCommand('ls'), CorrectedCommand('ls -la', priority=9000),
|
||||||
|
CorrectedCommand('ls -lh', priority=100),
|
||||||
|
CorrectedCommand('ls -lh', priority=9999)]
|
||||||
|
assert list(organize_commands(iter(commands))) \
|
||||||
|
== [CorrectedCommand('ls'), CorrectedCommand('ls -lh', priority=100),
|
||||||
|
CorrectedCommand('ls -la', priority=9000)]
|
||||||
|
@ -1,37 +1,6 @@
|
|||||||
from thefuck.types import SortedCorrectedCommandsSequence
|
|
||||||
from tests.utils import CorrectedCommand
|
from tests.utils import CorrectedCommand
|
||||||
|
|
||||||
|
|
||||||
class TestSortedCorrectedCommandsSequence(object):
|
|
||||||
def test_realises_generator_only_on_demand(self, settings):
|
|
||||||
should_realise = False
|
|
||||||
|
|
||||||
def gen():
|
|
||||||
yield CorrectedCommand('git commit')
|
|
||||||
yield CorrectedCommand('git branch', priority=200)
|
|
||||||
assert should_realise
|
|
||||||
yield CorrectedCommand('git checkout', priority=100)
|
|
||||||
|
|
||||||
commands = SortedCorrectedCommandsSequence(gen())
|
|
||||||
assert commands[0] == CorrectedCommand('git commit')
|
|
||||||
should_realise = True
|
|
||||||
assert commands[1] == CorrectedCommand('git checkout', priority=100)
|
|
||||||
assert commands[2] == CorrectedCommand('git branch', priority=200)
|
|
||||||
|
|
||||||
def test_remove_duplicates(self):
|
|
||||||
side_effect = lambda *_: None
|
|
||||||
seq = SortedCorrectedCommandsSequence(
|
|
||||||
iter([CorrectedCommand('ls', priority=100),
|
|
||||||
CorrectedCommand('ls', priority=200),
|
|
||||||
CorrectedCommand('ls', side_effect, 300)]))
|
|
||||||
assert set(seq) == {CorrectedCommand('ls', priority=100),
|
|
||||||
CorrectedCommand('ls', side_effect, 300)}
|
|
||||||
|
|
||||||
def test_with_blank(self):
|
|
||||||
seq = SortedCorrectedCommandsSequence(iter([]))
|
|
||||||
assert list(seq) == []
|
|
||||||
|
|
||||||
|
|
||||||
class TestCorrectedCommand(object):
|
class TestCorrectedCommand(object):
|
||||||
|
|
||||||
def test_equality(self):
|
def test_equality(self):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
from mock import Mock
|
|
||||||
import pytest
|
import pytest
|
||||||
from itertools import islice
|
from itertools import islice
|
||||||
from thefuck import ui
|
from thefuck import ui
|
||||||
from thefuck.types import CorrectedCommand, SortedCorrectedCommandsSequence
|
from thefuck.types import CorrectedCommand
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -41,7 +40,7 @@ def test_read_actions(patch_getch):
|
|||||||
|
|
||||||
|
|
||||||
def test_command_selector():
|
def test_command_selector():
|
||||||
selector = ui.CommandSelector([1, 2, 3])
|
selector = ui.CommandSelector(iter([1, 2, 3]))
|
||||||
assert selector.value == 1
|
assert selector.value == 1
|
||||||
selector.next()
|
selector.next()
|
||||||
assert selector.value == 2
|
assert selector.value == 2
|
||||||
@ -57,51 +56,49 @@ def test_command_selector():
|
|||||||
class TestSelectCommand(object):
|
class TestSelectCommand(object):
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def commands_with_side_effect(self):
|
def commands_with_side_effect(self):
|
||||||
return SortedCorrectedCommandsSequence(
|
return [CorrectedCommand('ls', lambda *_: None, 100),
|
||||||
iter([CorrectedCommand('ls', lambda *_: None, 100),
|
CorrectedCommand('cd', lambda *_: None, 100)]
|
||||||
CorrectedCommand('cd', lambda *_: None, 100)]))
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def commands(self):
|
def commands(self):
|
||||||
return SortedCorrectedCommandsSequence(
|
return [CorrectedCommand('ls', None, 100),
|
||||||
iter([CorrectedCommand('ls', None, 100),
|
CorrectedCommand('cd', None, 100)]
|
||||||
CorrectedCommand('cd', None, 100)]))
|
|
||||||
|
|
||||||
def test_without_commands(self, capsys):
|
def test_without_commands(self, capsys):
|
||||||
assert ui.select_command([]) is None
|
assert ui.select_command(iter([])) is None
|
||||||
assert capsys.readouterr() == ('', 'No fucks given\n')
|
assert capsys.readouterr() == ('', 'No fucks given\n')
|
||||||
|
|
||||||
def test_without_confirmation(self, capsys, commands, settings):
|
def test_without_confirmation(self, capsys, commands, settings):
|
||||||
settings.require_confirmation = False
|
settings.require_confirmation = False
|
||||||
assert ui.select_command(commands) == commands[0]
|
assert ui.select_command(iter(commands)) == commands[0]
|
||||||
assert capsys.readouterr() == ('', 'ls\n')
|
assert capsys.readouterr() == ('', 'ls\n')
|
||||||
|
|
||||||
def test_without_confirmation_with_side_effects(
|
def test_without_confirmation_with_side_effects(
|
||||||
self, capsys, commands_with_side_effect, settings):
|
self, capsys, commands_with_side_effect, settings):
|
||||||
settings.require_confirmation = False
|
settings.require_confirmation = False
|
||||||
assert ui.select_command(commands_with_side_effect) \
|
assert ui.select_command(iter(commands_with_side_effect)) \
|
||||||
== commands_with_side_effect[0]
|
== commands_with_side_effect[0]
|
||||||
assert capsys.readouterr() == ('', 'ls (+side effect)\n')
|
assert capsys.readouterr() == ('', 'ls (+side effect)\n')
|
||||||
|
|
||||||
def test_with_confirmation(self, capsys, patch_getch, commands):
|
def test_with_confirmation(self, capsys, patch_getch, commands):
|
||||||
patch_getch(['\n'])
|
patch_getch(['\n'])
|
||||||
assert ui.select_command(commands) == commands[0]
|
assert ui.select_command(iter(commands)) == commands[0]
|
||||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\n')
|
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\n')
|
||||||
|
|
||||||
def test_with_confirmation_abort(self, capsys, patch_getch, commands):
|
def test_with_confirmation_abort(self, capsys, patch_getch, commands):
|
||||||
patch_getch([KeyboardInterrupt])
|
patch_getch([KeyboardInterrupt])
|
||||||
assert ui.select_command(commands) is None
|
assert ui.select_command(iter(commands)) is None
|
||||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\nAborted\n')
|
assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\nAborted\n')
|
||||||
|
|
||||||
def test_with_confirmation_with_side_effct(self, capsys, patch_getch,
|
def test_with_confirmation_with_side_effct(self, capsys, patch_getch,
|
||||||
commands_with_side_effect):
|
commands_with_side_effect):
|
||||||
patch_getch(['\n'])
|
patch_getch(['\n'])
|
||||||
assert ui.select_command(commands_with_side_effect)\
|
assert ui.select_command(iter(commands_with_side_effect))\
|
||||||
== commands_with_side_effect[0]
|
== commands_with_side_effect[0]
|
||||||
assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
|
assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
|
||||||
|
|
||||||
def test_with_confirmation_select_second(self, capsys, patch_getch, commands):
|
def test_with_confirmation_select_second(self, capsys, patch_getch, commands):
|
||||||
patch_getch(['\x1b', '[', 'B', '\n'])
|
patch_getch(['\x1b', '[', 'B', '\n'])
|
||||||
assert ui.select_command(commands) == commands[1]
|
assert ui.select_command(iter(commands)) == commands[1]
|
||||||
assert capsys.readouterr() == (
|
assert capsys.readouterr() == (
|
||||||
'', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\x1b[1K\rcd [enter/↑/↓/ctrl+c]\n')
|
'', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\x1b[1K\rcd [enter/↑/↓/ctrl+c]\n')
|
||||||
|
@ -2,7 +2,7 @@ import sys
|
|||||||
from imp import load_source
|
from imp import load_source
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from .conf import settings, DEFAULT_PRIORITY, ALL_ENABLED
|
from .conf import settings, DEFAULT_PRIORITY, ALL_ENABLED
|
||||||
from .types import Rule, CorrectedCommand, SortedCorrectedCommandsSequence
|
from .types import Rule, CorrectedCommand
|
||||||
from .utils import compatibility_call
|
from .utils import compatibility_call
|
||||||
from . import logs
|
from . import logs
|
||||||
|
|
||||||
@ -76,10 +76,33 @@ def make_corrected_commands(command, rule):
|
|||||||
side_effect=rule.side_effect,
|
side_effect=rule.side_effect,
|
||||||
priority=(n + 1) * rule.priority)
|
priority=(n + 1) * rule.priority)
|
||||||
|
|
||||||
|
def organize_commands(corrected_commands):
|
||||||
|
"""Yields sorted commands without duplicates."""
|
||||||
|
try:
|
||||||
|
first_command = next(corrected_commands)
|
||||||
|
yield first_command
|
||||||
|
except StopIteration:
|
||||||
|
return
|
||||||
|
|
||||||
|
without_duplicates = {
|
||||||
|
command for command in sorted(
|
||||||
|
corrected_commands, key=lambda command: command.priority)
|
||||||
|
if command != first_command}
|
||||||
|
|
||||||
|
sorted_commands = sorted(
|
||||||
|
without_duplicates,
|
||||||
|
key=lambda corrected_command: corrected_command.priority)
|
||||||
|
|
||||||
|
logs.debug('Corrected commands: '.format(
|
||||||
|
', '.join(str(cmd) for cmd in [first_command] + sorted_commands)))
|
||||||
|
|
||||||
|
for command in sorted_commands:
|
||||||
|
yield command
|
||||||
|
|
||||||
|
|
||||||
def get_corrected_commands(command):
|
def get_corrected_commands(command):
|
||||||
corrected_commands = (
|
corrected_commands = (
|
||||||
corrected for rule in get_rules()
|
corrected for rule in get_rules()
|
||||||
if is_rule_match(command, rule)
|
if is_rule_match(command, rule)
|
||||||
for corrected in make_corrected_commands(command, rule))
|
for corrected in make_corrected_commands(command, rule))
|
||||||
return SortedCorrectedCommandsSequence(corrected_commands)
|
return organize_commands(corrected_commands)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from traceback import format_stack
|
|
||||||
|
|
||||||
Command = namedtuple('Command', ('script', 'stdout', 'stderr'))
|
Command = namedtuple('Command', ('script', 'stdout', 'stderr'))
|
||||||
|
|
||||||
@ -36,62 +35,3 @@ class Settings(dict):
|
|||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
self[key] = value
|
self[key] = value
|
||||||
|
|
||||||
|
|
||||||
class SortedCorrectedCommandsSequence(object):
|
|
||||||
"""List-like collection/wrapper around generator, that:
|
|
||||||
|
|
||||||
- immediately gives access to the first commands through [];
|
|
||||||
- realises generator and sorts commands on first access to other
|
|
||||||
commands through [], or when len called.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, commands):
|
|
||||||
self._commands = commands
|
|
||||||
self._cached = self._realise_first()
|
|
||||||
self._realised = False
|
|
||||||
|
|
||||||
def _realise_first(self):
|
|
||||||
try:
|
|
||||||
return [next(self._commands)]
|
|
||||||
except StopIteration:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def _remove_duplicates(self, corrected_commands):
|
|
||||||
"""Removes low-priority duplicates."""
|
|
||||||
commands = {command
|
|
||||||
for command in sorted(corrected_commands,
|
|
||||||
key=lambda command: -command.priority)
|
|
||||||
if command.script != self._cached[0]}
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def _realise(self):
|
|
||||||
"""Realises generator, removes duplicates and sorts commands."""
|
|
||||||
from .logs import debug
|
|
||||||
|
|
||||||
if self._cached:
|
|
||||||
commands = self._remove_duplicates(self._commands)
|
|
||||||
self._cached = [self._cached[0]] + sorted(
|
|
||||||
commands, key=lambda corrected_command: corrected_command.priority)
|
|
||||||
self._realised = True
|
|
||||||
debug('SortedCommandsSequence was realised with: {}, after: {}'.format(
|
|
||||||
self._cached, '\n'.join(format_stack())))
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
if item != 0 and not self._realised:
|
|
||||||
self._realise()
|
|
||||||
return self._cached[item]
|
|
||||||
|
|
||||||
def __bool__(self):
|
|
||||||
return bool(self._cached)
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
if not self._realised:
|
|
||||||
self._realise()
|
|
||||||
return len(self._cached)
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
if not self._realised:
|
|
||||||
self._realise()
|
|
||||||
return iter(self._cached)
|
|
||||||
|
@ -50,14 +50,25 @@ def read_actions():
|
|||||||
|
|
||||||
|
|
||||||
class CommandSelector(object):
|
class CommandSelector(object):
|
||||||
|
"""Helper for selecting rule from rules list."""
|
||||||
|
|
||||||
def __init__(self, commands):
|
def __init__(self, commands):
|
||||||
self._commands = commands
|
self._commands_gen = commands
|
||||||
|
self._commands = [next(self._commands_gen)]
|
||||||
|
self._realised = False
|
||||||
self._index = 0
|
self._index = 0
|
||||||
|
|
||||||
|
def _realise(self):
|
||||||
|
if not self._realised:
|
||||||
|
self._commands += list(self._commands_gen)
|
||||||
|
self._realised = True
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
|
self._realise()
|
||||||
self._index = (self._index + 1) % len(self._commands)
|
self._index = (self._index + 1) % len(self._commands)
|
||||||
|
|
||||||
def previous(self):
|
def previous(self):
|
||||||
|
self._realise()
|
||||||
self._index = (self._index - 1) % len(self._commands)
|
self._index = (self._index - 1) % len(self._commands)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -73,11 +84,12 @@ def select_command(corrected_commands):
|
|||||||
- selected command.
|
- selected command.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not corrected_commands:
|
try:
|
||||||
|
selector = CommandSelector(corrected_commands)
|
||||||
|
except StopIteration:
|
||||||
logs.failed('No fucks given')
|
logs.failed('No fucks given')
|
||||||
return
|
return
|
||||||
|
|
||||||
selector = CommandSelector(corrected_commands)
|
|
||||||
if not settings.require_confirmation:
|
if not settings.require_confirmation:
|
||||||
logs.show_corrected_command(selector.value)
|
logs.show_corrected_command(selector.value)
|
||||||
return selector.value
|
return selector.value
|
||||||
|
Loading…
x
Reference in New Issue
Block a user