simpleArgParser 0.2.1__tar.gz → 0.2.3__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 (37) hide show
  1. simpleargparser-0.2.3/PKG-INFO +417 -0
  2. simpleargparser-0.2.3/README.md +406 -0
  3. simpleargparser-0.2.3/pyproject.toml +24 -0
  4. simpleargparser-0.2.3/simpleArgParser/__init__.py +12 -0
  5. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/simpleArgParser/s_argparse.py +467 -40
  6. simpleargparser-0.2.3/simpleArgParser.egg-info/PKG-INFO +417 -0
  7. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/simpleArgParser.egg-info/SOURCES.txt +3 -2
  8. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/simpleArgParser.egg-info/top_level.txt +0 -1
  9. simpleargparser-0.2.3/tests/test_nested_defaults.py +275 -0
  10. simpleargparser-0.2.3/tests/test_subparser.py +639 -0
  11. simpleargparser-0.2.1/PKG-INFO +0 -51
  12. simpleargparser-0.2.1/README.md +0 -31
  13. simpleargparser-0.2.1/setup.py +0 -22
  14. simpleargparser-0.2.1/simpleArgParser/__init__.py +0 -10
  15. simpleargparser-0.2.1/simpleArgParser.egg-info/PKG-INFO +0 -51
  16. simpleargparser-0.2.1/tests/__init__.py +0 -1
  17. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/setup.cfg +0 -0
  18. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/simpleArgParser.egg-info/dependency_links.txt +0 -0
  19. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_alias_map.py +0 -0
  20. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_bool_converter.py +0 -0
  21. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_convert_type.py +0 -0
  22. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_convert_value.py +0 -0
  23. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_deep_merge.py +0 -0
  24. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_dict_utils.py +0 -0
  25. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_doc_help.py +0 -0
  26. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_enum.py +0 -0
  27. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_extract_field_comments.py +0 -0
  28. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_fill_defaults.py +0 -0
  29. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_from_dict.py +0 -0
  30. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_inheritance.py +0 -0
  31. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_nest_namespace.py +0 -0
  32. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_parse_args.py +0 -0
  33. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_pass_in_special_char.py +0 -0
  34. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_recursive_process.py +0 -0
  35. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_serialization.py +0 -0
  36. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_special_load_marker.py +0 -0
  37. {simpleargparser-0.2.1 → simpleargparser-0.2.3}/tests/test_to_json.py +0 -0
