confargs 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. confargs-0.2.0/.gitattributes +29 -0
  2. confargs-0.2.0/.github/workflows/ci.yml +66 -0
  3. confargs-0.2.0/.github/workflows/pr-title.yml +35 -0
  4. confargs-0.2.0/.github/workflows/publish.yml +38 -0
  5. confargs-0.2.0/.github/workflows/release-please.yml +41 -0
  6. confargs-0.2.0/.gitignore +26 -0
  7. confargs-0.2.0/.pre-commit-config.yaml +28 -0
  8. confargs-0.2.0/.release-please-manifest.json +3 -0
  9. confargs-0.2.0/CHANGELOG.md +86 -0
  10. confargs-0.2.0/LICENSE +21 -0
  11. confargs-0.2.0/PKG-INFO +222 -0
  12. confargs-0.2.0/README.md +197 -0
  13. confargs-0.2.0/examples/README.md +22 -0
  14. confargs-0.2.0/examples/demo.py +77 -0
  15. confargs-0.2.0/examples/example.args +10 -0
  16. confargs-0.2.0/pyproject.toml +80 -0
  17. confargs-0.2.0/release-please-config.json +32 -0
  18. confargs-0.2.0/src/confargs/__init__.py +44 -0
  19. confargs-0.2.0/src/confargs/argfile.py +77 -0
  20. confargs-0.2.0/src/confargs/base.py +72 -0
  21. confargs-0.2.0/src/confargs/cli.py +167 -0
  22. confargs-0.2.0/src/confargs/coercion.py +129 -0
  23. confargs-0.2.0/src/confargs/demo.py +77 -0
  24. confargs-0.2.0/src/confargs/env_source.py +50 -0
  25. confargs-0.2.0/src/confargs/exceptions.py +62 -0
  26. confargs-0.2.0/src/confargs/help.py +79 -0
  27. confargs-0.2.0/src/confargs/namespace.py +69 -0
  28. confargs-0.2.0/src/confargs/options.py +261 -0
  29. confargs-0.2.0/src/confargs/processor.py +250 -0
  30. confargs-0.2.0/src/confargs/py.typed +0 -0
  31. confargs-0.2.0/src/confargs/toml_source.py +105 -0
  32. confargs-0.2.0/tests/__init__.py +0 -0
  33. confargs-0.2.0/tests/robot_cli.py +222 -0
  34. confargs-0.2.0/tests/test_cli.py +156 -0
  35. confargs-0.2.0/tests/test_coercion.py +151 -0
  36. confargs-0.2.0/tests/test_eager.py +144 -0
  37. confargs-0.2.0/tests/test_env_source.py +66 -0
  38. confargs-0.2.0/tests/test_example.py +80 -0
  39. confargs-0.2.0/tests/test_help.py +73 -0
  40. confargs-0.2.0/tests/test_options.py +169 -0
  41. confargs-0.2.0/tests/test_processor.py +258 -0
  42. confargs-0.2.0/tests/test_robot_cli.py +232 -0
  43. confargs-0.2.0/tests/test_toml_source.py +128 -0
  44. confargs-0.2.0/uv.lock +788 -0
