0
# Utilities
1
2
Utility functions and classes for path handling, lazy instantiation, parser introspection, and advanced type support. These utilities provide foundational functionality used throughout jsonargparse and offer helpful tools for building sophisticated CLI applications.
3
4
## Capabilities
5
6
### Path Handling
7
8
Enhanced path class for robust file system path validation, resolution, and access control.
9
10
```python { .api }
11
class Path:
12
def __init__(self, path: Union[str, os.PathLike], mode: str = "fr"):
13
"""
14
Create a Path object with validation and access control.
15
16
Args:
17
path: File system path (relative or absolute)
18
mode: Access mode string (combinations of 'f'=file, 'd'=dir, 'r'=read, 'w'=write, 'x'=executable)
19
20
Raises:
21
TypeError: If path validation fails
22
"""
23
24
def __str__(self) -> str:
25
"""
26
Get string representation of the path.
27
28
Returns:
29
str: String path
30
"""
31
32
@property
33
def absolute(self) -> pathlib.Path:
34
"""
35
Get absolute path as pathlib.Path object.
36
37
Returns:
38
pathlib.Path: Absolute path
39
"""
40
41
def exists(self) -> bool:
42
"""
43
Check if path exists.
44
45
Returns:
46
bool: True if path exists
47
"""
48
49
def is_file(self) -> bool:
50
"""
51
Check if path is a file.
52
53
Returns:
54
bool: True if path is a file
55
"""
56
57
def is_dir(self) -> bool:
58
"""
59
Check if path is a directory.
60
61
Returns:
62
bool: True if path is a directory
63
"""
64
```
65
66
### Lazy Instantiation
67
68
Utility for creating lazy instances where class instantiation is delayed until first method call.
69
70
```python { .api }
71
def lazy_instance(init_fn: Callable[[], Any]) -> Any:
72
"""
73
Create a lazy instance that delays instantiation until first use.
74
75
Args:
76
init_fn: Function that returns the instance when called
77
78
Returns:
79
Any: Lazy proxy object that behaves like the target instance
80
"""
81
```
82
83
### Parser Introspection
84
85
Utilities for capturing and introspecting ArgumentParser instances during execution.
86
87
```python { .api }
88
def capture_parser() -> ArgumentParser:
89
"""
90
Capture the ArgumentParser being used in the current execution context.
91
92
Returns:
93
ArgumentParser: The parser instance currently being used
94
95
Raises:
96
RuntimeError: If no parser is active in current context
97
"""
98
```
99
100
### Dynamic Class Generation
101
102
Utilities for creating classes dynamically from functions and managing class introspection.
103
104
```python { .api }
105
def class_from_function(function: Callable, *args, **kwargs) -> Type:
106
"""
107
Create a dynamic class equivalent to calling a function.
108
109
Args:
110
function: Function to wrap as a class
111
*args: Positional arguments for function
112
**kwargs: Keyword arguments for function
113
114
Returns:
115
Type: Dynamic class that instantiates by calling the function
116
"""
117
118
def register_unresolvable_import_paths(*import_paths: str) -> None:
119
"""
120
Register import paths for objects whose import path cannot be automatically resolved.
121
122
Args:
123
*import_paths: Import path strings to register
124
"""
125
```
126
127
## Usage Examples
128
129
### Path Validation and Access Control
130
131
```python
132
from jsonargparse import ArgumentParser, Path
133
134
parser = ArgumentParser()
135
136
# Add path arguments with validation
137
parser.add_argument(
138
"--input-file",
139
type=Path(mode="fr"), # Must exist, be a file, and be readable
140
help="Input file path"
141
)
142
143
parser.add_argument(
144
"--output-dir",
145
type=Path(mode="dw"), # Must be a directory and writable
146
help="Output directory path"
147
)
148
149
parser.add_argument(
150
"--script",
151
type=Path(mode="fx"), # Must be a file and executable
152
help="Script to execute"
153
)
154
155
config = parser.parse_args()
156
157
# Paths are validated automatically
158
print(f"Input file: {config.input_file}")
159
print(f"Absolute path: {config.input_file.absolute}")
160
print(f"Exists: {config.input_file.exists()}")
161
print(f"Is file: {config.input_file.is_file()}")
162
163
# Use the paths
164
with open(config.input_file, 'r') as f:
165
data = f.read()
166
```
167
168
### Lazy Instance Creation
169
170
```python
171
from jsonargparse import lazy_instance
172
import expensive_module
173
174
# Create lazy instance that delays expensive initialization
175
def create_model():
176
print("Creating expensive model...")
177
return expensive_module.LargeModel()
178
179
# Model is not created yet
180
lazy_model = lazy_instance(create_model)
181
182
print("Lazy model created")
183
184
# Model is created only when first accessed
185
result = lazy_model.predict(data) # "Creating expensive model..." printed here
186
print(f"Prediction: {result}")
187
188
# Subsequent calls use the same instance
189
result2 = lazy_model.predict(more_data) # No "Creating..." message
190
```
191
192
### Parser Capture and Introspection
193
194
```python
195
from jsonargparse import ArgumentParser, capture_parser
196
197
def setup_logging_args(enable_capture: bool = True):
198
"""Function that adds logging arguments to current parser."""
199
if enable_capture:
200
# Capture the current parser being used
201
parser = capture_parser()
202
203
# Add logging arguments to captured parser
204
parser.add_argument("--log-level",
205
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
206
default="INFO")
207
parser.add_argument("--log-file", type=str, help="Log file path")
208
parser.add_argument("--quiet", action="store_true", help="Suppress output")
209
210
print("Added logging arguments to parser")
211
212
# Create parser
213
parser = ArgumentParser()
214
parser.add_argument("--name", type=str, required=True)
215
216
# Add function arguments - this will capture the current parser
217
parser.add_function_arguments(setup_logging_args)
218
219
config = parser.parse_args()
220
221
print(f"Name: {config.name}")
222
print(f"Log level: {config.log_level}")
223
if config.log_file:
224
print(f"Log file: {config.log_file}")
225
```
226
227
### Dynamic Class Creation
228
229
```python
230
from jsonargparse import class_from_function, ArgumentParser
231
232
def train_model(data_path: str, epochs: int = 100, learning_rate: float = 0.001):
233
"""Train a machine learning model."""
234
print(f"Training model with data from {data_path}")
235
print(f"Epochs: {epochs}, Learning rate: {learning_rate}")
236
return {"status": "trained", "epochs": epochs}
237
238
# Create a class from the function
239
TrainingClass = class_from_function(train_model)
240
241
# Use the dynamic class with jsonargparse
242
parser = ArgumentParser()
243
parser.add_class_arguments(TrainingClass, "training")
244
245
config = parser.parse_args()
246
247
# Instantiate the dynamic class (calls the original function)
248
trainer = TrainingClass(**config.training.as_dict())
249
print(f"Training result: {trainer}")
250
```
251
252
### Import Path Registration
253
254
```python
255
from jsonargparse import register_unresolvable_import_paths
256
from some_complex_module import HardToResolveClass
257
258
# Register import paths for classes that can't be automatically resolved
259
register_unresolvable_import_paths(
260
"some_complex_module.HardToResolveClass",
261
"another_module.DynamicClass"
262
)
263
264
# Now these classes can be properly serialized and deserialized
265
# in configuration files and command line arguments
266
```
267
268
### Advanced Path Usage
269
270
```python
271
from jsonargparse import ArgumentParser, Path
272
273
parser = ArgumentParser()
274
275
# Different path modes for different use cases
276
parser.add_argument("--config", type=Path(mode="fr")) # File, readable
277
parser.add_argument("--output", type=Path(mode="fw")) # File, writable (may not exist)
278
parser.add_argument("--data-dir", type=Path(mode="dr")) # Directory, readable
279
parser.add_argument("--temp-dir", type=Path(mode="dw")) # Directory, writable
280
parser.add_argument("--script", type=Path(mode="frx")) # File, readable, executable
281
282
try:
283
config = parser.parse_args()
284
285
# All paths are validated according to their modes
286
print(f"Config file: {config.config}")
287
print(f"Output will be written to: {config.output}")
288
print(f"Data directory: {config.data_dir}")
289
print(f"Script to run: {config.script}")
290
291
except Exception as e:
292
print(f"Path validation failed: {e}")
293
```
294
295
### Combining Utilities
296
297
```python
298
from jsonargparse import ArgumentParser, Path, lazy_instance, capture_parser
299
import logging
300
301
def create_logger():
302
"""Create logger instance only when needed."""
303
logger = logging.getLogger("myapp")
304
logger.setLevel(logging.INFO)
305
handler = logging.StreamHandler()
306
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
307
handler.setFormatter(formatter)
308
logger.addHandler(handler)
309
return logger
310
311
def setup_app_args():
312
"""Setup application-specific arguments."""
313
parser = capture_parser()
314
parser.add_argument("--debug", action="store_true")
315
parser.add_argument("--workers", type=int, default=1)
316
317
class AppConfig:
318
def __init__(self,
319
input_file: Path(mode="fr"),
320
output_dir: Path(mode="dw"),
321
log_file: Path(mode="fw") = None):
322
self.input_file = input_file
323
self.output_dir = output_dir
324
self.log_file = log_file
325
326
# Create lazy logger
327
self.logger = lazy_instance(create_logger)
328
329
def process(self):
330
self.logger.info(f"Processing {self.input_file}")
331
self.logger.info(f"Output will go to {self.output_dir}")
332
333
# Process files here
334
print(f"Processing {self.input_file} -> {self.output_dir}")
335
336
parser = ArgumentParser()
337
parser.add_class_arguments(AppConfig, "config")
338
parser.add_function_arguments(setup_app_args)
339
340
args = parser.parse_args()
341
342
app = AppConfig(**args.config.as_dict())
343
app.process()
344
345
if args.debug:
346
print("Debug mode enabled")
347
print(f"Using {args.workers} workers")
348
```
349
350
### Path Mode Reference
351
352
Path validation modes:
353
354
- `"f"` - Must be a file
355
- `"d"` - Must be a directory
356
- `"r"` - Must be readable
357
- `"w"` - Must be writable
358
- `"x"` - Must be executable
359
- `"c"` - File can be created (parent directory must exist and be writable)
360
- `"u"` - Path can be a URL
361
362
Common combinations:
363
- `"fr"` - Existing readable file
364
- `"fw"` - Writable file (may not exist yet)
365
- `"dr"` - Existing readable directory
366
- `"dw"` - Writable directory
367
- `"frx"` - Executable file
368
- `"fc"` - File that can be created