1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-09-19 03:32:31 +01:00

Organize settings initialization logic in Settings

This commit is contained in:
nvbn
2015-09-08 15:15:53 +03:00
parent a8dbc48fd4
commit 1173f9f59c
3 changed files with 88 additions and 101 deletions

View File

@@ -19,7 +19,7 @@ def environ(monkeypatch):
@pytest.mark.usefixture('environ') @pytest.mark.usefixture('environ')
def test_settings_defaults(load_source, settings): def test_settings_defaults(load_source, settings):
load_source.return_value = object() load_source.return_value = object()
conf.init_settings(Mock()) settings.init()
for key, val in conf.DEFAULT_SETTINGS.items(): for key, val in conf.DEFAULT_SETTINGS.items():
assert getattr(settings, key) == val assert getattr(settings, key) == val
@@ -33,7 +33,7 @@ class TestSettingsFromFile(object):
no_colors=True, no_colors=True,
priority={'vim': 100}, priority={'vim': 100},
exclude_rules=['git']) exclude_rules=['git'])
conf.init_settings(Mock()) settings.init()
assert settings.rules == ['test'] assert settings.rules == ['test']
assert settings.wait_command == 10 assert settings.wait_command == 10
assert settings.require_confirmation is True assert settings.require_confirmation is True
@@ -47,7 +47,7 @@ class TestSettingsFromFile(object):
exclude_rules=[], exclude_rules=[],
require_confirmation=True, require_confirmation=True,
no_colors=True) no_colors=True)
conf.init_settings(Mock()) settings.init()
assert settings.rules == conf.DEFAULT_RULES + ['test'] assert settings.rules == conf.DEFAULT_RULES + ['test']
@@ -60,7 +60,7 @@ class TestSettingsFromEnv(object):
'THEFUCK_REQUIRE_CONFIRMATION': 'true', 'THEFUCK_REQUIRE_CONFIRMATION': 'true',
'THEFUCK_NO_COLORS': 'false', 'THEFUCK_NO_COLORS': 'false',
'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15'}) 'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15'})
conf.init_settings(Mock()) settings.init()
assert settings.rules == ['bash', 'lisp'] assert settings.rules == ['bash', 'lisp']
assert settings.exclude_rules == ['git', 'vim'] assert settings.exclude_rules == ['git', 'vim']
assert settings.wait_command == 55 assert settings.wait_command == 55
@@ -70,26 +70,26 @@ class TestSettingsFromEnv(object):
def test_from_env_with_DEFAULT(self, environ, settings): def test_from_env_with_DEFAULT(self, environ, settings):
environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'}) environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
conf.init_settings(Mock()) settings.init()
assert settings.rules == conf.DEFAULT_RULES + ['bash', 'lisp'] assert settings.rules == conf.DEFAULT_RULES + ['bash', 'lisp']
class TestInitializeSettingsFile(object): class TestInitializeSettingsFile(object):
def test_ignore_if_exists(self): def test_ignore_if_exists(self, settings):
settings_path_mock = Mock(is_file=Mock(return_value=True), open=Mock()) settings_path_mock = Mock(is_file=Mock(return_value=True), open=Mock())
user_dir_mock = Mock(joinpath=Mock(return_value=settings_path_mock)) settings.user_dir = Mock(joinpath=Mock(return_value=settings_path_mock))
conf.initialize_settings_file(user_dir_mock) settings._init_settings_file()
assert settings_path_mock.is_file.call_count == 1 assert settings_path_mock.is_file.call_count == 1
assert not settings_path_mock.open.called assert not settings_path_mock.open.called
def test_create_if_doesnt_exists(self): def test_create_if_doesnt_exists(self, settings):
settings_file = six.StringIO() settings_file = six.StringIO()
settings_path_mock = Mock( settings_path_mock = Mock(
is_file=Mock(return_value=False), is_file=Mock(return_value=False),
open=Mock(return_value=Mock( open=Mock(return_value=Mock(
__exit__=lambda *args: None, __enter__=lambda *args: settings_file))) __exit__=lambda *args: None, __enter__=lambda *args: settings_file)))
user_dir_mock = Mock(joinpath=Mock(return_value=settings_path_mock)) settings.user_dir = Mock(joinpath=Mock(return_value=settings_path_mock))
conf.initialize_settings_file(user_dir_mock) settings._init_settings_file()
settings_file_contents = settings_file.getvalue() settings_file_contents = settings_file.getvalue()
assert settings_path_mock.is_file.call_count == 1 assert settings_path_mock.is_file.call_count == 1
assert settings_path_mock.open.call_count == 1 assert settings_path_mock.open.call_count == 1

View File

