dataclass-args 1.2.2__tar.gz → 1.4.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.
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/PKG-INFO +413 -2
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/README.md +412 -1
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args/__init__.py +36 -1
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args/annotations.py +451 -107
- dataclass_args-1.4.0/dataclass_args/append_action.py +48 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args/builder.py +652 -9
- dataclass_args-1.4.0/dataclass_args/formatter.py +45 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args.egg-info/PKG-INFO +413 -2
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args.egg-info/SOURCES.txt +4 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/pyproject.toml +2 -2
- dataclass_args-1.4.0/tests/test_cli_append.py +841 -0
- dataclass_args-1.4.0/tests/test_cli_nested.py +765 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/LICENSE +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args/exceptions.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args/file_loading.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args/utils.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args.egg-info/dependency_links.txt +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args.egg-info/requires.txt +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/dataclass_args.egg-info/top_level.txt +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/setup.cfg +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_annotations.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_basic.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_boolean_base_configs.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_boolean_flags.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_builder_advanced.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_cli_choices.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_cli_short.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_combine_annotations.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_config_merging_simple.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_description.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_file_loading.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_positional.py +0 -0
- {dataclass_args-1.2.2 → dataclass_args-1.4.0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dataclass-args
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Zero-boilerplate CLI generation from Python dataclasses with advanced type support and file loading
|
|
5
5
|
Author-email: Martin Bartlett <martin.j.bartlett@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -52,7 +52,8 @@ Dynamic: license-file
|
|
|
52
52
|
Generate command-line interfaces from Python dataclasses.
|
|
53
53
|
|
|
54
54
|
[](https://github.com/bassmanitram/dataclass-args/actions/workflows/test.yml)
|
|
55
|
-
[](https://github.com/bassmanitram/dataclass-args/actions/workflows/lint.yml)
|
|
56
|
+
[](https://github.com/bassmanitram/dataclass-args/actions/workflows/quality.yml)
|
|
56
57
|
[](https://github.com/bassmanitram/dataclass-args/actions/workflows/examples.yml)
|
|
57
58
|
[](https://www.python.org/downloads/)
|
|
58
59
|
[](https://pypi.org/project/dataclass-args/)
|
|
@@ -62,10 +63,12 @@ Generate command-line interfaces from Python dataclasses.
|
|
|
62
63
|
|
|
63
64
|
- **[Automatic CLI Generation](#quick-start)** - Generate CLI from dataclass definitions
|
|
64
65
|
- **[Type-Safe Parsing](#type-support)** - Type-aware argument parsing for standard Python types
|
|
66
|
+
- **[Nested Dataclasses](#nested-dataclasses)** - Organize configs hierarchically with automatic flattening
|
|
65
67
|
- **[Positional Arguments](#positional-arguments)** - Support for positional args with `cli_positional()`
|
|
66
68
|
- **[Short Options](#short-options)** - Concise `-n` flags in addition to `--name`
|
|
67
69
|
- **[Boolean Flags](#boolean-flags)** - Proper `--flag` and `--no-flag` boolean handling
|
|
68
70
|
- **[Value Validation](#value-choices)** - Restrict values with `cli_choices()`
|
|
71
|
+
- **[Repeatable Options](#repeatable-options)** - Allow options to be specified multiple times with `cli_append()`
|
|
69
72
|
- **[File Loading](#file-loadable-parameters)** - Load parameters from files using `@filename` syntax
|
|
70
73
|
- **[Config Merging](#configuration-merging)** - Combine configuration sources with hierarchical overrides
|
|
71
74
|
- **[Flexible Types](#type-support)** - Support for `List`, `Dict`, `Optional`, and custom types
|
|
@@ -209,6 +212,108 @@ error: argument --environment: invalid choice: 'invalid' (choose from 'dev', 'st
|
|
|
209
212
|
|
|
210
213
|
|
|
211
214
|
|
|
215
|
+
### Repeatable Options
|
|
216
|
+
|
|
217
|
+
Use `cli_append()` to allow an option to be specified multiple times, with each occurrence collecting its own arguments:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from dataclass_args import cli_append
|
|
221
|
+
|
|
222
|
+
@dataclass
|
|
223
|
+
class Config:
|
|
224
|
+
# Simple tags: each -t adds one value
|
|
225
|
+
tags: List[str] = combine_annotations(
|
|
226
|
+
cli_short('t'),
|
|
227
|
+
cli_append(),
|
|
228
|
+
cli_help("Add a tag"),
|
|
229
|
+
default_factory=list
|
|
230
|
+
)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# Each -t occurrence accumulates
|
|
235
|
+
$ python app.py -t python -t cli -t tool
|
|
236
|
+
# Result: ['python', 'cli', 'tool']
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### Repeatable with Multiple Arguments
|
|
240
|
+
|
|
241
|
+
Each occurrence can take multiple arguments using `nargs`:
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
@dataclass
|
|
245
|
+
class DockerConfig:
|
|
246
|
+
# Each -p takes exactly 2 arguments (HOST CONTAINER)
|
|
247
|
+
ports: List[List[str]] = combine_annotations(
|
|
248
|
+
cli_short('p'),
|
|
249
|
+
cli_append(nargs=2),
|
|
250
|
+
cli_help("Port mapping (HOST CONTAINER)"),
|
|
251
|
+
default_factory=list
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# Each -v takes exactly 2 arguments (SOURCE TARGET)
|
|
255
|
+
volumes: List[List[str]] = combine_annotations(
|
|
256
|
+
cli_short('v'),
|
|
257
|
+
cli_append(nargs=2),
|
|
258
|
+
cli_help("Volume mount (SOURCE TARGET)"),
|
|
259
|
+
default_factory=list
|
|
260
|
+
)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
$ python docker.py -p 8080 80 -p 8443 443 -v /host/data /container/data
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Variable Arguments with Validation
|
|
268
|
+
|
|
269
|
+
Use `min_args` and `max_args` for flexible argument counts with automatic validation:
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
@dataclass
|
|
273
|
+
class UploadConfig:
|
|
274
|
+
files: List[List[str]] = combine_annotations(
|
|
275
|
+
cli_short('f'),
|
|
276
|
+
cli_append(min_args=1, max_args=2, metavar="FILE [MIMETYPE]"),
|
|
277
|
+
cli_help("File with optional MIME type"),
|
|
278
|
+
default_factory=list
|
|
279
|
+
)
|
|
280
|
+
# No __post_init__ needed - validation is automatic!
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
# Mix files with and without MIME types
|
|
285
|
+
$ python upload.py -f doc.pdf application/pdf -f image.png -f video.mp4 video/mp4
|
|
286
|
+
# Result: [['doc.pdf', 'application/pdf'], ['image.png'], ['video.mp4', 'video/mp4']]
|
|
287
|
+
|
|
288
|
+
# Validation catches errors automatically
|
|
289
|
+
$ python upload.py -f file1 arg2 arg3 arg4
|
|
290
|
+
# Error: Expected at most 2 argument(s), got 4
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Clean help display:**
|
|
294
|
+
```
|
|
295
|
+
-f FILE [MIMETYPE], --files FILE [MIMETYPE]
|
|
296
|
+
File with optional MIME type (can be repeated, 1-2 args each)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Parameters:**
|
|
300
|
+
- `min_args`: Minimum arguments per occurrence
|
|
301
|
+
- `max_args`: Maximum arguments per occurrence
|
|
302
|
+
- Must be used together (both or neither)
|
|
303
|
+
- Mutually exclusive with `nargs`
|
|
304
|
+
|
|
305
|
+
**nargs Options:**
|
|
306
|
+
- `None` - One value per occurrence → `List[T]`
|
|
307
|
+
- `int` (e.g., `2`) - Exact count per occurrence → `List[List[T]]`
|
|
308
|
+
- `'+'` - One or more per occurrence → `List[List[T]]`
|
|
309
|
+
- `'*'` - Zero or more per occurrence → `List[List[T]]`
|
|
310
|
+
|
|
311
|
+
**Use Cases:**
|
|
312
|
+
- Docker-style options: `-p 8080:80 -p 8443:443 -v /host:/container -e KEY=value`
|
|
313
|
+
- File operations: `-f file1 type1 -f file2 -f file3 type3`
|
|
314
|
+
- Server pools: `-s host1 port1 -s host2 port2`
|
|
315
|
+
- Build systems: `-I dir1 -I dir2 --define KEY VAL`
|
|
316
|
+
|
|
212
317
|
### Positional Arguments
|
|
213
318
|
|
|
214
319
|
Add positional arguments that don't require `--` prefixes:
|
|
@@ -475,6 +580,284 @@ $ python app.py --name "MyApp" --system-prompt "@~/prompts/assistant.txt"
|
|
|
475
580
|
- `@/absolute/path` → Used as-is
|
|
476
581
|
- `@relative/path` → Relative to current working directory
|
|
477
582
|
|
|
583
|
+
### Nested Dataclasses
|
|
584
|
+
|
|
585
|
+
Organize complex configurations into nested dataclasses with automatic CLI flattening. Use `cli_nested()` to create hierarchical configs that are exposed as flat CLI arguments with customizable prefixes.
|
|
586
|
+
|
|
587
|
+
```python
|
|
588
|
+
from dataclass_args import cli_nested
|
|
589
|
+
|
|
590
|
+
@dataclass
|
|
591
|
+
class DatabaseConfig:
|
|
592
|
+
host: str = "localhost"
|
|
593
|
+
port: int = 5432
|
|
594
|
+
username: str = "admin"
|
|
595
|
+
password: str = "secret"
|
|
596
|
+
|
|
597
|
+
@dataclass
|
|
598
|
+
class CacheConfig:
|
|
599
|
+
host: str = "localhost"
|
|
600
|
+
port: int = 6379
|
|
601
|
+
ttl: int = 3600
|
|
602
|
+
|
|
603
|
+
@dataclass
|
|
604
|
+
class AppConfig:
|
|
605
|
+
app_name: str = "myapp"
|
|
606
|
+
debug: bool = False
|
|
607
|
+
|
|
608
|
+
# Nested with custom prefix
|
|
609
|
+
database: DatabaseConfig = cli_nested(prefix="db", default_factory=DatabaseConfig)
|
|
610
|
+
|
|
611
|
+
# Nested with custom prefix
|
|
612
|
+
cache: CacheConfig = cli_nested(prefix="cache", default_factory=CacheConfig)
|
|
613
|
+
|
|
614
|
+
config = build_config(AppConfig)
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
```bash
|
|
618
|
+
# All nested fields are flattened with prefixes
|
|
619
|
+
$ python app.py \
|
|
620
|
+
--app-name "MyApp" \
|
|
621
|
+
--db-host prod-db.example.com \
|
|
622
|
+
--db-port 5432 \
|
|
623
|
+
--db-username dbuser \
|
|
624
|
+
--cache-host redis.example.com \
|
|
625
|
+
--cache-ttl 7200
|
|
626
|
+
|
|
627
|
+
# Help shows all flattened fields
|
|
628
|
+
$ python app.py --help
|
|
629
|
+
options:
|
|
630
|
+
--app-name APP_NAME
|
|
631
|
+
--debug / --no-debug
|
|
632
|
+
--db-host DB_HOST
|
|
633
|
+
--db-port DB_PORT
|
|
634
|
+
--db-username DB_USERNAME
|
|
635
|
+
--db-password DB_PASSWORD
|
|
636
|
+
--cache-host CACHE_HOST
|
|
637
|
+
--cache-port CACHE_PORT
|
|
638
|
+
--cache-ttl CACHE_TTL
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
#### Prefix Modes
|
|
642
|
+
|
|
643
|
+
**Custom Prefix:**
|
|
644
|
+
```python
|
|
645
|
+
database: DatabaseConfig = cli_nested(prefix="db", default_factory=DatabaseConfig)
|
|
646
|
+
# CLI: --db-host, --db-port, --db-username
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
**No Prefix (Complete Flattening):**
|
|
650
|
+
```python
|
|
651
|
+
credentials: Credentials = cli_nested(prefix="", default_factory=Credentials)
|
|
652
|
+
# CLI: --username, --password (no prefix)
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
**Auto Prefix (Uses Field Name):**
|
|
656
|
+
```python
|
|
657
|
+
database: DatabaseConfig = cli_nested(default_factory=DatabaseConfig)
|
|
658
|
+
# CLI: --database-host, --database-port (field name as prefix)
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
#### Short Options with Nested Fields
|
|
662
|
+
|
|
663
|
+
Short options behave differently based on the prefix:
|
|
664
|
+
|
|
665
|
+
**With Prefix** → Short options are **ignored** (prevents conflicts):
|
|
666
|
+
```python
|
|
667
|
+
@dataclass
|
|
668
|
+
class ServerConfig:
|
|
669
|
+
host: str = cli_short("h", default="localhost")
|
|
670
|
+
port: int = cli_short("p", default=8080)
|
|
671
|
+
|
|
672
|
+
@dataclass
|
|
673
|
+
class Config:
|
|
674
|
+
server: ServerConfig = cli_nested(prefix="srv", default_factory=ServerConfig)
|
|
675
|
+
|
|
676
|
+
# CLI: --srv-host, --srv-port (no -h or -p for nested fields)
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
**No Prefix** → Short options are **enabled**:
|
|
680
|
+
```python
|
|
681
|
+
@dataclass
|
|
682
|
+
class Credentials:
|
|
683
|
+
username: str = cli_short("u", default="admin")
|
|
684
|
+
password: str = cli_short("p", default="secret")
|
|
685
|
+
|
|
686
|
+
@dataclass
|
|
687
|
+
class Config:
|
|
688
|
+
app_name: str = cli_short("a", default="app")
|
|
689
|
+
creds: Credentials = cli_nested(prefix="", default_factory=Credentials)
|
|
690
|
+
|
|
691
|
+
# CLI: -a, -u, -p all work! (completely flattened)
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
```bash
|
|
695
|
+
# Use short options for all fields
|
|
696
|
+
$ python app.py -a MyApp -u john -p secretpass
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
#### Collision Detection
|
|
700
|
+
|
|
701
|
+
Automatic collision detection prevents field name and short option conflicts:
|
|
702
|
+
|
|
703
|
+
**Field Name Collision:**
|
|
704
|
+
```python
|
|
705
|
+
@dataclass
|
|
706
|
+
class Nested:
|
|
707
|
+
name: str = "nested"
|
|
708
|
+
|
|
709
|
+
@dataclass
|
|
710
|
+
class Config:
|
|
711
|
+
name: str = "parent"
|
|
712
|
+
nested: Nested = cli_nested(prefix="", default_factory=Nested)
|
|
713
|
+
|
|
714
|
+
# ERROR: Field name collision detected:
|
|
715
|
+
# --name
|
|
716
|
+
# - name
|
|
717
|
+
# - nested.name
|
|
718
|
+
# Solution: Add prefix to nested field or rename
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
**Short Option Collision:**
|
|
722
|
+
```python
|
|
723
|
+
@dataclass
|
|
724
|
+
class Nested:
|
|
725
|
+
host: str = cli_short("h", default="nested-host")
|
|
726
|
+
|
|
727
|
+
@dataclass
|
|
728
|
+
class Config:
|
|
729
|
+
help_text: str = cli_short("h", default="help")
|
|
730
|
+
nested: Nested = cli_nested(prefix="", default_factory=Nested)
|
|
731
|
+
|
|
732
|
+
# ERROR: Short option collision detected:
|
|
733
|
+
# -h
|
|
734
|
+
# - help_text (--help-text)
|
|
735
|
+
# - nested.host (--host)
|
|
736
|
+
# Solution: Use different short options or add prefix
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
#### Config File Merging with Nested Fields
|
|
740
|
+
|
|
741
|
+
Nested dataclasses work seamlessly with config files:
|
|
742
|
+
|
|
743
|
+
**config.yaml:**
|
|
744
|
+
```yaml
|
|
745
|
+
app_name: "ProductionApp"
|
|
746
|
+
database:
|
|
747
|
+
host: "prod-db.example.com"
|
|
748
|
+
port: 5432
|
|
749
|
+
username: "prod_user"
|
|
750
|
+
cache:
|
|
751
|
+
host: "redis.example.com"
|
|
752
|
+
ttl: 7200
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
```python
|
|
756
|
+
config = build_config(AppConfig, args=[
|
|
757
|
+
'--config', 'config.yaml',
|
|
758
|
+
'--db-password', 'secret', # Override specific nested field
|
|
759
|
+
'--cache-ttl', '3600' # Override another nested field
|
|
760
|
+
])
|
|
761
|
+
|
|
762
|
+
# Result:
|
|
763
|
+
# - app_name: "ProductionApp" (from file)
|
|
764
|
+
# - database.host: "prod-db.example.com" (from file)
|
|
765
|
+
# - database.password: "secret" (CLI override)
|
|
766
|
+
# - cache.host: "redis.example.com" (from file)
|
|
767
|
+
# - cache.ttl: 3600 (CLI override)
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
#### Real-World Example
|
|
771
|
+
|
|
772
|
+
```python
|
|
773
|
+
from dataclasses import dataclass
|
|
774
|
+
from dataclass_args import build_config, cli_nested, cli_short, cli_help, combine_annotations
|
|
775
|
+
|
|
776
|
+
@dataclass
|
|
777
|
+
class DatabaseConfig:
|
|
778
|
+
"""Database connection settings."""
|
|
779
|
+
host: str = cli_help("Database hostname", default="localhost")
|
|
780
|
+
port: int = cli_help("Database port", default=5432)
|
|
781
|
+
database: str = cli_help("Database name", default="mydb")
|
|
782
|
+
username: str = cli_help("Database username", default="admin")
|
|
783
|
+
password: str = cli_help("Database password", default="")
|
|
784
|
+
|
|
785
|
+
@dataclass
|
|
786
|
+
class LoggingConfig:
|
|
787
|
+
"""Logging configuration."""
|
|
788
|
+
level: str = combine_annotations(
|
|
789
|
+
cli_help("Log level"),
|
|
790
|
+
cli_choices(["DEBUG", "INFO", "WARNING", "ERROR"]),
|
|
791
|
+
default="INFO"
|
|
792
|
+
)
|
|
793
|
+
file: str = cli_help("Log file path", default="app.log")
|
|
794
|
+
format: str = cli_help("Log format string", default="%(levelname)s: %(message)s")
|
|
795
|
+
|
|
796
|
+
@dataclass
|
|
797
|
+
class AppConfig:
|
|
798
|
+
"""Application configuration with nested sections."""
|
|
799
|
+
|
|
800
|
+
# Top-level settings
|
|
801
|
+
app_name: str = combine_annotations(
|
|
802
|
+
cli_short("n"),
|
|
803
|
+
cli_help("Application name"),
|
|
804
|
+
default="myapp"
|
|
805
|
+
)
|
|
806
|
+
|
|
807
|
+
debug: bool = combine_annotations(
|
|
808
|
+
cli_short("d"),
|
|
809
|
+
cli_help("Enable debug mode"),
|
|
810
|
+
default=False
|
|
811
|
+
)
|
|
812
|
+
|
|
813
|
+
workers: int = combine_annotations(
|
|
814
|
+
cli_short("w"),
|
|
815
|
+
cli_help("Number of worker threads"),
|
|
816
|
+
default=4
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
# Nested configurations
|
|
820
|
+
database: DatabaseConfig = cli_nested(
|
|
821
|
+
prefix="db",
|
|
822
|
+
default_factory=DatabaseConfig
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
logging: LoggingConfig = cli_nested(
|
|
826
|
+
prefix="log",
|
|
827
|
+
default_factory=LoggingConfig
|
|
828
|
+
)
|
|
829
|
+
|
|
830
|
+
if __name__ == "__main__":
|
|
831
|
+
config = build_config(AppConfig)
|
|
832
|
+
|
|
833
|
+
print(f"App: {config.app_name}")
|
|
834
|
+
print(f"Database: {config.database.host}:{config.database.port}/{config.database.database}")
|
|
835
|
+
print(f"Logging: {config.logging.level} -> {config.logging.file}")
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
```bash
|
|
839
|
+
# Production deployment with nested config
|
|
840
|
+
$ python app.py \
|
|
841
|
+
-n "ProductionApp" \
|
|
842
|
+
-w 16 \
|
|
843
|
+
--db-host prod-db.example.com \
|
|
844
|
+
--db-database prod_db \
|
|
845
|
+
--db-username prod_user \
|
|
846
|
+
--log-level WARNING \
|
|
847
|
+
--log-file /var/log/app.log
|
|
848
|
+
|
|
849
|
+
# Or load base config and override specific fields
|
|
850
|
+
$ python app.py \
|
|
851
|
+
--config production.yaml \
|
|
852
|
+
--db-password "${DB_PASSWORD}" \
|
|
853
|
+
--log-level DEBUG
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
**See also:**
|
|
857
|
+
- [`examples/nested_dataclass.py`](examples/nested_dataclass.py) - Complete nested dataclass example
|
|
858
|
+
- [`examples/nested_short_options.py`](examples/nested_short_options.py) - Short options with nested fields
|
|
859
|
+
|
|
860
|
+
|
|
478
861
|
# config.yaml
|
|
479
862
|
name: "DefaultApp"
|
|
480
863
|
count: 100
|
|
@@ -830,6 +1213,30 @@ input: str = combine_annotations(
|
|
|
830
1213
|
|
|
831
1214
|
**Important:** At most one positional can use `nargs='*'` or `'+'`, and it must be the last positional.
|
|
832
1215
|
|
|
1216
|
+
#### `cli_nested(prefix=None, default_factory=None, **kwargs)`
|
|
1217
|
+
|
|
1218
|
+
Mark a dataclass field as a nested configuration that should be flattened into CLI arguments.
|
|
1219
|
+
|
|
1220
|
+
```python
|
|
1221
|
+
# Custom prefix
|
|
1222
|
+
database: DatabaseConfig = cli_nested(prefix="db", default_factory=DatabaseConfig)
|
|
1223
|
+
# CLI: --db-host, --db-port
|
|
1224
|
+
|
|
1225
|
+
# No prefix (complete flattening)
|
|
1226
|
+
credentials: Credentials = cli_nested(prefix="", default_factory=Credentials)
|
|
1227
|
+
# CLI: --username, --password
|
|
1228
|
+
|
|
1229
|
+
# Auto prefix (uses field name)
|
|
1230
|
+
logging: LogConfig = cli_nested(default_factory=LogConfig)
|
|
1231
|
+
# CLI: --logging-level, --logging-file
|
|
1232
|
+
```
|
|
1233
|
+
|
|
1234
|
+
**Important:**
|
|
1235
|
+
- Fields with prefixes don't support short options
|
|
1236
|
+
- Fields without prefix (prefix="") support short options
|
|
1237
|
+
- Automatic collision detection for field names and short options
|
|
1238
|
+
- Works seamlessly with config file merging
|
|
1239
|
+
|
|
833
1240
|
#### `cli_exclude(**kwargs)`
|
|
834
1241
|
|
|
835
1242
|
Exclude fields from CLI argument generation.
|
|
@@ -1071,6 +1478,7 @@ from dataclass_args import (
|
|
|
1071
1478
|
cli_positional, # Positional args
|
|
1072
1479
|
cli_choices, # Value validation
|
|
1073
1480
|
cli_help, # Custom help text
|
|
1481
|
+
cli_nested, # Nested dataclasses
|
|
1074
1482
|
cli_exclude, # Hide from CLI
|
|
1075
1483
|
cli_file_loadable, # @file loading
|
|
1076
1484
|
combine_annotations, # Combine features
|
|
@@ -1107,6 +1515,9 @@ class Config:
|
|
|
1107
1515
|
# File-loadable
|
|
1108
1516
|
config_text: str = cli_file_loadable(default="")
|
|
1109
1517
|
|
|
1518
|
+
# Nested dataclass
|
|
1519
|
+
database: DatabaseConfig = cli_nested(prefix="db", default_factory=DatabaseConfig)
|
|
1520
|
+
|
|
1110
1521
|
# Build and use
|
|
1111
1522
|
config = build_config(Config)
|
|
1112
1523
|
```
|