Skip to content

Commit 8275d18

Browse files
authored
Merge pull request #20 from openSUSE/bug-cli-and-placeholders
Replace placeholders in cli (and context)
2 parents 8a54ff4 + d5dd5fa commit 8275d18

9 files changed

Lines changed: 17 additions & 21 deletions

File tree

changelog.d/20.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Replace placeholders in :command:`cli` main command. This ensures that the placeholders in the environment or application configuration are replaced before the subcommands are executed. This is necessary because the subcommands might rely on these placeholders being resolved.

src/docbuild/cli/cmd_c14n.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,4 @@ def c14n(ctx: click.Context) -> None:
1212
1313
:param ctx: The Click context object.
1414
"""
15-
ctx.ensure_object(DocBuildContext)
16-
context: DocBuildContext = ctx.obj
17-
click.echo(f'[C17N] Verbosity: {context.verbose}')
15+
click.echo(f'[C17N] Verbosity: {ctx.obj.verbose}')

src/docbuild/cli/cmd_cli.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import click
66

77
from ..__about__ import __version__
8+
from ..config.app import replace_placeholders
89
from ..config.load import handle_config
910
from ..constants import (
1011
APP_CONFIG_BASENAMES,
@@ -117,6 +118,8 @@ def cli(
117118
None,
118119
DEFAULT_APP_CONFIG,
119120
)
121+
context.appconfig = replace_placeholders(context.appconfig)
122+
120123
(
121124
context.envconfigfiles,
122125
context.envconfig,
@@ -128,6 +131,9 @@ def cli(
128131
DEFAULT_ENV_CONFIG_FILENAME,
129132
DEFAULT_ENV_CONFIG,
130133
)
134+
context.envconfig = replace_placeholders(
135+
context.envconfig,
136+
)
131137

132138

133139
# Add subcommand

src/docbuild/cli/cmd_validate.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,11 @@ def validate(ctx: click.Context, xmlfiles: tuple | Iterator[Path]) -> None:
2626
2727
:param ctx: The Click context object.
2828
"""
29-
ctx.ensure_object(DocBuildContext)
3029
context: DocBuildContext = ctx.obj
3130
if context.envconfig is None:
3231
# log.critical('No envconfig found in context.')
3332
raise ValueError('No envconfig found in context.')
3433

35-
# Replace placeholders in the envconfig
36-
# TODO: shouldn't this be done somewhere else? In the context initialization?
37-
context.envconfig = replace_placeholders(context.envconfig)
38-
3934
if (paths := ctx.obj.envconfig.get('paths')) is None:
4035
raise ValueError('No paths found in envconfig.')
4136

src/docbuild/config/app.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
import re
44
from typing import Any
55

6-
# Type aliases
7-
Container = dict[str, Any] | list[Any]
8-
"""A dictionary or list container for any configuration data."""
9-
106
MAX_RECURSION_DEPTH: int = 10
117
"""The maximum recursion depth for placeholder replacement."""
128

@@ -159,9 +155,9 @@ def replace(self) -> dict[str, Any]:
159155

160156

161157
def replace_placeholders(
162-
config: dict[str, Any],
158+
config: dict[str, Any] | None,
163159
max_recursion_depth: int = MAX_RECURSION_DEPTH,
164-
) -> Container:
160+
) -> dict[str, Any] | None:
165161
"""Replace placeholder values in a nested dictionary structure.
166162
167163
* ``{foo}`` resolves from the current section.

src/docbuild/config/load.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from typing import Any
88

99
from ..constants import DEFAULT_ENV_CONFIG_FILENAME
10-
from .app import Container, replace_placeholders
10+
from .app import replace_placeholders
1111
from .merge import deep_merge
1212

1313

14-
def process_envconfig(envconfigfile: str | Path | None) -> tuple[Path, Container]:
14+
def process_envconfig(envconfigfile: str | Path | None) -> tuple[Path, dict[str, Any]]:
1515
"""Process the env config.
1616
1717
:param envconfigfile: Path to the env TOML config file.

tests/cli/test_cmd_c14n.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test_c14n_command_with_high_verbosity(self, runner):
3636
def test_c14n_command_without_context_object(self, runner):
3737
"""Test c14n command without passing a context object."""
3838
# Don't pass obj parameter - this will test ctx.ensure_object()
39-
result = runner.invoke(cmd_c14n.c14n, [])
39+
result = runner.invoke(cmd_c14n.c14n, [], obj=DocBuildContext())
4040

4141
assert result.exit_code == 0
4242
# Should create a default context with verbose=0

tests/cli/test_cmd_cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def fake_handle_config(user_path, *a, **kw):
3030
monkeypatch.setattr(cli_mod, 'handle_config', fake_handle_config)
3131
result = runner.invoke(cli, ['--app-config', str(app_file), 'capture'])
3232
assert result.exit_code == 0
33-
assert result.output.strip() == 'capture'
33+
assert 'capture' in result.output.strip()
3434

3535

3636
def test_cli_with_app_and_env_config(monkeypatch, runner, tmp_path):
@@ -62,7 +62,7 @@ def fake_handle_config(user_path, *a, **kw):
6262
obj=context,
6363
)
6464
assert result.exit_code == 0
65-
assert result.output == 'capture\n'
65+
assert 'capture' in result.output.strip()
6666

6767
assert context.appconfigfiles == (app_file,)
6868
assert context.appconfig == {'app_config_data': 'app_content'}
@@ -94,7 +94,7 @@ def fake_handle_config(user_path, *a, **kw):
9494
obj=context,
9595
)
9696
assert result.exit_code == 0
97-
assert result.output == 'capture\n'
97+
assert 'capture\n' in result.output
9898
assert context.verbose == 3
9999
assert context.debug is True
100100
assert context.appconfigfiles == (app_file,)

tests/cli/test_cmd_validate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def test_validate_no_envconfig_in_context(self, runner):
269269
Path('test.xml').write_text('<?xml version="1.0"?><root></root>')
270270
# When no context object is passed, a default one is created,
271271
# which has envconfig=None, triggering the error.
272-
result = runner.invoke(validate, ['test.xml'])
272+
result = runner.invoke(validate, ['test.xml'], obj=DocBuildContext())
273273

274274
assert result.exit_code != 0
275275
assert isinstance(result.exception, ValueError)

0 commit comments

Comments
 (0)