[settings] Better impl. of Setting class, tests for it and refactor hardcoded settings to use it.
This commit is contained in:
@ -45,7 +45,7 @@ def run(graph, strategy=None, plugins=None, services=None):
|
||||
from bonobo import settings
|
||||
settings.check()
|
||||
|
||||
if not settings.QUIET: # pragma: no cover
|
||||
if not settings.QUIET.get(): # pragma: no cover
|
||||
if _is_interactive_console():
|
||||
from bonobo.ext.console import ConsoleOutputPlugin
|
||||
if ConsoleOutputPlugin not in plugins:
|
||||
|
||||
@ -27,9 +27,9 @@ def entrypoint(args=None):
|
||||
|
||||
args = parser.parse_args(args).__dict__
|
||||
if args.pop('debug', False):
|
||||
settings.DEBUG = True
|
||||
settings.LOGGING_LEVEL = logging.DEBUG
|
||||
logging.set_level(settings.LOGGING_LEVEL)
|
||||
settings.DEBUG.set(True)
|
||||
settings.LOGGING_LEVEL.set(logging.DEBUG)
|
||||
logging.set_level(settings.LOGGING_LEVEL.get())
|
||||
|
||||
logger.debug('Command: ' + args['command'] + ' Arguments: ' + repr(args))
|
||||
commands[args.pop('command')](**args)
|
||||
|
||||
@ -31,10 +31,10 @@ def execute(filename, module, install=False, quiet=False, verbose=False):
|
||||
from bonobo import Graph, run, settings
|
||||
|
||||
if quiet:
|
||||
settings.QUIET = True
|
||||
settings.QUIET.set(True)
|
||||
|
||||
if verbose:
|
||||
settings.DEBUG = True
|
||||
settings.DEBUG.set(True)
|
||||
|
||||
if filename:
|
||||
if os.path.isdir(filename):
|
||||
|
||||
@ -65,7 +65,7 @@ class ConsoleOutputPlugin(Plugin):
|
||||
|
||||
for i in context.graph.topologically_sorted_indexes:
|
||||
node = context[i]
|
||||
name_suffix = '({})'.format(i) if settings.DEBUG else ''
|
||||
name_suffix = '({})'.format(i) if settings.DEBUG.get() else ''
|
||||
if node.alive:
|
||||
_line = ''.join(
|
||||
(
|
||||
@ -100,7 +100,7 @@ class ConsoleOutputPlugin(Plugin):
|
||||
print(MOVE_CURSOR_UP(t_cnt + 2), file=sys.stderr)
|
||||
|
||||
def _write(self, graph_context, rewind):
|
||||
if settings.PROFILE:
|
||||
if settings.PROFILE.get():
|
||||
if self.counter % 10 and self._append_cache:
|
||||
append = self._append_cache
|
||||
else:
|
||||
|
||||
@ -75,4 +75,4 @@ def get_logger(name='bonobo'):
|
||||
getLogger = get_logger
|
||||
|
||||
# Setup formating and level.
|
||||
setup(level=settings.LOGGING_LEVEL)
|
||||
setup(level=settings.LOGGING_LEVEL.get())
|
||||
|
||||
@ -69,7 +69,7 @@ def _count_counter(self, context):
|
||||
|
||||
class PrettyPrinter(Configurable):
|
||||
def call(self, *args, **kwargs):
|
||||
formater = self._format_quiet if settings.QUIET else self._format_console
|
||||
formater = self._format_quiet if settings.QUIET.get() else self._format_console
|
||||
|
||||
for i, (item, value) in enumerate(itertools.chain(enumerate(args), kwargs.items())):
|
||||
print(formater(i, item, value))
|
||||
|
||||
@ -5,6 +5,10 @@ from bonobo.errors import ValidationError
|
||||
|
||||
|
||||
def to_bool(s):
|
||||
if s is None:
|
||||
return False
|
||||
if type(s) is bool:
|
||||
return s
|
||||
if len(s):
|
||||
if s.lower() in ('f', 'false', 'n', 'no', '0'):
|
||||
return False
|
||||
@ -13,7 +17,18 @@ def to_bool(s):
|
||||
|
||||
|
||||
class Setting:
|
||||
def __init__(self, name, default=None, validator=None):
|
||||
__all__ = {}
|
||||
|
||||
@classmethod
|
||||
def clear_all(cls):
|
||||
for setting in Setting.__all__.values():
|
||||
setting.clear()
|
||||
|
||||
def __new__(cls, name, *args, **kwargs):
|
||||
Setting.__all__[name] = super().__new__(cls)
|
||||
return Setting.__all__[name]
|
||||
|
||||
def __init__(self, name, default=None, validator=None, formatter=None):
|
||||
self.name = name
|
||||
|
||||
if default:
|
||||
@ -21,15 +36,14 @@ class Setting:
|
||||
else:
|
||||
self.default = lambda: None
|
||||
|
||||
if validator:
|
||||
self.validator = validator
|
||||
else:
|
||||
self.validator = None
|
||||
self.validator = validator
|
||||
self.formatter = formatter
|
||||
|
||||
def __repr__(self):
|
||||
return '<Setting {}={!r}>'.format(self.name, self.get())
|
||||
|
||||
def set(self, value):
|
||||
value = self.formatter(value) if self.formatter else value
|
||||
if self.validator and not self.validator(value):
|
||||
raise ValidationError('Invalid value {!r} for setting {}.'.format(value, self.name))
|
||||
self.value = value
|
||||
@ -38,21 +52,35 @@ class Setting:
|
||||
try:
|
||||
return self.value
|
||||
except AttributeError:
|
||||
self.value = self.default()
|
||||
value = os.environ.get(self.name, None)
|
||||
if value is None:
|
||||
value = self.default()
|
||||
self.set(value)
|
||||
return self.value
|
||||
|
||||
def clear(self):
|
||||
try:
|
||||
del self.value
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
# Debug/verbose mode.
|
||||
DEBUG = to_bool(os.environ.get('DEBUG', 'f'))
|
||||
DEBUG = Setting('DEBUG', formatter=to_bool, default=False)
|
||||
|
||||
# Profile mode.
|
||||
PROFILE = to_bool(os.environ.get('PROFILE', 'f'))
|
||||
PROFILE = Setting('PROFILE', formatter=to_bool, default=False)
|
||||
|
||||
# Quiet mode.
|
||||
QUIET = to_bool(os.environ.get('QUIET', 'f'))
|
||||
QUIET = Setting('QUIET', formatter=to_bool, default=False)
|
||||
|
||||
# Logging level.
|
||||
LOGGING_LEVEL = logging.DEBUG if DEBUG else logging.INFO
|
||||
LOGGING_LEVEL = Setting(
|
||||
'LOGGING_LEVEL',
|
||||
formatter=logging._checkLevel,
|
||||
validator=logging._checkLevel,
|
||||
default=lambda: logging.DEBUG if DEBUG.get() else logging.INFO
|
||||
)
|
||||
|
||||
# Input/Output format for transformations
|
||||
IOFORMAT_ARG0 = 'arg0'
|
||||
@ -67,5 +95,8 @@ IOFORMAT = Setting('IOFORMAT', default=IOFORMAT_KWARGS, validator=IOFORMATS.__co
|
||||
|
||||
|
||||
def check():
|
||||
if DEBUG and QUIET:
|
||||
if DEBUG.get() and QUIET.get():
|
||||
raise RuntimeError('I cannot be verbose and quiet at the same time.')
|
||||
|
||||
|
||||
clear_all = Setting.clear_all
|
||||
|
||||
63
tests/test_settings.py
Normal file
63
tests/test_settings.py
Normal file
@ -0,0 +1,63 @@
|
||||
import logging
|
||||
from os import environ
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from bonobo import settings
|
||||
|
||||
TEST_SETTING = 'TEST_SETTING'
|
||||
|
||||
|
||||
def test_to_bool():
|
||||
assert not settings.to_bool('')
|
||||
assert not settings.to_bool('FALSE')
|
||||
assert not settings.to_bool('NO')
|
||||
assert not settings.to_bool('0')
|
||||
|
||||
assert settings.to_bool('yup')
|
||||
assert settings.to_bool('True')
|
||||
assert settings.to_bool('yes')
|
||||
assert settings.to_bool('1')
|
||||
|
||||
|
||||
def test_setting():
|
||||
s = settings.Setting(TEST_SETTING)
|
||||
assert s.get() is None
|
||||
|
||||
with patch.dict(environ, {TEST_SETTING: 'hello'}):
|
||||
assert s.get() is None
|
||||
s.clear()
|
||||
assert s.get() == 'hello'
|
||||
|
||||
s = settings.Setting(TEST_SETTING, default='nope')
|
||||
assert s.get() is 'nope'
|
||||
|
||||
with patch.dict(environ, {TEST_SETTING: 'hello'}):
|
||||
assert s.get() == 'nope'
|
||||
s.clear()
|
||||
assert s.get() == 'hello'
|
||||
|
||||
|
||||
def test_default_settings():
|
||||
settings.clear_all()
|
||||
|
||||
assert settings.DEBUG.get() == False
|
||||
assert settings.PROFILE.get() == False
|
||||
assert settings.QUIET.get() == False
|
||||
assert settings.LOGGING_LEVEL.get() == logging._checkLevel('INFO')
|
||||
|
||||
with patch.dict(environ, {'DEBUG': 't'}):
|
||||
settings.clear_all()
|
||||
assert settings.LOGGING_LEVEL.get() == logging._checkLevel('DEBUG')
|
||||
|
||||
settings.clear_all()
|
||||
|
||||
|
||||
def test_check():
|
||||
settings.check()
|
||||
with patch.dict(environ, {'DEBUG': 't', 'PROFILE': 't', 'QUIET': 't'}):
|
||||
settings.clear_all()
|
||||
with pytest.raises(RuntimeError):
|
||||
settings.check()
|
||||
settings.clear_all()
|
||||
Reference in New Issue
Block a user