orionis 0.448.0__py3-none-any.whl → 0.449.0__py3-none-any.whl
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.
- orionis/console/args/argument.py +174 -43
- orionis/console/args/parser.py +37 -3
- orionis/console/base/command.py +103 -48
- orionis/console/base/contracts/command.py +97 -40
- orionis/console/core/reactor.py +408 -14
- orionis/console/output/contracts/executor.py +93 -0
- orionis/console/output/executor.py +153 -0
- orionis/foundation/application.py +6 -2
- orionis/foundation/providers/console_provider.py +35 -10
- orionis/foundation/providers/dumper_provider.py +42 -14
- orionis/foundation/providers/executor_provider.py +80 -0
- orionis/foundation/providers/inspirational_provider.py +43 -23
- orionis/foundation/providers/logger_provider.py +47 -8
- orionis/foundation/providers/progress_bar_provider.py +55 -10
- orionis/foundation/providers/testing_provider.py +75 -31
- orionis/foundation/providers/workers_provider.py +69 -11
- orionis/metadata/framework.py +1 -1
- orionis/support/facades/console.py +11 -3
- orionis/support/facades/dumper.py +10 -3
- orionis/support/facades/executor.py +24 -0
- orionis/support/facades/inspire.py +9 -6
- orionis/support/facades/logger.py +11 -4
- orionis/support/facades/progress_bar.py +9 -3
- orionis/support/facades/testing.py +10 -4
- orionis/support/facades/workers.py +8 -4
- orionis/test/kernel.py +2 -2
- {orionis-0.448.0.dist-info → orionis-0.449.0.dist-info}/METADATA +1 -1
- {orionis-0.448.0.dist-info → orionis-0.449.0.dist-info}/RECORD +32 -28
- {orionis-0.448.0.dist-info → orionis-0.449.0.dist-info}/WHEEL +0 -0
- {orionis-0.448.0.dist-info → orionis-0.449.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.448.0.dist-info → orionis-0.449.0.dist-info}/top_level.txt +0 -0
- {orionis-0.448.0.dist-info → orionis-0.449.0.dist-info}/zip-safe +0 -0
orionis/console/args/argument.py
CHANGED
|
@@ -45,69 +45,69 @@ class CLIArgument:
|
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
47
|
# Required fields
|
|
48
|
-
flags: List[str]
|
|
49
|
-
type: Type
|
|
50
|
-
help: str = None
|
|
48
|
+
flags: List[str]
|
|
49
|
+
type: Type
|
|
50
|
+
help: Optional[str] = None
|
|
51
51
|
|
|
52
52
|
default: Any = field(
|
|
53
|
-
|
|
54
|
-
metadata
|
|
53
|
+
default=None,
|
|
54
|
+
metadata={
|
|
55
55
|
"description": "Default value for the argument.",
|
|
56
56
|
"default": None
|
|
57
57
|
}
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
choices: Optional[List[Any]] = field(
|
|
61
|
-
|
|
62
|
-
metadata
|
|
61
|
+
default=None,
|
|
62
|
+
metadata={
|
|
63
63
|
"description": "List of valid choices for the argument.",
|
|
64
64
|
"default": None
|
|
65
65
|
}
|
|
66
66
|
)
|
|
67
67
|
|
|
68
68
|
required: bool = field(
|
|
69
|
-
|
|
70
|
-
metadata
|
|
69
|
+
default=False,
|
|
70
|
+
metadata={
|
|
71
71
|
"description": "Indicates if the argument is required.",
|
|
72
72
|
"default": False
|
|
73
73
|
}
|
|
74
74
|
)
|
|
75
75
|
|
|
76
76
|
metavar: Optional[str] = field(
|
|
77
|
-
|
|
78
|
-
metadata
|
|
77
|
+
default=None,
|
|
78
|
+
metadata={
|
|
79
79
|
"description": "Metavar for displaying in help messages.",
|
|
80
80
|
"default": None
|
|
81
81
|
}
|
|
82
82
|
)
|
|
83
83
|
|
|
84
84
|
dest: Optional[str] = field(
|
|
85
|
-
|
|
86
|
-
metadata
|
|
85
|
+
default=None,
|
|
86
|
+
metadata={
|
|
87
87
|
"description": "Destination name for the argument in the namespace.",
|
|
88
88
|
"default": None
|
|
89
89
|
}
|
|
90
90
|
)
|
|
91
91
|
|
|
92
92
|
action: Union[str, ArgumentAction] = field(
|
|
93
|
-
|
|
94
|
-
metadata
|
|
93
|
+
default=ArgumentAction.STORE,
|
|
94
|
+
metadata={
|
|
95
95
|
"description": "Action to perform with the argument.",
|
|
96
96
|
"default": ArgumentAction.STORE.value
|
|
97
97
|
}
|
|
98
98
|
)
|
|
99
99
|
|
|
100
100
|
nargs: Optional[Union[int, str]] = field(
|
|
101
|
-
|
|
102
|
-
metadata
|
|
101
|
+
default=None,
|
|
102
|
+
metadata={
|
|
103
103
|
"description": "Number of arguments expected (e.g., 1, 2, '+', '*').",
|
|
104
104
|
"default": None
|
|
105
105
|
}
|
|
106
106
|
)
|
|
107
107
|
|
|
108
108
|
const: Any = field(
|
|
109
|
-
|
|
110
|
-
metadata
|
|
109
|
+
default=None,
|
|
110
|
+
metadata={
|
|
111
111
|
"description": "Constant value for store_const or append_const actions.",
|
|
112
112
|
"default": None
|
|
113
113
|
}
|
|
@@ -159,7 +159,8 @@ class CLIArgument:
|
|
|
159
159
|
|
|
160
160
|
# Auto-generate help if not provided
|
|
161
161
|
if self.help is None:
|
|
162
|
-
|
|
162
|
+
clean_flag = primary_flag.lstrip('-').replace('-', ' ').title()
|
|
163
|
+
object.__setattr__(self, 'help', f"{clean_flag} argument")
|
|
163
164
|
|
|
164
165
|
# Ensure help is a string
|
|
165
166
|
if not isinstance(self.help, str):
|
|
@@ -204,9 +205,7 @@ class CLIArgument:
|
|
|
204
205
|
raise CLIOrionisValueError(f"Destination '{self.dest}' is not a valid Python identifier")
|
|
205
206
|
|
|
206
207
|
# Normalize action value
|
|
207
|
-
if self.action
|
|
208
|
-
object.__setattr__(self, 'action', ArgumentAction.STORE.value)
|
|
209
|
-
elif isinstance(self.action, str):
|
|
208
|
+
if isinstance(self.action, str):
|
|
210
209
|
try:
|
|
211
210
|
action_enum = ArgumentAction(self.action)
|
|
212
211
|
object.__setattr__(self, 'action', action_enum.value)
|
|
@@ -217,22 +216,74 @@ class CLIArgument:
|
|
|
217
216
|
else:
|
|
218
217
|
raise CLIOrionisValueError("Action must be a string or an ArgumentAction enum value")
|
|
219
218
|
|
|
219
|
+
# Determine if this is an optional argument (starts with dash)
|
|
220
|
+
is_optional = any(flag.startswith('-') for flag in self.flags)
|
|
221
|
+
|
|
220
222
|
# Special handling for boolean types
|
|
221
223
|
if self.type is bool:
|
|
224
|
+
# Auto-configure action based on default value and whether it's optional
|
|
225
|
+
if is_optional:
|
|
226
|
+
action = ArgumentAction.STORE_FALSE.value if self.default else ArgumentAction.STORE_TRUE.value
|
|
227
|
+
object.__setattr__(self, 'action', action)
|
|
228
|
+
# argparse ignores type with store_true/false actions
|
|
229
|
+
object.__setattr__(self, 'type', None)
|
|
230
|
+
else:
|
|
231
|
+
# For positional boolean arguments, keep type as bool
|
|
232
|
+
pass
|
|
222
233
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
234
|
+
# Special handling for list types
|
|
235
|
+
elif self.type is list:
|
|
236
|
+
if self.nargs is None:
|
|
237
|
+
# Auto-configure for accepting multiple values
|
|
238
|
+
object.__setattr__(self, 'nargs', '+' if is_optional else '*')
|
|
239
|
+
# Keep type as list for proper conversion
|
|
240
|
+
object.__setattr__(self, 'type', str) # argparse expects element type, not list
|
|
241
|
+
|
|
242
|
+
# Handle count action - typically used for verbosity flags
|
|
243
|
+
elif self.action == ArgumentAction.COUNT.value:
|
|
244
|
+
object.__setattr__(self, 'type', None) # count action doesn't use type
|
|
245
|
+
if self.default is None:
|
|
246
|
+
object.__setattr__(self, 'default', 0)
|
|
247
|
+
|
|
248
|
+
# Handle const actions
|
|
249
|
+
if self.action in (ArgumentAction.STORE_CONST.value, ArgumentAction.APPEND_CONST.value):
|
|
250
|
+
if self.const is None:
|
|
251
|
+
# Auto-set const based on type or use True as default
|
|
252
|
+
if self.type is bool:
|
|
253
|
+
object.__setattr__(self, 'const', True)
|
|
254
|
+
elif self.type is int:
|
|
255
|
+
object.__setattr__(self, 'const', 1)
|
|
256
|
+
elif self.type is str:
|
|
257
|
+
object.__setattr__(self, 'const', self.dest)
|
|
258
|
+
else:
|
|
259
|
+
object.__setattr__(self, 'const', True)
|
|
260
|
+
object.__setattr__(self, 'type', None) # const actions don't use type
|
|
261
|
+
|
|
262
|
+
# Handle nargs '?' - optional single argument
|
|
263
|
+
elif self.nargs == '?':
|
|
264
|
+
if self.const is None and is_optional:
|
|
265
|
+
# For optional arguments with nargs='?', set a reasonable const
|
|
266
|
+
object.__setattr__(self, 'const', True if self.type is bool else self.dest)
|
|
267
|
+
|
|
268
|
+
# Validate nargs compatibility
|
|
269
|
+
if self.nargs is not None:
|
|
270
|
+
valid_nargs = ['?', '*', '+'] + [str(i) for i in range(0, 10)]
|
|
271
|
+
if isinstance(self.nargs, int):
|
|
272
|
+
if self.nargs < 0:
|
|
273
|
+
raise CLIOrionisValueError("nargs cannot be negative")
|
|
274
|
+
elif self.nargs not in valid_nargs:
|
|
275
|
+
raise CLIOrionisValueError(f"Invalid nargs value: {self.nargs}")
|
|
276
|
+
|
|
277
|
+
# Handle version action
|
|
278
|
+
if self.action == ArgumentAction.VERSION.value:
|
|
228
279
|
object.__setattr__(self, 'type', None)
|
|
280
|
+
if 'version' not in self.dest:
|
|
281
|
+
object.__setattr__(self, 'dest', 'version')
|
|
229
282
|
|
|
230
|
-
#
|
|
231
|
-
if self.
|
|
283
|
+
# Handle help action
|
|
284
|
+
if self.action == ArgumentAction.HELP.value:
|
|
285
|
+
object.__setattr__(self, 'type', None)
|
|
232
286
|
|
|
233
|
-
# Auto-configure for accepting multiple values
|
|
234
|
-
object.__setattr__(self, 'nargs', '+')
|
|
235
|
-
object.__setattr__(self, 'type', str)
|
|
236
287
|
|
|
237
288
|
def addToParser(self, parser: argparse.ArgumentParser) -> None:
|
|
238
289
|
"""
|
|
@@ -327,17 +378,97 @@ class CLIArgument:
|
|
|
327
378
|
"action": self.action, # Action to take when argument is encountered
|
|
328
379
|
"nargs": self.nargs, # Number of command-line arguments expected
|
|
329
380
|
"type": self.type, # Type to convert the argument to
|
|
330
|
-
"const": self.const # Constant value for certain actions
|
|
331
381
|
}
|
|
332
382
|
|
|
333
|
-
#
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
383
|
+
# Handle const parameter for specific actions
|
|
384
|
+
const_actions = [
|
|
385
|
+
ArgumentAction.STORE_CONST.value,
|
|
386
|
+
ArgumentAction.APPEND_CONST.value
|
|
387
|
+
]
|
|
388
|
+
|
|
389
|
+
# Add const parameter when it's needed
|
|
390
|
+
if self.action in const_actions or (self.nargs == '?' and self.const is not None):
|
|
391
|
+
kwargs["const"] = self.const
|
|
392
|
+
|
|
393
|
+
# Special handling for version action
|
|
394
|
+
if self.action == ArgumentAction.VERSION.value and hasattr(self, 'version'):
|
|
395
|
+
kwargs["version"] = getattr(self, 'version', None)
|
|
396
|
+
|
|
397
|
+
# Define actions that don't accept certain parameters
|
|
398
|
+
type_ignored_actions = [
|
|
399
|
+
ArgumentAction.STORE_TRUE.value,
|
|
400
|
+
ArgumentAction.STORE_FALSE.value,
|
|
401
|
+
ArgumentAction.STORE_CONST.value,
|
|
402
|
+
ArgumentAction.APPEND_CONST.value,
|
|
403
|
+
ArgumentAction.COUNT.value,
|
|
404
|
+
ArgumentAction.HELP.value,
|
|
405
|
+
ArgumentAction.VERSION.value
|
|
406
|
+
]
|
|
407
|
+
|
|
408
|
+
# Define actions that don't accept metavar or default parameters
|
|
409
|
+
metavar_ignored_actions = [
|
|
410
|
+
ArgumentAction.STORE_TRUE.value,
|
|
411
|
+
ArgumentAction.STORE_FALSE.value,
|
|
412
|
+
ArgumentAction.COUNT.value,
|
|
413
|
+
ArgumentAction.HELP.value,
|
|
414
|
+
ArgumentAction.VERSION.value
|
|
415
|
+
]
|
|
416
|
+
|
|
417
|
+
# Define actions that don't accept default parameters
|
|
418
|
+
default_ignored_actions = [
|
|
419
|
+
ArgumentAction.STORE_TRUE.value,
|
|
420
|
+
ArgumentAction.STORE_FALSE.value,
|
|
421
|
+
ArgumentAction.STORE_CONST.value,
|
|
422
|
+
ArgumentAction.APPEND_CONST.value,
|
|
423
|
+
ArgumentAction.HELP.value,
|
|
424
|
+
ArgumentAction.VERSION.value
|
|
425
|
+
]
|
|
426
|
+
|
|
427
|
+
# Filter out None values and incompatible parameters
|
|
428
|
+
filtered_kwargs = {}
|
|
429
|
+
for k, v in kwargs.items():
|
|
430
|
+
if v is not None:
|
|
431
|
+
|
|
432
|
+
# Skip parameters that are not compatible with certain actions
|
|
433
|
+
if k == "type" and self.action in type_ignored_actions:
|
|
434
|
+
continue
|
|
435
|
+
|
|
436
|
+
# Skip metavar for actions that don't accept it
|
|
437
|
+
if k == "metavar" and self.action in metavar_ignored_actions:
|
|
438
|
+
continue
|
|
439
|
+
|
|
440
|
+
# Skip default for actions that don't accept it
|
|
441
|
+
if k == "default" and self.action in default_ignored_actions:
|
|
442
|
+
continue
|
|
443
|
+
|
|
444
|
+
# Special case: don't include empty strings for metavar in positional args
|
|
445
|
+
if k == "metavar" and is_positional and v == "":
|
|
446
|
+
continue
|
|
447
|
+
|
|
448
|
+
# Add the parameter to the filtered kwargs
|
|
449
|
+
filtered_kwargs[k] = v
|
|
450
|
+
|
|
451
|
+
# Remove parameters that are not compatible with positional arguments
|
|
452
|
+
if is_positional:
|
|
453
|
+
|
|
454
|
+
# Remove 'required' parameter for positional arguments since it's not supported
|
|
455
|
+
if 'required' in filtered_kwargs:
|
|
456
|
+
del filtered_kwargs['required']
|
|
457
|
+
|
|
458
|
+
# Remove 'dest' parameter for positional arguments as argparse calculates it automatically
|
|
459
|
+
if 'dest' in filtered_kwargs:
|
|
460
|
+
del filtered_kwargs['dest']
|
|
461
|
+
|
|
462
|
+
# Remove 'metavar' if it's the same as the flag name (redundant)
|
|
463
|
+
if 'metavar' in filtered_kwargs and len(self.flags) == 1:
|
|
464
|
+
flag_upper = self.flags[0].upper()
|
|
465
|
+
if filtered_kwargs['metavar'] == flag_upper:
|
|
466
|
+
del filtered_kwargs['metavar']
|
|
467
|
+
|
|
468
|
+
# For count action, ensure default is an integer
|
|
469
|
+
if self.action == ArgumentAction.COUNT.value and 'default' in filtered_kwargs:
|
|
470
|
+
if not isinstance(filtered_kwargs['default'], int):
|
|
471
|
+
filtered_kwargs['default'] = 0
|
|
341
472
|
|
|
342
473
|
# Return the cleaned and validated kwargs dictionary
|
|
343
|
-
return
|
|
474
|
+
return filtered_kwargs
|
orionis/console/args/parser.py
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
1
3
|
class ArgumentPaser():
|
|
2
4
|
|
|
3
|
-
def __init__(self
|
|
4
|
-
self.
|
|
5
|
+
def __init__(self):
|
|
6
|
+
self.__parser = argparse.ArgumentParser()
|
|
7
|
+
|
|
8
|
+
def addArgument(self, name: str, **kwargs):
|
|
9
|
+
"""
|
|
10
|
+
Add an argument to the parser.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
name : str
|
|
15
|
+
The name of the argument to add.
|
|
16
|
+
kwargs : dict
|
|
17
|
+
Additional keyword arguments for the argument configuration.
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
None
|
|
22
|
+
This method does not return any value.
|
|
23
|
+
"""
|
|
24
|
+
self.__parser.add_argument(name, **kwargs)
|
|
25
|
+
|
|
26
|
+
def parse(self, args=None):
|
|
27
|
+
"""
|
|
28
|
+
Parse the command-line arguments.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
args : list, optional
|
|
33
|
+
A list of arguments to parse. If None, uses sys.argv by default.
|
|
5
34
|
|
|
6
|
-
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
Namespace
|
|
38
|
+
An object containing the parsed arguments as attributes.
|
|
39
|
+
"""
|
|
40
|
+
return self.__parser.parse_args(args)
|
orionis/console/base/command.py
CHANGED
|
@@ -1,92 +1,147 @@
|
|
|
1
|
-
from typing import Any, Dict
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
from orionis.console.args.argument import CLIArgument
|
|
2
3
|
from orionis.console.dynamic.progress_bar import ProgressBar
|
|
3
4
|
from orionis.console.output.console import Console
|
|
4
5
|
from orionis.console.base.contracts.command import IBaseCommand
|
|
5
6
|
|
|
6
7
|
class BaseCommand(Console, ProgressBar, IBaseCommand):
|
|
7
8
|
"""
|
|
8
|
-
Abstract base class for console commands in Orionis.
|
|
9
|
+
Abstract base class for implementing console commands in the Orionis framework.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
This class provides a foundation for creating command-line interface commands with
|
|
12
|
+
built-in console output capabilities, progress bar functionality, and argument handling.
|
|
13
|
+
It inherits from Console and ProgressBar to provide rich terminal interaction features
|
|
14
|
+
while implementing the IBaseCommand interface contract.
|
|
15
|
+
|
|
16
|
+
The BaseCommand class serves as a template that enforces a consistent structure for
|
|
17
|
+
all command implementations in the framework, requiring subclasses to implement the
|
|
18
|
+
core command logic while providing common utilities for argument access and console
|
|
19
|
+
operations.
|
|
20
|
+
|
|
21
|
+
This is an abstract base class and should not be instantiated directly.
|
|
22
|
+
All concrete command implementations must inherit from this class and
|
|
23
|
+
provide their own handle() method implementation.
|
|
24
|
+
|
|
25
|
+
The class integrates with the framework's console and progress bar systems,
|
|
26
|
+
allowing commands to provide rich user feedback during execution.
|
|
14
27
|
|
|
15
28
|
Attributes
|
|
16
29
|
----------
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
timestamps : bool, default True
|
|
31
|
+
Controls whether timestamps are included in console output messages.
|
|
32
|
+
When True, all console output will be prefixed with timestamp information.
|
|
33
|
+
signature : str
|
|
34
|
+
Defines the command signature string used for command registration and
|
|
35
|
+
automatic help text generation. This should follow the framework's
|
|
36
|
+
signature format conventions.
|
|
37
|
+
description : str
|
|
38
|
+
Human-readable description of the command's purpose and functionality.
|
|
39
|
+
Used in help documentation and command listing interfaces.
|
|
40
|
+
_args : Dict[str, Any], default {}
|
|
41
|
+
Dictionary containing parsed command-line arguments and options.
|
|
42
|
+
Populated automatically by the command parser before handle() execution.
|
|
43
|
+
arguments : List[CLIArgument], default []
|
|
44
|
+
List of CLIArgument instances defining the command's accepted arguments
|
|
45
|
+
and options. Used for argument parsing and validation.
|
|
19
46
|
|
|
20
47
|
Methods
|
|
21
48
|
-------
|
|
22
49
|
handle()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
50
|
+
Abstract method that must be implemented by subclasses to define the
|
|
51
|
+
main command execution logic.
|
|
52
|
+
argument(key: str)
|
|
53
|
+
Safely retrieves argument values from the parsed arguments dictionary
|
|
54
|
+
with type validation and error handling.
|
|
28
55
|
"""
|
|
29
56
|
|
|
30
|
-
|
|
57
|
+
# Enable timestamps in console output by default
|
|
58
|
+
timestamps: bool = True
|
|
59
|
+
|
|
60
|
+
# Command signature string for registration and help text generation
|
|
61
|
+
signature: str
|
|
62
|
+
|
|
63
|
+
# Human-readable description for documentation and help display
|
|
64
|
+
description: str
|
|
65
|
+
|
|
66
|
+
# Dictionary to store parsed command-line arguments and options
|
|
67
|
+
_args: Dict[str, Any] = {}
|
|
68
|
+
|
|
69
|
+
# List of CLIArgument instances defining command arguments
|
|
70
|
+
arguments: List[CLIArgument] = []
|
|
31
71
|
|
|
32
72
|
def handle(self):
|
|
33
73
|
"""
|
|
34
|
-
|
|
74
|
+
Execute the main command logic.
|
|
35
75
|
|
|
36
|
-
This method
|
|
37
|
-
|
|
76
|
+
This abstract method defines the entry point for command execution and must be
|
|
77
|
+
implemented by all concrete command subclasses. It serves as the primary interface
|
|
78
|
+
for running the command's core functionality after argument parsing and validation.
|
|
38
79
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
None
|
|
83
|
+
This method does not return any value. All command output should be handled
|
|
84
|
+
through the inherited console methods or other side effects.
|
|
44
85
|
|
|
45
86
|
Raises
|
|
46
87
|
------
|
|
47
88
|
NotImplementedError
|
|
48
|
-
Always raised
|
|
89
|
+
Always raised when called on the base class, indicating that subclasses
|
|
90
|
+
must provide their own implementation of this method.
|
|
91
|
+
|
|
92
|
+
Notes
|
|
93
|
+
-----
|
|
94
|
+
Subclasses should override this method to implement their specific command
|
|
95
|
+
behavior. The method will be called after all command-line arguments have
|
|
96
|
+
been parsed and stored in the _args dictionary.
|
|
49
97
|
"""
|
|
98
|
+
|
|
99
|
+
# Raise an error to enforce implementation in subclasses
|
|
50
100
|
raise NotImplementedError("The 'handle' method must be implemented in the subclass.")
|
|
51
101
|
|
|
52
|
-
def argument(self, key: str):
|
|
102
|
+
def argument(self, key: str, default: Any = None) -> Any:
|
|
53
103
|
"""
|
|
54
|
-
|
|
104
|
+
Retrieve the value of a specific command-line argument by key with optional default fallback.
|
|
105
|
+
|
|
106
|
+
This method provides safe and validated access to command-line arguments stored in the
|
|
107
|
+
internal arguments dictionary. It performs type checking on both the key parameter and
|
|
108
|
+
the internal _args attribute to ensure data integrity before attempting retrieval.
|
|
109
|
+
|
|
110
|
+
The method follows a fail-safe approach by returning a default value when the requested
|
|
111
|
+
argument key is not found, preventing KeyError exceptions during command execution.
|
|
55
112
|
|
|
56
113
|
Parameters
|
|
57
114
|
----------
|
|
58
115
|
key : str
|
|
59
|
-
|
|
116
|
+
The string identifier used to locate the desired argument in the arguments
|
|
117
|
+
dictionary. Must be a non-empty string that corresponds to a valid argument name.
|
|
118
|
+
default : Any, optional
|
|
119
|
+
The fallback value to return if the specified key is not found in the arguments
|
|
120
|
+
dictionary. Defaults to None if not provided.
|
|
60
121
|
|
|
61
122
|
Returns
|
|
62
123
|
-------
|
|
63
|
-
|
|
64
|
-
|
|
124
|
+
Any
|
|
125
|
+
The value associated with the specified key if it exists in the arguments
|
|
126
|
+
dictionary. If the key is not found, returns the provided default value
|
|
127
|
+
or None if no default was specified.
|
|
65
128
|
|
|
66
129
|
Raises
|
|
67
130
|
------
|
|
68
131
|
ValueError
|
|
69
|
-
If the key is not
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
132
|
+
If the provided key parameter is not of string type.
|
|
133
|
+
ValueError
|
|
134
|
+
If the internal _args attribute is not of dictionary type, indicating
|
|
135
|
+
a corrupted or improperly initialized command state.
|
|
73
136
|
"""
|
|
74
|
-
if not isinstance(key, str):
|
|
75
|
-
raise ValueError("Argument key must be a string.")
|
|
76
|
-
if not isinstance(self.args, dict):
|
|
77
|
-
raise ValueError("Arguments must be a dictionary.")
|
|
78
|
-
return self.args.get(key)
|
|
79
137
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
138
|
+
# Validate that the key parameter is a string type
|
|
139
|
+
if not isinstance(key, str):
|
|
140
|
+
raise ValueError(f"Argument key must be a string, got '{type(key).__name__}' instead.")
|
|
83
141
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Dictionary containing all arguments received by the command. If no arguments, returns an empty dictionary.
|
|
142
|
+
# Ensure the internal args attribute is a valid dictionary
|
|
143
|
+
if not isinstance(self._args, dict):
|
|
144
|
+
raise ValueError(f"Arguments must be a dictionary, got '{type(self._args).__name__}' instead.")
|
|
88
145
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"""
|
|
92
|
-
return dict(self.args) if isinstance(self.args, dict) else {}
|
|
146
|
+
# Safely retrieve the argument value with optional default fallback
|
|
147
|
+
return self._args.get(key, default)
|