Skip to content

Commit

Permalink
Merge pull request #2 from dbosk/make-config-cmd-use-non-default-config
Browse files Browse the repository at this point in the history
Allows specifying config file for `config` command
  • Loading branch information
dbosk committed May 3, 2023
2 parents 6bbb623 + 71c7816 commit d8614b5
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 37 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "typerconf"
version = "1.10"
version = "1.11"
description = "Library to read and write configs using API and CLI with Typer"
authors = ["Daniel Bosk <daniel@bosk.se>"]
license = "MIT"
Expand Down
122 changes: 86 additions & 36 deletions src/typerconf/init.nw
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ config.add_config_cmd(cli)
\end{minted}
So we need to provide such a function.
<<helper functions>>=
def add_config_cmd(cli: typer.Typer):
def add_config_cmd(cli: typer.Typer, conf_path: str = None):
"""
Add config command to Typer cli
Add config command to Typer instance `cli`.

If `conf_path` is not None, use that file instead of the default.
"""
<<config subcommands>>
@
Expand Down Expand Up @@ -619,17 +621,28 @@ def set(path: str, value: typing.Any):
\section{The [[config]] command}

We will provide the [[config]] command as outlined above.
If it gets a value, it will set it as the value at path.
Otherwise, it will print the current value at path.
If we get a path, but the user didn't use [[--set]] and provide a value, we
simply print the value at the end of the path.
If we get a value through [[--set]], we'll update the value at the end of the
path (or create it if it doesn't exist).
This corresponds to how the [[.set]] method of [[Config]] works.

We have access to two variables: [[cli]], the Typer instance to which we want
to add the command; and [[conf_path]], which is the path to the config file.
If [[conf_path]] is [[None]], we should use the default config file (as
determined by the [[.read_config]] method of [[Config]]).
Otherwise, we supply [[.read_config]] with the [[conf_path]] value.
<<config subcommands>>=
path_arg = typer.Argument(...,
help="Path in config, e.g. 'courses.datintro22'. "
"Empty string is root of config.",
autocompletion=complete_path_callback)
value_arg = typer.Option([], "-s", "--set",
help="Values to store. "
"More than one value makes a list. "
"Values are treated as JSON if possible.")
conf = Config()
try:
if conf_path:
conf.read_config(conf_path)
else:
conf.read_config()
except ValueError:
pass

<<default values for [[config_cmd]]>>

@cli.command(name="config")
def config_cmd(path: str = path_arg,
Expand All @@ -640,9 +653,25 @@ def config_cmd(path: str = path_arg,
if values:
<<change [[values]] to non-list if one-element list>>
<<if [[values]] is empty string, replace it with [[None]]>>
set(path, values)
conf.set(path, values)
else:
print_config(get(path), path)
print_config(conf.get(path), path)
@

The default values are the special Typer objects that specify how the command
arguments and options should behave.
We can autocomplete the path since we can predict the possible values.
The same cannot be said of the value to store, that can be arbitrary.
<<default values for [[config_cmd]]>>=
path_arg = typer.Argument("",
help="Path in config, e.g. 'courses.datintro22'. "
"Empty string is root of config. Defaults to "
"the empty string.",
autocompletion=complete_path_callback)
value_arg = typer.Option([], "-s", "--set",
help="Values to store. "
"More than one value makes a list. "
"Values are treated as JSON if possible.")
@

If the user supplies only one argument on the command line, we don't want it to
Expand All @@ -661,35 +690,56 @@ if values == "":
@

Let's test this command.
We'll set up the testing.
<<test functions>>=
runner = CliRunner()

def test_cli():
# set example data
result = runner.invoke(cli,
["courses.datintro22.url", "--set", "https://..."])
assert result.exit_code == 0

# try access nonexisting
result = runner.invoke(cli, ["courses.datintro.url"])
assert result.exit_code == 1

# access existing
result = runner.invoke(cli, ["courses.datintro22.url"])
assert "courses.datintro22.url = https://..." in result.stdout

# clear config
result = runner.invoke(cli,
["courses", "--set", None])
assert result.exit_code == 0

# check that it's cleared
result = runner.invoke(cli, ["courses"])
assert "courses" not in result.stdout
<<run tests on [[cli]]>>
<<test imports>>=
from typer.testing import CliRunner
@

Let's look at the actual tests.
<<run tests on [[cli]]>>=
# set example data
result = runner.invoke(cli,
["courses.datintro22.url", "--set", "https://..."])
assert result.exit_code == 0

# try access nonexisting
result = runner.invoke(cli, ["courses.datintro.url"])
assert result.exit_code == 1

# access existing
result = runner.invoke(cli, ["courses.datintro22.url"])
assert "courses.datintro22.url = https://..." in result.stdout

# clear config
result = runner.invoke(cli,
["courses", "--set", None])
assert result.exit_code == 0

# check that it's cleared
result = runner.invoke(cli, ["courses"])
assert "courses" not in result.stdout
@

Let's also test it with the non-default config.
Note that we want the temporary file to open it ourselves, hence we close it
immediately (through an empty [[with]] statement) and ensure it's not deleted
on closing.
<<test functions>>=
def test_cli_not_default_conf():
with tempfile.NamedTemporaryFile(delete=False) as tmp_conf:
pass

cli = typer.Typer()
add_config_cmd(cli, tmp_conf.name)

<<run tests on [[cli]]>>
@


\subsection{Autocompleting the path}

Expand Down Expand Up @@ -723,7 +773,7 @@ def test_complete_path():
incomplete = "courses.datintro22.T"
assert "courses.datintro22.TAs" in complete_path(incomplete, conf)
assert "courses.datintro22.url" not in complete_path(incomplete, conf)
assert len(complete_path(incomplete, conf)) >= 0
assert len(list(complete_path(incomplete, conf))) >= 0
@

Now, the callback must not have any additional arguments, like we want that
Expand Down

0 comments on commit d8614b5

Please sign in to comment.