@@ -1,17 +1,10 @@
from imp import load_source from imp import load_source
import os import os
import sys import sys
from pathlib import Path
from six import text_type from six import text_type
class Settings(dict):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
ALL_ENABLED = object() ALL_ENABLED = object()
DEFAULT_RULES = [ALL_ENABLED] DEFAULT_RULES = [ALL_ENABLED]
DEFAULT_PRIORITY = 1000 DEFAULT_PRIORITY = 1000
@@ -46,24 +39,62 @@ SETTINGS_HEADER = u"""# ~/.thefuck/settings.py: The Fuck settings file
""" """
def _settings_from_file(user_dir): class Settings(dict):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
def init(self):
"""Fills `settings` with values from `settings.py` and env."""
from .logs import exception
self._setup_user_dir()
self._init_settings_file()
try:
self.update(self._settings_from_file())
except Exception:
exception("Can't load settings from file", sys.exc_info())
try:
self.update(self._settings_from_env())
except Exception:
exception("Can't load settings from env", sys.exc_info())
def _init_settings_file(self):
settings_path = self.user_dir.joinpath('settings.py')
if not settings_path.is_file():
with settings_path.open(mode='w') as settings_file:
settings_file.write(SETTINGS_HEADER)
for setting in DEFAULT_SETTINGS.items():
settings_file.write(u'# {} = {}\n'.format(*setting))
def _setup_user_dir(self):
"""Returns user config dir, create it when it doesn't exist."""
user_dir = Path(os.path.expanduser('~/.thefuck'))
rules_dir = user_dir.joinpath('rules')
if not rules_dir.is_dir():
rules_dir.mkdir(parents=True)
self.user_dir = user_dir
def _settings_from_file(self):
"""Loads settings from file.""" """Loads settings from file."""
settings = load_source('settings', settings = load_source(
text_type(user_dir.joinpath('settings.py'))) 'settings', text_type(self.user_dir.joinpath('settings.py')))
return {key: getattr(settings, key) return {key: getattr(settings, key)
for key in DEFAULT_SETTINGS.keys() for key in DEFAULT_SETTINGS.keys()
if hasattr(settings, key)} if hasattr(settings, key)}
def _rules_from_env(self, val):
def _rules_from_env(val):
"""Transforms rules list from env-string to python.""" """Transforms rules list from env-string to python."""
val = val.split(':') val = val.split(':')
if 'DEFAULT_RULES' in val: if 'DEFAULT_RULES' in val:
val = DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES'] val = DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES']
return val return val
def _priority_from_env(self, val):
def _priority_from_env(val):
"""Gets priority pairs from env.""" """Gets priority pairs from env."""
for part in val.split(':'): for part in val.split(':'):
try: try:
@@ -72,14 +103,13 @@ def _priority_from_env(val):
except ValueError: except ValueError:
continue continue
def _val_from_env(self, env, attr):
def _val_from_env(env, attr):
"""Transforms env-strings to python.""" """Transforms env-strings to python."""
val = os.environ[env] val = os.environ[env]
if attr in ('rules', 'exclude_rules'): if attr in ('rules', 'exclude_rules'):
return _rules_from_env(val) return self._rules_from_env(val)
elif attr == 'priority': elif attr == 'priority':
return dict(_priority_from_env(val)) return dict(self._priority_from_env(val))
elif attr == 'wait_command': elif attr == 'wait_command':
return int(val) return int(val)
elif attr in ('require_confirmation', 'no_colors', 'debug'): elif attr in ('require_confirmation', 'no_colors', 'debug'):
@@ -87,38 +117,11 @@ def _val_from_env(env, attr):
else: else:
return val return val
def _settings_from_env(self):
def _settings_from_env():
"""Loads settings from env.""" """Loads settings from env."""
return {attr: _val_from_env(env, attr) return {attr: self._val_from_env(env, attr)
for env, attr in ENV_TO_ATTR.items() for env, attr in ENV_TO_ATTR.items()
if env in os.environ} if env in os.environ}
settings = Settings(DEFAULT_SETTINGS) settings = Settings(DEFAULT_SETTINGS)
def init_settings(user_dir):
"""Fills `settings` with values from `settings.py` and env."""
from .logs import exception
settings.user_dir = user_dir
try:
settings.update(_settings_from_file(user_dir))
except Exception:
exception("Can't load settings from file", sys.exc_info())
try:
settings.update(_settings_from_env())
except Exception:
exception("Can't load settings from env", sys.exc_info())
def initialize_settings_file(user_dir):
settings_path = user_dir.joinpath('settings.py')
if not settings_path.is_file():
with settings_path.open(mode='w') as settings_file:
settings_file.write(SETTINGS_HEADER)
for setting in DEFAULT_SETTINGS.items():
settings_file.write(u'# {} = {}\n'.format(*setting))

View File

@@ -1,34 +1,19 @@
from argparse import ArgumentParser from argparse import ArgumentParser
from warnings import warn from warnings import warn
from pathlib import Path
from os.path import expanduser
from pprint import pformat from pprint import pformat
import pkg_resources import pkg_resources
import sys import sys
import colorama import colorama
from . import logs, types, shells from . import logs, types, shells
from .conf import initialize_settings_file, init_settings, settings from .conf import settings
from .corrector import get_corrected_commands from .corrector import get_corrected_commands
from .exceptions import EmptyCommand from .exceptions import EmptyCommand
from .ui import select_command from .ui import select_command
def setup_user_dir():
"""Returns user config dir, create it when it doesn't exist."""
user_dir = Path(expanduser('~/.thefuck'))
rules_dir = user_dir.joinpath('rules')
if not rules_dir.is_dir():
rules_dir.mkdir(parents=True)
initialize_settings_file(user_dir)
return user_dir
# Entry points:
def fix_command(): def fix_command():
colorama.init() colorama.init()
user_dir = setup_user_dir() settings.init()
init_settings(user_dir)
with logs.debug_time('Total'): with logs.debug_time('Total'):
logs.debug(u'Run with settings: {}'.format(pformat(settings))) logs.debug(u'Run with settings: {}'.format(pformat(settings)))
@@ -68,8 +53,7 @@ def how_to_configure_alias():
""" """
colorama.init() colorama.init()
user_dir = setup_user_dir() settings.init()
init_settings(user_dir)
logs.how_to_configure_alias(shells.how_to_configure()) logs.how_to_configure_alias(shells.how_to_configure())