Skip to content

Commit

Permalink
feat: Allow passing additional arguments, preventing their interpreta…
Browse files Browse the repository at this point in the history
…tion by delimitating them with `--` if needed

Issue-15: #15
  • Loading branch information
pawamoy committed May 19, 2024
1 parent 55c9b9f commit 9df0437
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 4 deletions.
36 changes: 33 additions & 3 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -598,9 +598,10 @@ in the duty's signature. If there is no annotation
but a default value, it will be type-casted using
the type of the default value.

We only support types that are callable and accept
one positional argument: a string.
Examples of supported builtin types: `int`, `str`, `float`, `bool`, `list`, etc.
We support any type that is callable and accepts
one positional argument (a string), as well as
optional types (`Optional[...]`, `... | None`)
and union types (`Union[..., ...]`, `... | ...`).

The `bool` type uses a special conversion table:

Expand Down Expand Up @@ -652,6 +653,35 @@ make sure there is no overlap between other duties' names
and the argument value, otherwise `duty` will not be able
to parse the command correctly.

If your duty accepts variadic positional arguments,
those can be passed too from the command line:

```python
@duty
def shout(ctx, *names):
ctx.run(print, args=[f"{name.upper()}!" for name in names])
```

```bash
duty shout herbert marvin
```

This can also be used to pass additional CLI flags
to commands or duty tools. If the flags clash with
duty's own options, add `--` first:

```python
from duty import duty, tools

@duty
def docs(ctx, *cli_args) -> None:
ctx.run(tools.mkdocs.serve().add_args(*cli_args), capture=False)
```

```bash
duty docs -- -vs -f mkdocs.yml
```

### Passing options

Usage summary:
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ classifiers = [
dependencies = [
"eval-type-backport; python_version < '3.10'",
"failprint>=0.11,!=1.0.0",
"typing-extensions>=4.0; python_version < '3.11'",
]

[project.urls]
Expand Down
2 changes: 2 additions & 0 deletions src/duty/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ def parse_commands(arg_lists: list[list[str]], global_opts: dict[str, Any], coll
for arg_list in arg_lists:
duty = collection.get(arg_list[0])
opts, remainder = parse_options(duty, arg_list[1:])
if remainder and remainder[0] == "--":
remainder = remainder[1:]
duty.options_override = {**global_opts, **opts}
commands.append((duty, *parse_args(duty, remainder)))
return commands
Expand Down
16 changes: 15 additions & 1 deletion src/duty/tools/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
from io import StringIO
from typing import Any

if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self


class LazyStdout(StringIO):
"""Lazy stdout buffer.
Expand Down Expand Up @@ -41,10 +46,19 @@ class Tool:

cli_name: str = ""

def __init__(self, cli_args: list[str] | None = None, py_args: dict[str, Any] | None = None) -> None:
def __init__(
self,
cli_args: list[str] | None = None,
py_args: dict[str, Any] | None = None,
) -> None:
self.cli_args: list[str] = cli_args or []
self.py_args: dict[str, Any] = py_args or {}

def add_args(self, *args: str) -> Self:
"""Add arguments."""
self.cli_args.extend(args)
return self

@property
def cli_command(self) -> str:
if not self.cli_name:
Expand Down

0 comments on commit 9df0437

Please sign in to comment.