@@ -0,0 +1,29 @@
1
+ # Normalize all text files to LF on checkout and commit.
2
+ * text=auto eol=lf
3
+
4
+ # Explicit text file declarations.
5
+ *.py text eol=lf
6
+ *.pyi text eol=lf
7
+ *.toml text eol=lf
8
+ *.cfg text eol=lf
9
+ *.ini text eol=lf
10
+ *.yml text eol=lf
11
+ *.yaml text eol=lf
12
+ *.md text eol=lf
13
+ *.rst text eol=lf
14
+ *.txt text eol=lf
15
+ *.json text eol=lf
16
+ *.sh text eol=lf
17
+ .gitignore text eol=lf
18
+ .gitattributes text eol=lf
19
+ py.typed text eol=lf
20
+
21
+ # Binary files (never normalized).
22
+ *.png binary
23
+ *.jpg binary
24
+ *.jpeg binary
25
+ *.gif binary
26
+ *.ico binary
27
+ *.whl binary
28
+ *.gz binary
29
+ *.zip binary
@@ -0,0 +1,66 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ env:
13
+ # Pin uv for reproducible CI; bump deliberately.
14
+ UV_VERSION: "0.12.7"
15
+
16
+ jobs:
17
+ lint:
18
+ runs-on: ubuntu-latest
19
+ env:
20
+ UV_PYTHON: "3.12"
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v3
25
+ with:
26
+ version: ${{ env.UV_VERSION }}
27
+ enable-cache: true
28
+ - name: Sync (locked)
29
+ run: uv sync --locked
30
+ - name: Ruff (lint)
31
+ run: uv run ruff check .
32
+ - name: Ruff (format check)
33
+ run: uv run ruff format --check .
34
+ - name: Mypy
35
+ run: uv run mypy
36
+
37
+ test:
38
+ name: test (${{ matrix.os }}, py${{ matrix.python-version }})
39
+ runs-on: ${{ matrix.os }}
40
+ env:
41
+ # setup-uv@v3 has no `python-version` input, so uv picks the interpreter
42
+ # from UV_PYTHON (downloading it if needed) for each matrix entry.
43
+ UV_PYTHON: ${{ matrix.python-version }}
44
+ strategy:
45
+ fail-fast: false
46
+ # Test every supported Python on Linux; on the costlier Windows runners
47
+ # cover only the oldest and newest supported versions.
48
+ matrix:
49
+ os: [ubuntu-latest]
50
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
51
+ include:
52
+ - os: windows-latest
53
+ python-version: "3.10"
54
+ - os: windows-latest
55
+ python-version: "3.13"
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+ - name: Install uv
59
+ uses: astral-sh/setup-uv@v3
60
+ with:
61
+ version: ${{ env.UV_VERSION }}
62
+ enable-cache: true
63
+ - name: Sync (locked)
64
+ run: uv sync --locked
65
+ - name: Run tests
66
+ run: uv run pytest --cov=confargs --cov-report=xml
@@ -0,0 +1,35 @@
1
+ name: PR Title Check
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, edited, synchronize, reopened]
6
+
7
+ permissions:
8
+ pull-requests: read
9
+
10
+ jobs:
11
+ lint-pr-title:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: amannn/action-semantic-pull-request@v5
15
+ env:
16
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17
+ with:
18
+ types: |
19
+ feat
20
+ fix
21
+ docs
22
+ style
23
+ refactor
24
+ perf
25
+ test
26
+ build
27
+ ci
28
+ chore
29
+ revert
30
+ requireScope: false
31
+ subjectPattern: ^.+$
32
+ subjectPatternError: |
33
+ PR title must follow the Conventional Commits format:
34
+ type: description
35
+ Example: feat: add eager option support
@@ -0,0 +1,38 @@
1
+ name: Publish
2
+
3
+ # Automated releases are handled by release-please (.github/workflows/release-please.yml),
4
+ # which builds and publishes on release creation. This workflow is a manual
5
+ # fallback for publishing a release out-of-band.
6
+ on:
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v3
16
+ - name: Build sdist and wheel
17
+ run: uv build
18
+ - name: Upload artifacts
19
+ uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish:
25
+ needs: build
26
+ runs-on: ubuntu-latest
27
+ environment: pypi
28
+ permissions:
29
+ # Required for PyPI trusted publishing (OIDC); no API token needed.
30
+ id-token: write
31
+ steps:
32
+ - name: Download artifacts
33
+ uses: actions/download-artifact@v4
34
+ with:
35
+ name: dist
36
+ path: dist/
37
+ - name: Publish to PyPI
38
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,41 @@
1
+ name: Release Please
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ release-please:
14
+ runs-on: ubuntu-latest
15
+ outputs:
16
+ release_created: ${{ steps.release.outputs.release_created }}
17
+ tag_name: ${{ steps.release.outputs.tag_name }}
18
+ steps:
19
+ - uses: googleapis/release-please-action@v4
20
+ id: release
21
+ with:
22
+ config-file: release-please-config.json
23
+ manifest-file: .release-please-manifest.json
24
+
25
+ publish:
26
+ needs: release-please
27
+ if: ${{ needs.release-please.outputs.release_created == 'true' }}
28
+ runs-on: ubuntu-latest
29
+ environment: pypi
30
+ permissions:
31
+ # Required for PyPI trusted publishing (OIDC); no API token needed.
32
+ id-token: write
33
+ contents: read
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - name: Install uv
37
+ uses: astral-sh/setup-uv@v3
38
+ - name: Build sdist and wheel
39
+ run: uv build
40
+ - name: Publish to PyPI
41
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,26 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+
13
+ # uv: the lockfile is committed for reproducible installs and CI caching.
14
+
15
+ # Tooling caches
16
+ .mypy_cache/
17
+ .ruff_cache/
18
+ .pytest_cache/
19
+ .coverage
20
+ htmlcov/
21
+ coverage.xml
22
+
23
+ # Editors / OS
24
+ .idea/
25
+ .vscode/
26
+ .DS_Store
@@ -0,0 +1,28 @@
1
+ default_language_version:
2
+ python: python3
3
+
4
+ repos:
5
+ - repo: https://github.com/pre-commit/pre-commit-hooks
6
+ rev: v5.0.0
7
+ hooks:
8
+ - id: check-toml
9
+ - id: check-yaml
10
+ - id: end-of-file-fixer
11
+ - id: trailing-whitespace
12
+ - id: mixed-line-ending
13
+ args: [--fix=lf]
14
+
15
+ - repo: https://github.com/astral-sh/ruff-pre-commit
16
+ rev: v0.16.5
17
+ hooks:
18
+ - id: ruff
19
+ args: [--fix]
20
+ - id: ruff-format
21
+
22
+ - repo: https://github.com/pre-commit/mirrors-mypy
23
+ rev: v2.3.1
24
+ hooks:
25
+ - id: mypy
26
+ additional_dependencies: ["tomli>=2.0"]
27
+ pass_filenames: false
28
+ args: [--config-file=pyproject.toml]
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.0"
3
+ }
@@ -0,0 +1,86 @@
1
+ # Changelog
2
+
3
+ All notable changes to **confargs** are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ > **Pre-1.0 note:** while the version is `0.x.y`, the public API is still
9
+ > stabilising. Minor (`0.X.0`) releases may include breaking changes; patch
10
+ > (`0.x.Y`) releases are reserved for backwards-compatible fixes.
11
+
12
+ ## [0.2.0](https://github.com/MarketSquare/confargs/compare/v0.1.0...v0.2.0) (2026-08-28)
13
+
14
+
15
+ ### Features
16
+
17
+ * add argconfig-demo console entry-point ([d0249d8](https://github.com/MarketSquare/confargs/commit/d0249d83c0d37ab1e71d10ef41d4a9d79ad80b0a))
18
+ * add ConfigurationProcessor, Namespace and discovery controls ([8395145](https://github.com/MarketSquare/confargs/commit/83951450a7b9b81d6f47bb72cd2b0da64f61a373))
19
+ * add core option model and ArgConfig base ([a5e1c4d](https://github.com/MarketSquare/confargs/commit/a5e1c4d15c0bc6a4d1a4ce79a7cd69a12c6361a5))
20
+ * add eager options and argument-file expansion ([b6837bd](https://github.com/MarketSquare/confargs/commit/b6837bd4fda7c10efccb4bacd5fab420475ca7f9))
21
+ * add environment-variable source ([8b34439](https://github.com/MarketSquare/confargs/commit/8b34439eb153be00fd443eff0dcaba4ced96b4f2))
22
+ * add minimal command-line tokenizer ([e2c07bd](https://github.com/MarketSquare/confargs/commit/e2c07bd00c4ea8b3cb4f793b37b041dbce90ffd0))
23
+ * add TOML loading and config file discovery ([3e8171c](https://github.com/MarketSquare/confargs/commit/3e8171c18b3da3e49b658453fb7dc1a785ddfddf))
24
+ * add type resolution and value coercion ([3976797](https://github.com/MarketSquare/confargs/commit/397679794170b008feb256d320b72022069c0450))
25
+ * generate help text from docstrings ([13cd88c](https://github.com/MarketSquare/confargs/commit/13cd88c1738ebc480ef2575072140b431f70294a))
26
+ * support boolean flag negation with --no- prefix ([3d44e05](https://github.com/MarketSquare/confargs/commit/3d44e05746bfa050dbb436160b61c83564b21aab))
27
+ * validate config keys with strict_config mode ([f707858](https://github.com/MarketSquare/confargs/commit/f7078587200155f8122c725f9dc8b30fa4cec64e))
28
+
29
+
30
+ ### Documentation
31
+
32
+ * add publishing workflow, example and expanded README ([6f266d8](https://github.com/MarketSquare/confargs/commit/6f266d88cebdd66f55833eae7badecb0ab837cae))
33
+ * make examples/ a self-contained runnable example ([73a0948](https://github.com/MarketSquare/confargs/commit/73a094831a85cd0e86a00b570fd03e2f4cbc608d))
34
+
35
+
36
+ ### Build System
37
+
38
+ * single-source version and add CHANGELOG ([690efd9](https://github.com/MarketSquare/confargs/commit/690efd9b7017270a262ab13d75641891c73ca959))
39
+
40
+ ## [Unreleased]
41
+
42
+ ### Changed
43
+
44
+ - Renamed the distribution and import package from `argconfig` to **`confargs`**
45
+ (the `argconfig` name was already taken on PyPI). The `ArgConfig` base class
46
+ keeps its name.
47
+
48
+ ### Added
49
+
50
+ - Eager options (`@option(is_eager=True)`): resolved before every other source,
51
+ directly against `argv`. An eager option's method returns tokens that replace
52
+ its own arguments, enabling argument-file expansion.
53
+ - `confargs.split_argument_file` / `confargs.read_argument_file` helpers that
54
+ parse Robot Framework-style argument files (comment lines, `name value` and
55
+ `name=value` forms) into argv tokens, including nested argument files.
56
+
57
+ ## [0.1.0] - 2026-08-28
58
+
59
+ Initial development release.
60
+
61
+ ### Added
62
+
63
+ - Declarative option model: options are methods on an `ArgConfig` subclass
64
+ decorated with `@option`, receiving the raw value and returning the final one.
65
+ - `ConfigurationProcessor` that merges sources with precedence
66
+ **CLI > environment variables > nearest TOML > user-directory TOML > default**
67
+ and returns an immutable `Namespace` (attribute and item access).
68
+ - Minimal command-line tokenizer: long/short options, `--opt=value`, attached
69
+ and combined short flags, repeatable list options, `--` terminator and
70
+ positional collection.
71
+ - Boolean flag negation via `--no-<flag>`.
72
+ - Type coercion from strings and native TOML values (`str`, `int`, `float`,
73
+ `bool`, `list[...]`, `Optional`).
74
+ - TOML discovery that walks up to the `.git` project root, with `--config`,
75
+ `--no-config` and `--ignore-git` controls and a per-user config fallback.
76
+ - `strict_config` mode (default on) that rejects unknown or cli-only keys in a
77
+ config section.
78
+ - Environment-variable source via explicit `envvar=` or `auto_env_vars`.
79
+ - Help generation from class and option docstrings; built-in `--help`.
80
+ - `confargs-demo` console entry-point and runnable example.
81
+ - Tooling: uv project, ruff, mypy (strict), pytest, pre-commit, CI matrix
82
+ (Python 3.10-3.13 on Linux and Windows) and a PyPI trusted-publishing
83
+ workflow.
84
+
85
+ [Unreleased]: https://github.com/MarketSquare/confargs/compare/v0.1.0...HEAD
86
+ [0.1.0]: https://github.com/MarketSquare/confargs/releases/tag/v0.1.0
confargs-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 confargs contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.5
2
+ Name: confargs
3
+ Version: 0.2.0
4
+ Summary: Declarative CLI argument parser that merges command line, TOML config files, and environment variables.
5
+ Project-URL: Homepage, https://github.com/MarketSquare/confargs
6
+ Project-URL: Repository, https://github.com/MarketSquare/confargs
7
+ Project-URL: Issues, https://github.com/MarketSquare/confargs/issues
8
+ Author: confargs contributors
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: argparse,arguments,cli,configuration,toml
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # confargs
27
+
28
+ > ⚠️ Early development. APIs may change.
29
+
30
+ **confargs** is a small, declarative CLI argument parser for Python 3.10+ that
31
+ merges configuration from three sources into one result:
32
+
33
+ 1. **Command line** arguments (`--log out.html`, `-l NONE`)
34
+ 2. **Environment variables** (per-option or auto-generated)
35
+ 3. **TOML config files** (discovered by walking up from the current directory,
36
+ `pyproject.toml`-style)
37
+
38
+ You describe options as **methods** on a class. Each method receives the raw
39
+ value from whichever source supplied it, performs any parsing/validation you
40
+ like, and returns the final value. confargs handles discovery, precedence and
41
+ basic type coercion; your code owns the domain logic.
42
+
43
+ ```python
44
+ import confargs
45
+ from confargs import ArgConfig
46
+
47
+
48
+ class MyArgs(ArgConfig):
49
+ """My CLI tool.
50
+
51
+ Longer description shown in --help.
52
+ """
53
+
54
+ name = "mytool"
55
+
56
+ @confargs.option
57
+ def log(self, value: str | None = "log.html") -> str | None:
58
+ """HTML log file. Disable with the special value 'NONE'."""
59
+ if value == "NONE":
60
+ return None
61
+ return value
62
+
63
+ @confargs.option(names="--console/-c")
64
+ def console(self, value: str = "verbose") -> str:
65
+ choices = ["verbose", "dotted", "quiet", "none"]
66
+ if value not in choices:
67
+ raise confargs.OptionValueError(f"console must be one of {choices}")
68
+ return value
69
+
70
+
71
+ config = confargs.ConfigurationProcessor(MyArgs).process()
72
+ print(config.log, config.console)
73
+ ```
74
+
75
+ ## Precedence
76
+
77
+ Highest wins: **CLI > environment variables > nearest TOML > user-directory TOML > option default**.
78
+
79
+ ## Configuration sources
80
+
81
+ ### TOML files
82
+
83
+ Config is read from a table named after your tool. By default that is
84
+ `[tool.<name>]` (e.g. `[tool.mytool]`); override it with
85
+ `default_config_section = "tool.custom"`. The file names searched are set with
86
+ `config_names` (default `["pyproject.toml"]`). Both `dashed-keys` and
87
+ `snake_case_keys` are accepted.
88
+
89
+ ```toml
90
+ [tool.mytool]
91
+ log = "results.html"
92
+ console = "dotted"
93
+ tags = ["ci", "nightly"]
94
+ ```
95
+
96
+ **Discovery** walks up from the current directory looking for those files and
97
+ stops at the project root (a directory containing `.git`). If nothing is found,
98
+ a per-user config directory is consulted (`%APPDATA%\<name>` on Windows,
99
+ `$XDG_CONFIG_HOME/<name>` otherwise). Discovery is controlled by built-in,
100
+ CLI-only options:
101
+
102
+ - `--config PATH` — use only this file, skip discovery.
103
+ - `--no-config` — ignore config files entirely.
104
+ - `--ignore-git` — keep searching above the `.git` project root.
105
+
106
+ By default (`strict_config = True`) unknown keys — and any `cli_only` option —
107
+ found in the config section raise an error, which catches typos early. Set
108
+ `strict_config = False` on your class to silently ignore them instead.
109
+
110
+ ### Environment variables
111
+
112
+ Set a name per option with `@option(envvar="MYTOOL_LOG")`, or enable
113
+ `auto_env_vars = True` on the class to expose every non-`cli_only` option as
114
+ `<NAME>_<OPTION>` (e.g. `MYTOOL_CONSOLE`).
115
+
116
+ ### CLI-only options
117
+
118
+ Options marked `@option(cli_only=True)` are never read from TOML or the
119
+ environment — use this for switches that control the tool run itself (the
120
+ built-in discovery options above are defined this way).
121
+
122
+ ## Options in depth
123
+
124
+ - Long names come from the method name (`dry_run` → `--dry-run`); a short name
125
+ is derived from the first letter when it is still free. Override with
126
+ `names="--console/-c"`.
127
+ - The value type is taken from the `value` parameter annotation. `bool` becomes
128
+ a flag; `list[...]` becomes a repeatable option; `int`/`float`/`str` are
129
+ coerced from strings. Your method receives the coerced value and returns the
130
+ final one — raise `confargs.OptionValueError` to reject it.
131
+ - Boolean options can be negated on the command line: `--verbose` sets it to
132
+ `True`, `--no-verbose` sets it to `False`.
133
+
134
+ ### Eager options and argument files
135
+
136
+ Mark an option `is_eager=True` to resolve it *before* every other source,
137
+ directly against `argv`. The method's return value — an iterable of tokens or
138
+ `None` — replaces the option's own arguments, so it can inject more options.
139
+ This is how an `--argumentfile` option expands a file (Robot Framework style)
140
+ into extra arguments, including nested argument files:
141
+
142
+ ```python
143
+ from confargs import ArgConfig, option, read_argument_file
144
+
145
+
146
+ class Args(ArgConfig):
147
+ @option(names="--argumentfile/-A", cli_only=True, is_eager=True)
148
+ def argumentfile(self, value: str | None = None) -> list[str] | None:
149
+ return read_argument_file(value) if value else None
150
+ ```
151
+
152
+ `ConfigurationProcessor(Args, argv=[...])` accepts an explicit argument list;
153
+ when omitted it falls back to `sys.argv[1:]`.
154
+
155
+ ## Example
156
+
157
+ A complete, self-contained example lives in [`examples/demo.py`](examples/demo.py)
158
+ (with a sample [`examples/example.args`](examples/example.args) and
159
+ [`examples/README.md`](examples/README.md)). It's a single copy-pasteable file
160
+ showing value options, `--no-` flag negation, environment variables and an
161
+ eager `--argumentfile`. Run it from a checkout without installing anything:
162
+
163
+ ```bash
164
+ uv run python examples/demo.py --who Ada --repeat 3
165
+ uv run python examples/demo.py -A examples/example.args
166
+ uv run python examples/demo.py --help
167
+ ```
168
+
169
+ Separately, the packaged [`confargs.demo`](src/confargs/demo.py) module is
170
+ installed as the `confargs-demo` console script via `[project.scripts]`:
171
+
172
+ ```bash
173
+ uv run confargs-demo --console quiet --retries 5
174
+ uv run confargs-demo --help
175
+ ```
176
+
177
+ To ship your own tool, point a console script at a `main()` that runs the
178
+ processor, for example in `pyproject.toml`:
179
+
180
+ ```toml
181
+ [project.scripts]
182
+ mytool = "mytool.cli:main"
183
+ ```
184
+
185
+ ## Development
186
+
187
+ This project uses [uv](https://docs.astral.sh/uv/).
188
+
189
+ ```bash
190
+ uv sync # create the environment
191
+ uv run pytest # run the tests
192
+ uv run ruff check # lint
193
+ uv run ruff format # format
194
+ uv run mypy # type-check
195
+ pre-commit install # enable git hooks
196
+ ```
197
+
198
+ ## Publishing
199
+
200
+ Releases are published to PyPI by `.github/workflows/publish.yml` when a GitHub
201
+ Release is published. It uses [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/)
202
+ (OIDC), so no API token is stored in the repository — configure the project as a
203
+ trusted publisher on PyPI (workflow `publish.yml`, environment `pypi`) once.
204
+
205
+ ## Versioning
206
+
207
+ confargs follows [Semantic Versioning](https://semver.org/). The version is
208
+ single-sourced from `__version__` in `src/confargs/__init__.py` (hatchling reads
209
+ it at build time). While the project is `0.x.y` the API is still stabilising, so
210
+ minor releases may include breaking changes. Notable changes are recorded in
211
+ [`CHANGELOG.md`](CHANGELOG.md).
212
+
213
+ Releases are automated with
214
+ [release-please](https://github.com/googleapis/release-please): merging
215
+ [Conventional Commits](https://www.conventionalcommits.org/) to `main` keeps an
216
+ open release PR that bumps `__version__`, updates the changelog and, once merged,
217
+ tags the release and publishes to PyPI. Pre-1.0, breaking changes bump the minor
218
+ version (`bump-minor-pre-major`).
219
+
220
+ ## License
221
+
222
+ MIT