Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ var/
*.egg-info/
.installed.cfg
*.egg
.venv/
.pytest_cache/

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
36 changes: 11 additions & 25 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,30 @@
#!/usr/bin/env python
from setuptools import setup, find_packages
import pkg_resources
import sys
import os
import fastentrypoints


try:
if int(pkg_resources.get_distribution("pip").version.split('.')[0]) < 6:
print('pip older than 6.0 not supported, please upgrade pip with:\n\n'
' pip install -U pip')
sys.exit(-1)
except pkg_resources.DistributionNotFound:
pass

if os.environ.get('CONVERT_README'):
import pypandoc

long_description = pypandoc.convert('README.md', 'rst')
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):
print('thefuck requires Python version 3.5 or later' +
' ({}.{} detected).'.format(*version))
sys.exit(-1)

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'],
":sys_platform=='win32'": ['win_unicode_console']}
extras_require = {
":sys_platform=='win32'": ["win_unicode_console"],
}
install_requires = [
"psutil",
"colorama",
"six",
"decorator",
"pyte",
]

if sys.platform == "win32":
scripts = ['scripts\\fuck.bat', 'scripts\\fuck.ps1']
Expand All @@ -63,7 +49,7 @@
'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.12',
install_requires=install_requires,
extras_require=extras_require,
scripts=scripts,
Expand Down
2 changes: 1 addition & 1 deletion tests/entrypoints/test_alias.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from mock import Mock
from unittest.mock import Mock
import pytest
from thefuck.entrypoints.alias import _get_alias, print_alias

Expand Down
2 changes: 1 addition & 1 deletion tests/entrypoints/test_fix_command.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from mock import Mock
from unittest.mock import Mock
from thefuck.entrypoints.fix_command import _get_raw_command


Expand Down
2 changes: 1 addition & 1 deletion tests/entrypoints/test_not_configured.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest
import json
from six import StringIO
from mock import MagicMock
from unittest.mock import MagicMock
from thefuck.shells.generic import ShellConfiguration
from thefuck.entrypoints.not_configured import main

Expand Down
2 changes: 1 addition & 1 deletion tests/output_readers/test_rerun.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest
import sys
from mock import Mock, patch
from unittest.mock import Mock, patch
from psutil import AccessDenied, TimeoutExpired

from thefuck.output_readers import rerun
Expand Down
2 changes: 1 addition & 1 deletion tests/rules/test_has_exists_script.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from mock import patch
from unittest.mock import patch
from thefuck.rules.has_exists_script import match, get_new_command
from thefuck.types import Command

Expand Down
2 changes: 1 addition & 1 deletion tests/rules/test_pacman.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from mock import patch
from unittest.mock import patch
from thefuck.rules import pacman
from thefuck.rules.pacman import match, get_new_command
from thefuck.types import Command
Expand Down
2 changes: 1 addition & 1 deletion tests/rules/test_pacman_not_found.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from mock import patch
from unittest.mock import patch
from thefuck.rules import pacman_not_found
from thefuck.rules.pacman_not_found import match, get_new_command
from thefuck.types import Command
Expand Down
6 changes: 2 additions & 4 deletions tests/shells/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ def isfile(mocker):


@pytest.fixture
@pytest.mark.usefixtures('isfile')
def history_lines(mocker):
def history_lines(mocker, isfile):
def aux(lines):
mock = mocker.patch('io.open')
mock.return_value.__enter__ \
.return_value.readlines.return_value = lines
mock.return_value.__enter__.return_value.readlines.return_value = lines

return aux

Expand Down
2 changes: 1 addition & 1 deletion tests/test_conf.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest
import six
import os
from mock import Mock
from unittest.mock import Mock
from thefuck import const


Expand Down
2 changes: 1 addition & 1 deletion tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import os
from subprocess import PIPE, STDOUT
from mock import Mock
from unittest.mock import Mock
import pytest
from tests.utils import CorrectedCommand, Rule
from thefuck import const
Expand Down
2 changes: 1 addition & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest
import warnings
from mock import Mock, call, patch
from unittest.mock import Mock, call, patch
from thefuck.utils import default_settings, \
memoize, get_closest, get_all_executables, replace_argument, \
get_all_matched_commands, is_app, for_app, cache, \
Expand Down
19 changes: 10 additions & 9 deletions thefuck/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
from six import text_type
from . import const
from .system import Path
import importlib.util

try:
import importlib.util

