1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-02-21 20:38:54 +00: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,79 +39,89 @@ SETTINGS_HEADER = u"""# ~/.thefuck/settings.py: The Fuck settings file
""" """
def _settings_from_file(user_dir): class Settings(dict):
"""Loads settings from file.""" def __getattr__(self, item):
settings = load_source('settings', return self.get(item)
text_type(user_dir.joinpath('settings.py')))
return {key: getattr(settings, key)
for key in DEFAULT_SETTINGS.keys()
if hasattr(settings, key)}
def __setattr__(self, key, value):
self[key] = value
def _rules_from_env(val): def init(self):
"""Transforms rules list from env-string to python.""" """Fills `settings` with values from `settings.py` and env."""
val = val.split(':') from .logs import exception
if 'DEFAULT_RULES' in val:
val = DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES']
return val
self._setup_user_dir()
self._init_settings_file()
def _priority_from_env(val):
"""Gets priority pairs from env."""
for part in val.split(':'):
try: try:
rule, priority = part.split('=') self.update(self._settings_from_file())
yield rule, int(priority) except Exception:
except ValueError: exception("Can't load settings from file", sys.exc_info())
continue
try:
self.update(self._settings_from_env())
except Exception:
exception("Can't load settings from env", sys.exc_info())
def _val_from_env(env, attr): def _init_settings_file(self):
"""Transforms env-strings to python.""" settings_path = self.user_dir.joinpath('settings.py')
val = os.environ[env] if not settings_path.is_file():
if attr in ('rules', 'exclude_rules'): with settings_path.open(mode='w') as settings_file:
return _rules_from_env(val) settings_file.write(SETTINGS_HEADER)
elif attr == 'priority': for setting in DEFAULT_SETTINGS.items():
return dict(_priority_from_env(val)) settings_file.write(u'# {} = {}\n'.format(*setting))
elif attr == 'wait_command':
return int(val) def _setup_user_dir(self):
elif attr in ('require_confirmation', 'no_colors', 'debug'): """Returns user config dir, create it when it doesn't exist."""
return val.lower() == 'true' user_dir = Path(os.path.expanduser('~/.thefuck'))
else: 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."""
settings = load_source(
'settings', text_type(self.user_dir.joinpath('settings.py')))
return {key: getattr(settings, key)
for key in DEFAULT_SETTINGS.keys()
if hasattr(settings, key)}
def _rules_from_env(self, val):
"""Transforms rules list from env-string to python."""
val = val.split(':')
if 'DEFAULT_RULES' in val:
val = DEFAULT_RULES + [rule for rule in val if rule != 'DEFAULT_RULES']
return val return val
def _priority_from_env(self, val):
"""Gets priority pairs from env."""
for part in val.split(':'):
try:
rule, priority = part.split('=')
yield rule, int(priority)
except ValueError:
continue
def _settings_from_env(): def _val_from_env(self, env, attr):
"""Loads settings from env.""" """Transforms env-strings to python."""
return {attr: _val_from_env(env, attr) val = os.environ[env]
for env, attr in ENV_TO_ATTR.items() if attr in ('rules', 'exclude_rules'):
if env in os.environ} return self._rules_from_env(val)
elif attr == 'priority':
return dict(self._priority_from_env(val))
elif attr == 'wait_command':
return int(val)
elif attr in ('require_confirmation', 'no_colors', 'debug'):
return val.lower() == 'true'
else:
return val
def _settings_from_env(self):
"""Loads settings from env."""
return {attr: self._val_from_env(env, attr)
for env, attr in ENV_TO_ATTR.items()
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())