Metadata-Version: 2.4
Name: argsl
Version: 0.1.2
Summary: A readable DSL on top of argparse
Author-email: Gwang-Jin Kim <gwang.jin.kim.phd@gmail.com>
License: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# argsl️

A clean and readable DSL for building command-line interfaces in Python — **without the boilerplate**.

`argsl` is for developers who want fast, expressive CLI definitions using just a few lines of text.

---

## Why use `argsl`?

Python’s built-in `argparse` is powerful but verbose:

```python
# argparse version
parser = argparse.ArgumentParser()
parser.add_argument("filename", type=pathlib.Path)
parser.add_argument("--name", required=True)
parser.add_argument("--debug", action="store_true")
```

With `argsl`:

```python
args = argsl("""
filename <path!>         # required positional
--name <str!>            # required flag
--debug <flag>           # boolean switch
""")
```

- ✅ **Expressive**: just describe your arguments
- ✅ **No boilerplate**: get `argparse.Namespace` directly
- ✅ **Typed and validated**: int, float, str, path, bool, choices, etc.
- ✅ **Compatible with argparse**: wraps it internally

---

## Installation

### Using [`uv`](https://github.com/astral-sh/uv) (recommended):
```bash
uv pip install argsl
```

### Or with `pip`:
```bash
pip install argsl
```

---

## 🚀 Basic Example

```python
from argsl import argsl

args = argsl("""
filename <path!>                        # required positional
--name|-n <str=env:USER>                # optional with env fallback
--level|-l <choice:low,med,high="med"> # choice with default
--debug|-d <flag>                       # boolean flag
--onlylong <int=1>                      # long-only argument
--no-cache <flag>                       # negate behavior if passed
""")

print(vars(args))
```

In your `pyproject.toml`:
```toml
[project.scripts]
run = "main:main"
```
Run it:
```bash
uv run run file.txt --name Alice --debug --level high --no-cache
```

---

## Supported Argument Types

| DSL Expression               | Description                            |
|-----------------------------|----------------------------------------|
| `<str>`, `<int>`, `<float>` | Single typed argument                  |
| `<path>`                    | File/path via `pathlib.Path`           |
| `<flag>`                    | Boolean flag (false unless present)    |
| `<str!>`                    | Required string argument               |
| `<int=42>`                  | With default value                     |
| `<choice:a,b,c="b">`        | Choice + default                       |
| `<str*>`                    | Accept multiple values                 |
| `=env:VAR`                  | Fallback to environment variable       |

---

## Supported Flag Variants

```python
args = argsl("""
--user|-u <str!>      # short + long
--only <int=1>        # long-only
--debug <flag>        # long-only boolean flag
--no-cache <flag>     # negated logic: default False → True if passed
""")
```

---

## Test Coverage & Edge Cases

✔ Required positional + typed
✔ Required named args (`--foo <str!>`)  
✔ Optional args with defaults (`--bar <int=42>`)  
✔ Multiple values (`--list <str*>`)
✔ Boolean flags (`--debug <flag>`)  
✔ Env fallback (`--x <str=env:HOME>`)  
✔ Quoted defaults (`--title <str="The Answer">`)  
✔ Long-only or short+long (`--onlylong`, `--msg|-m`)
✔ Choice types (`--level <choice:low,med,high="med">`)
✔ All covered in `tests/test_argsl_all.py`

---

## Development Workflow

```bash
uv pip install .[dev]
uv pip install '.[dev]'   # on zsh (macos)
uv run test
```

Or with classic tools:
```bash
pip install -e .[dev]
pip install -e '.[dev]'   # on zsh (macos)
pytest
```

---

## Publishing to PyPI

```bash
rm -rf dist/     # necessary - otherwise PyPI would upload old version, too, resulting in an error
uv build
uv publish
```

---

MIT licensed • Built by Gwang-Jin Kim