def load_source(name, pathname, _file=None):
module_spec = importlib.util.spec_from_file_location(name, pathname)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
return module
except ImportError:
from imp import load_source
def load_source(name, path):
spec = importlib.util.spec_from_file_location(name, path)
if spec is None or spec.loader is None:
raise ImportError(f"Cannot load module {name!r} from {path!r}")

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


class Settings(dict):
Expand Down
3 changes: 3 additions & 0 deletions thefuck/shells/bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ def get_aliases(self):
return dict(self._parse_alias(alias)
for alias in raw_aliases if alias and '=' in alias)

def get_history(self):
return list(self._get_history_lines())

def _get_history_file_name(self):
return os.environ.get("HISTFILE",
os.path.expanduser('~/.bash_history'))
Expand Down
17 changes: 17 additions & 0 deletions thefuck/shells/fish.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ..const import ARGUMENT_PLACEHOLDER
from ..utils import DEVNULL, cache
from .generic import Generic
import io


@cache('~/.config/fish/config.fish', '~/.config/fish/functions')
Expand Down Expand Up @@ -72,6 +73,22 @@ def get_aliases(self):
functions.update(raw_aliases)
return functions

def get_history(self):
history_file_name = self._get_history_file_name()
if not os.path.isfile(history_file_name):
return

try:
with io.open(history_file_name, 'r') as history:
for line in history.readlines():
line = line.strip()
if line.startswith('- cmd:'):
cmd = line[len('- cmd:'):].strip()
if cmd:
yield cmd
except (OSError, IOError):
return

def _expand_aliases(self, command_script):
aliases = self.get_aliases()
binary = command_script.split(' ')[0]
Expand Down
15 changes: 9 additions & 6 deletions thefuck/shells/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,30 @@ def _get_history_file_name(self):
def _get_history_line(self, command_script):
return ''

@memoize
def get_history(self):
return list(self._get_history_lines())

def _get_history_lines(self):
"""Returns list of history entries."""
history_file_name = self._get_history_file_name()
if os.path.isfile(history_file_name):

if not history_file_name:
return []

if os.path.exists(history_file_name):
with io.open(history_file_name, 'r',
encoding='utf-8', errors='ignore') as history_file:
encoding='utf-8', errors='ignore') as history_file:

lines = history_file.readlines()
if settings.history_limit:
lines = lines[-settings.history_limit:]

for line in lines:
prepared = self._script_from_history(line) \
.strip()
prepared = self._script_from_history(line).strip()
if prepared:
yield prepared

return []

def and_(self, *commands):
return u' && '.join(commands)

Expand Down
15 changes: 15 additions & 0 deletions thefuck/shells/tcsh.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
from ..utils import DEVNULL, memoize
from .generic import Generic
import io


class Tcsh(Generic):
Expand All @@ -25,6 +26,20 @@ def get_aliases(self):
for alias in proc.stdout.read().decode('utf-8').split('\n')
if alias and '\t' in alias)

def get_history(self):
history_file_name = self._get_history_file_name()
if not os.path.isfile(history_file_name):
return

try:
with io.open(history_file_name, 'r') as history:
for line in history.readlines():
line = line.strip()
if line and not line.startswith('#+'):
yield line
except (OSError, IOError):
return

def _get_history_file_name(self):
return os.environ.get("HISTFILE",
os.path.expanduser('~/.history'))
Expand Down
2 changes: 1 addition & 1 deletion thefuck/system/unix.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import tty
import termios
import colorama
from distutils.spawn import find_executable
from shutil import which as find_executable
from .. import const

init_output = colorama.init
Expand Down
20 changes: 14 additions & 6 deletions thefuck/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,20 @@ def _not_corrected(history, tf_alias):
from thefuck.shells import shell
history = shell.get_history()
tf_alias = get_alias()
executables = set(get_all_executables())\
.union(shell.get_builtin_commands())

return [line for line in _not_corrected(history, tf_alias)
if not line.startswith(tf_alias) and not line == command.script
and line.split(' ')[0] in executables]
executables = set(get_all_executables()).union(shell.get_builtin_commands())

def _has_non_ascii(s):
return any(ord(ch) > 127 for ch in s)

return [
line for line in _not_corrected(history, tf_alias)
if not line.startswith(tf_alias)
and line != command.script
and (
line.split(' ')[0] in executables
or _has_non_ascii(line)
)
]


def format_raw_script(raw_script):
Expand Down