Skip to content

Commit 4c2df02

Browse files
committed
load_config() should load all commands. #395
1 parent 15ac74f commit 4c2df02

File tree

5 files changed

+50
-50
lines changed

5 files changed

+50
-50
lines changed

src/reader/_app/legacy/wsgi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import reader._cli
1717

1818

19-
config = reader._cli.load_reader_config('web')
19+
config = reader._cli.load_reader_config()
2020
app = reader._app.create_app(config)
2121
app.config['TRAP_BAD_REQUEST_ERRORS'] = bool(
2222
os.environ.get('FLASK_TRAP_BAD_REQUEST_ERRORS', '')

src/reader/_app/wsgi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import reader._cli
1717

1818

19-
config = reader._cli.load_reader_config('web')
19+
config = reader._cli.load_reader_config()
2020
app = reader._app.create_app(config)
2121
app.config['TRAP_BAD_REQUEST_ERRORS'] = bool(
2222
os.environ.get('FLASK_TRAP_BAD_REQUEST_ERRORS', '')

src/reader/_cli.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@
2727
log = logging.getLogger(__name__)
2828

2929

30-
def load_reader_config(*args, path=None, silent=False):
31-
env = None
30+
def load_reader_config(path=None, silent=False):
31+
prefix = env = None
3232
if path:
3333
if not silent:
34-
args = ('--config', str(path)) + args
34+
prefix = ('--config', os.fspath(path))
3535
else:
36-
env = {'READER_CONFIG': str(path)}
37-
config = load_config(cli, args, env)
36+
env = {'READER_CONFIG': os.fspath(path)}
37+
config = load_config(cli, prefix, env)
3838
config[''] = extract_args(config[''], make_reader)
3939
return config
4040

src/reader/_config_utils.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ def config_option(*args, **kwargs):
2323
)
2424

2525

26-
def load_config(command, args=None, env=None):
27-
"""Return the parameters from invoking command with args,
26+
def load_config(command, prefix=None, env=None):
27+
"""Return the parameters from invoking command and its subcommands,
2828
but without actually running any (sub)command.
2929
3030
Together with an option using load_defaults(),
@@ -38,23 +38,31 @@ def load_config(command, args=None, env=None):
3838
3939
"""
4040
command = copy.deepcopy(command)
41-
calls = {}
41+
prefix = tuple(prefix or ())
42+
params = {}
43+
leaves = []
4244

4345
def callback(**kwargs):
44-
calls.update(load_config_from_context())
46+
params.update(load_config_from_context())
4547

46-
def patch_command(command):
48+
def patch_command(command, path=()):
4749
command.callback = callback
4850
command.no_args_is_help = False
51+
for param in list(command.params):
52+
if isinstance(param, click.Argument):
53+
command.params.remove(param)
4954
if hasattr(command, 'commands'):
5055
command.invoke_without_command = True
51-
for subcommand in command.commands.values():
52-
patch_command(subcommand)
56+
for sub_name, sub in command.commands.items():
57+
patch_command(sub, path + (sub_name,))
58+
else:
59+
leaves.append(path)
5360

5461
patch_command(command)
5562
runner = click.testing.CliRunner(catch_exceptions=False)
56-
runner.invoke(command, args, env=env, standalone_mode=False, prog_name='')
57-
return calls
63+
for args in leaves:
64+
runner.invoke(command, prefix + args, env=env, standalone_mode=False)
65+
return params
5866

5967

6068
def load_config_from_context():

tests/test_config_utils.py

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,37 +31,35 @@ def with_config(config):
3131
return with_config
3232

3333

34-
def check_all(args, expected, **kwargs):
34+
def invoke(cli, args=None, env=None):
3535
runner = CliRunner(catch_exceptions=False)
36+
result = runner.invoke(cli, args, env=env, standalone_mode=False)
37+
return result.return_value
3638

37-
result = runner.invoke(cli, args, standalone_mode=False, **kwargs)
38-
assert expected == result.return_value
39-
40-
loaded = load_config(cli, args)
41-
assert expected == loaded
42-
43-
44-
def check_error(args, strings=(), exc_type=click.BadParameter, **kwargs):
45-
runner = CliRunner(catch_exceptions=False)
4639

40+
def check_error(strings=(), exc_type=click.BadParameter):
4741
with pytest.raises(exc_type) as exc_info:
48-
runner.invoke(cli, args, standalone_mode=False, **kwargs)
42+
invoke(cli, ['sub'])
4943
for s in strings:
5044
assert s in str(exc_info.value).lower()
5145

5246
with pytest.raises(exc_type) as exc_info:
53-
loaded = load_config(cli, args)
47+
loaded = load_config(cli)
5448
for s in strings:
5549
assert s in str(exc_info.value).lower()
5650

5751

5852
def test_no_config():
59-
check_all(['sub'], {'': {'plugin': ()}, 'sub': {'option': 'DEFAULT'}})
53+
expected = {'': {'plugin': ()}, 'sub': {'option': 'DEFAULT'}}
54+
assert invoke(cli, ['sub']) == expected
55+
assert load_config(cli) == expected
6056

6157

6258
def test_empty_config(with_config):
6359
with_config("[cli]")
64-
check_all(['sub'], {'': {'plugin': ()}, 'sub': {'option': 'DEFAULT'}})
60+
expected = {'': {'plugin': ()}, 'sub': {'option': 'DEFAULT'}}
61+
assert invoke(cli, ['sub']) == expected
62+
assert load_config(cli) == expected
6563

6664

6765
def test_config(with_config):
@@ -73,43 +71,37 @@ def test_config(with_config):
7371
option='config'
7472
"""
7573
)
76-
load_config(cli, []) == {'': {'plugin': ('CONFIG',)}}
77-
check_all(
78-
['sub'],
79-
{
80-
'': {'plugin': ('CONFIG',)},
81-
'sub': {'option': 'CONFIG'},
82-
},
83-
)
84-
check_all(
85-
['--plugin', 'user', 'sub', '--option', 'user'],
86-
{
87-
'': {'plugin': ('CONFIG', 'USER')},
88-
'sub': {'option': 'USER'},
89-
},
90-
)
74+
75+
expected = {'': {'plugin': ('CONFIG',)}, 'sub': {'option': 'CONFIG'}}
76+
assert invoke(cli, ['sub']) == expected
77+
assert load_config(cli) == expected
78+
79+
env = {'CLI_SUB_OPTION': 'env'}
80+
expected = {'': {'plugin': ('CONFIG', 'USER')}, 'sub': {'option': 'ENV'}}
81+
assert invoke(cli, ['--plugin', 'user', 'sub'], env=env)
82+
assert load_config(cli, ['--plugin', 'user'], env=env)
9183

9284

9385
def test_toml_error(with_config):
9486
with_config("[cli")
95-
check_error(['sub'], ['toml error'])
87+
check_error(['toml error'])
9688

9789

9890
def test_no_section_error(with_config):
9991
with_config("")
100-
check_error(['sub'], ['no [cli] section'])
92+
check_error(['no [cli] section'])
10193

10294

10395
def test_bad_section_type_error(with_config):
10496
with_config("cli = 1")
105-
check_error(['sub'], ['cli:', 'expected mapping'])
97+
check_error(['cli:', 'expected mapping'])
10698

10799

108100
def test_unknown_option_error(with_config):
109101
with_config("[cli]\nunknown = 1")
110-
check_error(['sub'], ['cli.unknown:', 'no such option'])
102+
check_error(['cli.unknown:', 'no such option'])
111103

112104

113105
def test_unknown_command_error(with_config):
114106
with_config("[cli.unknown]")
115-
check_error(['sub'], ['cli.unknown:', 'no such option'])
107+
check_error(['cli.unknown:', 'no such option'])

0 commit comments

Comments
 (0)