@@ -0,0 +1,417 @@
1
+ Metadata-Version: 2.4
2
+ Name: simpleArgParser
3
+ Version: 0.2.3
4
+ Summary: A simple typed argument parser using dataclasses and type hints. This project is largely generated by LLMs.
5
+ Author-email: raibows <raibows@hotmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Raibows/SimpleArgParser
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+
12
+ # SimpleArgParser
13
+
14
+ A simple typed argument parser for Python built on dataclasses. Define your config as a class, get CLI parsing, validation, and serialization.
15
+
16
+ This project is largely generated by LLMs.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install -U simpleArgParser
22
+ uv add simpleArgParser
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```python
28
+ from dataclasses import dataclass
29
+ from simpleArgParser import parse_args
30
+
31
+ @dataclass
32
+ class Config:
33
+ name: str # required (no default)
34
+ epochs: int = 10 # optional with default
35
+ lr: float = 0.001
36
+
37
+ config = parse_args(Config)
38
+ ```
39
+
40
+ ```bash
41
+ python main.py --name experiment1 --epochs 20
42
+ ```
43
+
44
+ ## Features
45
+
46
+ ### Required and Optional Arguments
47
+
48
+ Fields without defaults are required. Fields with defaults are optional.
49
+
50
+ ```python
51
+ @dataclass
52
+ class Config:
53
+ required_field: str # must be provided
54
+ optional_field: int = 42 # has a default
55
+ optional_none: float | None = None # optional, defaults to None
56
+ ```
57
+
58
+ ```bash
59
+ python main.py --required_field hello
60
+ python main.py --required_field hello --optional_none 3.14
61
+ python main.py --required_field hello --optional_none none # explicitly set to None
62
+ ```
63
+
64
+ ### Bool Arguments
65
+
66
+ Accepts `true/false`, `yes/no`, `t/f`, `y/n`, `1/0` (case-insensitive).
67
+
68
+ ```python
69
+ @dataclass
70
+ class Config:
71
+ verbose: bool = False
72
+ ```
73
+
74
+ ```bash
75
+ python main.py --verbose true
76
+ python main.py --verbose yes
77
+ ```
78
+
79
+ ### Enum Arguments
80
+
81
+ Pass in the enum member **name**. Choices are displayed in `--help`.
82
+
83
+ ```python
84
+ import enum
85
+
86
+ class Mode(enum.Enum):
87
+ train = "train"
88
+ eval = "eval"
89
+
90
+ @dataclass
91
+ class Config:
92
+ mode: Mode = Mode.train
93
+ ```
94
+
95
+ ```bash
96
+ python main.py --mode eval
97
+ ```
98
+
99
+ ### List Arguments
100
+
101
+ Comma-separated values. Supports `none` to pass `None`.
102
+
103
+ ```python
104
+ @dataclass
105
+ class Config:
106
+ devices: list[int] | None = None
107
+ ```
108
+
109
+ ```bash
110
+ python main.py --devices 0,1,2
111
+ python main.py --devices none
112
+ ```
113
+
114
+ ### Nested Dataclasses
115
+
116
+ Nest dataclasses as fields. Arguments use dot-separated names. Unique field names get short aliases automatically.
117
+
118
+ ```python
119
+ @dataclass
120
+ class OptimizerConfig:
121
+ lr: float = 0.001
122
+ weight_decay: float = 0.01
123
+
124
+ @dataclass
125
+ class Config:
126
+ name: str = "exp"
127
+ optimizer: OptimizerConfig = field(default_factory=OptimizerConfig)
128
+ ```
129
+
130
+ ```bash
131
+ # full path always works
132
+ python main.py --optimizer.lr 0.01
133
+
134
+ # short alias works when the name is unique across all fields
135
+ python main.py --lr 0.01 --weight_decay 0.05
136
+ ```
137
+
138
+ ### Inheritance
139
+
140
+ Child dataclasses inherit parent fields. You can override defaults.
141
+
142
+ ```python
143
+ @dataclass
144
+ class BaseConfig:
145
+ seed: int = 42
146
+ verbose: bool = False
147
+
148
+ @dataclass
149
+ class TrainConfig(BaseConfig):
150
+ lr: float = 0.001
151
+ verbose: bool = True # override parent default
152
+ ```
153
+
154
+ ```bash
155
+ python main.py --seed 123 --lr 0.01
156
+ ```
157
+
158
+ ### Comments as Help Text
159
+
160
+ Comments above or inline with fields are extracted and shown in `--help`.
161
+
162
+ ```python
163
+ @dataclass
164
+ class Config:
165
+ # Learning rate for the optimizer
166
+ lr: float = 0.001
167
+ epochs: int = 10 # number of training epochs
168
+ ```
169
+
170
+ ```bash
171
+ python main.py --help
172
+ # shows:
173
+ # --lr (type: float) (default: 0.001) Learning rate for the optimizer
174
+ # --epochs (type: int) (default: 10) number of training epochs
175
+ ```
176
+
177
+ ### JSON Config Loading
178
+
179
+ Use `SpecialLoadMarker` to load defaults from a JSON file. Priority: command line > pass_in > JSON config > default values.
180
+
181
+ ```python
182
+ from simpleArgParser import SpecialLoadMarker
183
+
184
+ @dataclass
185
+ class Config:
186
+ lr: float = 0.001
187
+ epochs: int = 10
188
+ load_from: str | None = SpecialLoadMarker()
189
+ ```
190
+
191
+ ```json
192
+ {"lr": 0.01, "epochs": 50}
193
+ ```
194
+
195
+ ```bash
196
+ python main.py --load_from config.json # uses JSON values
197
+ python main.py --load_from config.json --lr 0.1 # CLI overrides JSON
198
+ ```
199
+
200
+ ### Partial Defaults for Nested Dataclasses
201
+
202
+ When a nested dataclass has required fields, you can't use it directly as a default (e.g. `field(default_factory=SamplingConfig)` fails because `SamplingConfig` has required fields). Use `partial_defaults()` to provide defaults for **some** fields while keeping others required from CLI.
203
+
204
+ ```python
205
+ from simpleArgParser import parse_args, partial_defaults
206
+
207
+ @dataclass
208
+ class InnerConfig:
209
+ lr: float # required
210
+ weight_decay: float # required
211
+ warmup: int = 100
212
+
213
+ @dataclass
214
+ class Config:
215
+ # lr gets default 0.001, weight_decay stays required from CLI
216
+ optimizer: InnerConfig = partial_defaults(lr=0.001)
217
+ ```
218
+
219
+ ```bash
220
+ python main.py --optimizer.weight_decay 0.01
221
+ # optimizer.lr = 0.001 (from partial_defaults)
222
+ # optimizer.weight_decay = 0.01 (from CLI)
223
+ # optimizer.warmup = 100 (field default)
224
+
225
+ python main.py --optimizer.weight_decay 0.01 --optimizer.lr 0.1
226
+ # CLI overrides partial_defaults
227
+ ```
228
+
229
+ #### Nested partial_defaults
230
+
231
+ `partial_defaults` can be nested to set defaults at multiple levels:
232
+
233
+ ```python
234
+ @dataclass
235
+ class LeafConfig:
236
+ gen_n: int # required
237
+ cache: bool = True
238
+
239
+ @dataclass
240
+ class MiddleConfig:
241
+ max_tokens: int # required
242
+ temperature: float = 0.6
243
+ leaf: LeafConfig = partial_defaults(cache=False)
244
+
245
+ @dataclass
246
+ class OuterConfig:
247
+ mid: MiddleConfig = partial_defaults(
248
+ max_tokens=123,
249
+ leaf=partial_defaults(cache=False),
250
+ )
251
+ ```
252
+
253
+ ```bash
254
+ # Only gen_n is required — everything else has defaults
255
+ python main.py --mid.leaf.gen_n 10
256
+ # mid.max_tokens = 123
257
+ # mid.temperature = 0.6
258
+ # mid.leaf.gen_n = 10
259
+ # mid.leaf.cache = False
260
+
261
+ python main.py --mid.leaf.gen_n 10 --mid.leaf.cache true
262
+ # CLI overrides nested partial_defaults
263
+ ```
264
+
265
+ In `--help`, fields with partial defaults show their default value, and fields without defaults show `(required)`:
266
+
267
+ ```
268
+ --mid.leaf.gen_n (type: int) (required)
269
+ --mid.max_tokens (type: int) (default: 123)
270
+ --mid.leaf.cache (type: bool) (default: False)
271
+ ```
272
+
273
+ ### Pre/Post Processing
274
+
275
+ Define `pre_process()` and `post_process()` methods for validation or side effects. They are called recursively on all nested dataclasses (pre_process top-down, post_process bottom-up).
276
+
277
+ ```python
278
+ @dataclass
279
+ class Config:
280
+ tp: int = 1
281
+
282
+ def pre_process(self):
283
+ print("validating...")
284
+
285
+ def post_process(self):
286
+ if self.tp < 1:
287
+ raise ValueError("tp must be >= 1")
288
+ ```
289
+
290
+ ### Serialization
291
+
292
+ Convert configs to JSON or dict. Enum values are serialized by name.
293
+
294
+ ```python
295
+ from simpleArgParser import to_json, to_dict
296
+
297
+ config = parse_args(Config)
298
+ print(to_json(config)) # JSON string
299
+ print(to_dict(config)) # Python dict
300
+ ```
301
+
302
+ ### Programmatic Usage
303
+
304
+ Use `pass_in` to provide arguments from code. Use `disable_cmd=True` to ignore `sys.argv`. Very useful for debugging and testing.
305
+
306
+ ```python
307
+ config = parse_args(Config, pass_in=["--lr", "0.01", "--epochs", "5"])
308
+
309
+ # ignore command line entirely
310
+ config = parse_args(Config, pass_in=["--lr", "0.01"], disable_cmd=True)
311
+ ```
312
+
313
+ ### Subcommands (CLI Tools)
314
+
315
+ Build multi-command CLI tools with `parse_args_with_commands`. Define commands using enums for type-safe dispatching. Supports arbitrary nesting.
316
+
317
+ ```python
318
+ import enum
319
+ from simpleArgParser import parse_args_with_commands
320
+
321
+ class Command(enum.Enum):
322
+ train = "train" # start training
323
+ eval = "eval" # run evaluation
324
+
325
+ @dataclass
326
+ class TrainConfig:
327
+ lr: float = 0.001
328
+ epochs: int = 10
329
+
330
+ @dataclass
331
+ class EvalConfig:
332
+ checkpoint: str # required
333
+
334
+ command, config = parse_args_with_commands(
335
+ commands={
336
+ Command.train: TrainConfig,
337
+ Command.eval: EvalConfig,
338
+ },
339
+ )
340
+
341
+ if command == (Command.train,):
342
+ print(f"Training with lr={config.lr}")
343
+ elif command == (Command.eval,):
344
+ print(f"Evaluating {config.checkpoint}")
345
+ ```
346
+
347
+ ```bash
348
+ mycli train --lr 0.01 --epochs 20
349
+ mycli eval --checkpoint best.pt
350
+ mycli --help
351
+ ```
352
+
353
+ #### Nested Commands
354
+
355
+ Group commands into modules with nested dicts and separate enums per level. The returned `command` is a tuple of enum members.
356
+
357
+ ```python
358
+ class Top(enum.Enum):
359
+ model = "model" # model operations
360
+ data = "data" # data operations
361
+
362
+ class ModelCmd(enum.Enum):
363
+ train = "train"
364
+ eval = "eval"
365
+
366
+ class DataCmd(enum.Enum):
367
+ process = "process"
368
+
369
+ command, config = parse_args_with_commands(
370
+ commands={
371
+ Top.model: {
372
+ ModelCmd.train: TrainConfig,
373
+ ModelCmd.eval: EvalConfig,
374
+ },
375
+ Top.data: {
376
+ DataCmd.process: ProcessConfig,
377
+ },
378
+ },
379
+ description="My ML CLI",
380
+ )
381
+
382
+ # command == (Top.model, ModelCmd.train)
383
+ if command[0] == Top.model:
384
+ if command[1] == ModelCmd.train:
385
+ ...
386
+ ```
387
+
388
+ ```bash
389
+ mycli model train --lr 0.01
390
+ mycli data process --workers 8
391
+ mycli --help # shows command tree
392
+ mycli model --help # shows model sub-commands
393
+ ```
394
+
395
+ #### Shared Config Across Commands
396
+
397
+ Embed a common config as a nested field. Short aliases are created automatically for unique field names.
398
+
399
+ ```python
400
+ @dataclass
401
+ class CommonConfig:
402
+ verbose: bool = False
403
+
404
+ @dataclass
405
+ class TrainConfig:
406
+ lr: float = 0.001
407
+ common: CommonConfig = field(default_factory=CommonConfig)
408
+ ```
409
+
410
+ ```bash
411
+ mycli train --verbose true # alias for --common.verbose
412
+ mycli train --common.verbose true # full path always works
413
+ ```
414
+
415
+ ## Help Output Ordering
416
+
417
+ Arguments in `--help` are sorted by: required first, then by nesting depth (shallow first), then alphabetically.