cmd2 2.5.11__py3-none-any.whl → 2.6.1__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.
cmd2/argparse_custom.py CHANGED
@@ -1,6 +1,5 @@
1
- # coding=utf-8
2
- """
3
- This module adds capabilities to argparse by patching a few of its functions.
1
+ """Module adds capabilities to argparse by patching a few of its functions.
2
+
4
3
  It also defines a parser class called Cmd2ArgumentParser which improves error
5
4
  and help output over normal argparse. All cmd2 code uses this parser and it is
6
5
  recommended that developers of cmd2-based apps either use it or write their own
@@ -230,6 +229,7 @@ from argparse import (
230
229
  ZERO_OR_MORE,
231
230
  ArgumentError,
232
231
  )
232
+ from collections.abc import Callable, Iterable, Sequence
233
233
  from gettext import (
234
234
  gettext,
235
235
  )
@@ -237,17 +237,9 @@ from typing import (
237
237
  IO,
238
238
  TYPE_CHECKING,
239
239
  Any,
240
- Callable,
241
- Dict,
242
- Iterable,
243
- List,
244
240
  NoReturn,
245
241
  Optional,
246
242
  Protocol,
247
- Sequence,
248
- Set,
249
- Tuple,
250
- Type,
251
243
  Union,
252
244
  cast,
253
245
  runtime_checkable,
@@ -264,8 +256,8 @@ if TYPE_CHECKING: # pragma: no cover
264
256
  )
265
257
 
266
258
 
267
- def generate_range_error(range_min: int, range_max: Union[int, float]) -> str:
268
- """Generate an error message when the the number of arguments provided is not within the expected range"""
259
+ def generate_range_error(range_min: int, range_max: float) -> str:
260
+ """Generate an error message when the the number of arguments provided is not within the expected range."""
269
261
  err_str = "expected "
270
262
 
271
263
  if range_max == constants.INFINITY:
@@ -283,19 +275,18 @@ def generate_range_error(range_min: int, range_max: Union[int, float]) -> str:
283
275
  return err_str
284
276
 
285
277
 
286
- class CompletionItem(str):
287
- """
288
- Completion item with descriptive text attached
278
+ class CompletionItem(str): # noqa: SLOT000
279
+ """Completion item with descriptive text attached.
289
280
 
290
281
  See header of this file for more information
291
282
  """
292
283
 
293
- def __new__(cls, value: object, *args: Any, **kwargs: Any) -> 'CompletionItem':
294
- return super(CompletionItem, cls).__new__(cls, value)
284
+ def __new__(cls, value: object, *_args: Any, **_kwargs: Any) -> 'CompletionItem':
285
+ """Responsible for creating and returning a new instance, called before __init__ when an object is instantiated."""
286
+ return super().__new__(cls, value)
295
287
 
296
288
  def __init__(self, value: object, description: str = '', *args: Any) -> None:
297
- """
298
- CompletionItem Initializer
289
+ """CompletionItem Initializer.
299
290
 
300
291
  :param value: the value being tab completed
301
292
  :param description: description text to display
@@ -310,7 +301,7 @@ class CompletionItem(str):
310
301
 
311
302
  @property
312
303
  def orig_value(self) -> Any:
313
- """Read-only property for _orig_value"""
304
+ """Read-only property for _orig_value."""
314
305
  return self._orig_value
315
306
 
316
307
 
@@ -321,20 +312,18 @@ class CompletionItem(str):
321
312
 
322
313
  @runtime_checkable
323
314
  class ChoicesProviderFuncBase(Protocol):
324
- """
325
- Function that returns a list of choices in support of tab completion
326
- """
315
+ """Function that returns a list of choices in support of tab completion."""
327
316
 
328
- def __call__(self) -> List[str]: ... # pragma: no cover
317
+ def __call__(self) -> list[str]: # pragma: no cover
318
+ """Enable instances to be called like functions."""
329
319
 
330
320
 
331
321
  @runtime_checkable
332
322
  class ChoicesProviderFuncWithTokens(Protocol):
333
- """
334
- Function that returns a list of choices in support of tab completion and accepts a dictionary of prior arguments.
335
- """
323
+ """Function that returns a list of choices in support of tab completion and accepts a dictionary of prior arguments."""
336
324
 
337
- def __call__(self, *, arg_tokens: Dict[str, List[str]] = {}) -> List[str]: ... # pragma: no cover
325
+ def __call__(self, *, arg_tokens: dict[str, list[str]] = {}) -> list[str]: # pragma: no cover # noqa: B006
326
+ """Enable instances to be called like functions."""
338
327
 
339
328
 
340
329
  ChoicesProviderFunc = Union[ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens]
@@ -342,9 +331,7 @@ ChoicesProviderFunc = Union[ChoicesProviderFuncBase, ChoicesProviderFuncWithToke
342
331
 
343
332
  @runtime_checkable
344
333
  class CompleterFuncBase(Protocol):
345
- """
346
- Function to support tab completion with the provided state of the user prompt
347
- """
334
+ """Function to support tab completion with the provided state of the user prompt."""
348
335
 
349
336
  def __call__(
350
337
  self,
@@ -352,15 +339,13 @@ class CompleterFuncBase(Protocol):
352
339
  line: str,
353
340
  begidx: int,
354
341
  endidx: int,
355
- ) -> List[str]: ... # pragma: no cover
342
+ ) -> list[str]: # pragma: no cover
343
+ """Enable instances to be called like functions."""
356
344
 
357
345
 
358
346
  @runtime_checkable
359
347
  class CompleterFuncWithTokens(Protocol):
360
- """
361
- Function to support tab completion with the provided state of the user prompt and accepts a dictionary of prior
362
- arguments.
363
- """
348
+ """Function to support tab completion with the provided state of the user prompt, accepts a dictionary of prior args."""
364
349
 
365
350
  def __call__(
366
351
  self,
@@ -369,16 +354,17 @@ class CompleterFuncWithTokens(Protocol):
369
354
  begidx: int,
370
355
  endidx: int,
371
356
  *,
372
- arg_tokens: Dict[str, List[str]] = {},
373
- ) -> List[str]: ... # pragma: no cover
357
+ arg_tokens: dict[str, list[str]] = {}, # noqa: B006
358
+ ) -> list[str]: # pragma: no cover
359
+ """Enable instances to be called like functions."""
374
360
 
375
361
 
376
362
  CompleterFunc = Union[CompleterFuncBase, CompleterFuncWithTokens]
377
363
 
378
364
 
379
365
  class ChoicesCallable:
380
- """
381
- Enables using a callable as the choices provider for an argparse argument.
366
+ """Enables using a callable as the choices provider for an argparse argument.
367
+
382
368
  While argparse has the built-in choices attribute, it is limited to an iterable.
383
369
  """
384
370
 
@@ -387,11 +373,11 @@ class ChoicesCallable:
387
373
  is_completer: bool,
388
374
  to_call: Union[CompleterFunc, ChoicesProviderFunc],
389
375
  ) -> None:
390
- """
391
- Initializer
376
+ """Initialize the ChoiceCallable instance.
377
+
392
378
  :param is_completer: True if to_call is a tab completion routine which expects
393
379
  the args: text, line, begidx, endidx
394
- :param to_call: the callable object that will be called to provide choices for the argument
380
+ :param to_call: the callable object that will be called to provide choices for the argument.
395
381
  """
396
382
  self.is_completer = is_completer
397
383
  if is_completer:
@@ -400,27 +386,28 @@ class ChoicesCallable:
400
386
  raise ValueError(
401
387
  'With is_completer set to true, to_call must be either CompleterFunc, CompleterFuncWithTokens'
402
388
  )
403
- else:
404
- if not isinstance(to_call, (ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens)): # pragma: no cover
405
- # runtime checking of Protocols do not currently check the parameters of a function.
406
- raise ValueError(
407
- 'With is_completer set to false, to_call must be either: '
408
- 'ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens'
409
- )
389
+ elif not isinstance(to_call, (ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens)): # pragma: no cover
390
+ # runtime checking of Protocols do not currently check the parameters of a function.
391
+ raise ValueError(
392
+ 'With is_completer set to false, to_call must be either: '
393
+ 'ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens'
394
+ )
410
395
  self.to_call = to_call
411
396
 
412
397
  @property
413
398
  def completer(self) -> CompleterFunc:
399
+ """Retreive the internal Completer function, first type checking to ensure it is the right type."""
414
400
  if not isinstance(self.to_call, (CompleterFuncBase, CompleterFuncWithTokens)): # pragma: no cover
415
401
  # this should've been caught in the constructor, just a backup check
416
- raise ValueError('Function is not a CompleterFunc')
402
+ raise TypeError('Function is not a CompleterFunc')
417
403
  return self.to_call
418
404
 
419
405
  @property
420
406
  def choices_provider(self) -> ChoicesProviderFunc:
407
+ """Retreive the internal ChoicesProvider function, first type checking to ensure it is the right type."""
421
408
  if not isinstance(self.to_call, (ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens)): # pragma: no cover
422
409
  # this should've been caught in the constructor, just a backup check
423
- raise ValueError('Function is not a ChoicesProviderFunc')
410
+ raise TypeError('Function is not a ChoicesProviderFunc')
424
411
  return self.to_call
425
412
 
426
413
 
@@ -446,8 +433,7 @@ ATTR_SUPPRESS_TAB_HINT = 'suppress_tab_hint'
446
433
  # Patch argparse.Action with accessors for choice_callable attribute
447
434
  ############################################################################################################
448
435
  def _action_get_choices_callable(self: argparse.Action) -> Optional[ChoicesCallable]:
449
- """
450
- Get the choices_callable attribute of an argparse Action.
436
+ """Get the choices_callable attribute of an argparse Action.
451
437
 
452
438
  This function is added by cmd2 as a method called ``get_choices_callable()`` to ``argparse.Action`` class.
453
439
 
@@ -463,8 +449,7 @@ setattr(argparse.Action, 'get_choices_callable', _action_get_choices_callable)
463
449
 
464
450
 
465
451
  def _action_set_choices_callable(self: argparse.Action, choices_callable: ChoicesCallable) -> None:
466
- """
467
- Set the choices_callable attribute of an argparse Action.
452
+ """Set the choices_callable attribute of an argparse Action.
468
453
 
469
454
  This function is added by cmd2 as a method called ``_set_choices_callable()`` to ``argparse.Action`` class.
470
455
 
@@ -478,7 +463,7 @@ def _action_set_choices_callable(self: argparse.Action, choices_callable: Choice
478
463
  if self.choices is not None:
479
464
  err_msg = "None of the following parameters can be used alongside a choices parameter:\nchoices_provider, completer"
480
465
  raise (TypeError(err_msg))
481
- elif self.nargs == 0:
466
+ if self.nargs == 0:
482
467
  err_msg = (
483
468
  "None of the following parameters can be used on an action that takes no arguments:\nchoices_provider, completer"
484
469
  )
@@ -494,8 +479,7 @@ def _action_set_choices_provider(
494
479
  self: argparse.Action,
495
480
  choices_provider: ChoicesProviderFunc,
496
481
  ) -> None:
497
- """
498
- Set choices_provider of an argparse Action.
482
+ """Set choices_provider of an argparse Action.
499
483
 
500
484
  This function is added by cmd2 as a method called ``set_choices_callable()`` to ``argparse.Action`` class.
501
485
 
@@ -515,8 +499,7 @@ def _action_set_completer(
515
499
  self: argparse.Action,
516
500
  completer: CompleterFunc,
517
501
  ) -> None:
518
- """
519
- Set completer of an argparse Action.
502
+ """Set completer of an argparse Action.
520
503
 
521
504
  This function is added by cmd2 as a method called ``set_completer()`` to ``argparse.Action`` class.
522
505
 
@@ -536,8 +519,7 @@ setattr(argparse.Action, 'set_completer', _action_set_completer)
536
519
  # Patch argparse.Action with accessors for descriptive_header attribute
537
520
  ############################################################################################################
538
521
  def _action_get_descriptive_header(self: argparse.Action) -> Optional[str]:
539
- """
540
- Get the descriptive_header attribute of an argparse Action.
522
+ """Get the descriptive_header attribute of an argparse Action.
541
523
 
542
524
  This function is added by cmd2 as a method called ``get_descriptive_header()`` to ``argparse.Action`` class.
543
525
 
@@ -553,8 +535,7 @@ setattr(argparse.Action, 'get_descriptive_header', _action_get_descriptive_heade
553
535
 
554
536
 
555
537
  def _action_set_descriptive_header(self: argparse.Action, descriptive_header: Optional[str]) -> None:
556
- """
557
- Set the descriptive_header attribute of an argparse Action.
538
+ """Set the descriptive_header attribute of an argparse Action.
558
539
 
559
540
  This function is added by cmd2 as a method called ``set_descriptive_header()`` to ``argparse.Action`` class.
560
541
 
@@ -572,9 +553,8 @@ setattr(argparse.Action, 'set_descriptive_header', _action_set_descriptive_heade
572
553
  ############################################################################################################
573
554
  # Patch argparse.Action with accessors for nargs_range attribute
574
555
  ############################################################################################################
575
- def _action_get_nargs_range(self: argparse.Action) -> Optional[Tuple[int, Union[int, float]]]:
576
- """
577
- Get the nargs_range attribute of an argparse Action.
556
+ def _action_get_nargs_range(self: argparse.Action) -> Optional[tuple[int, Union[int, float]]]:
557
+ """Get the nargs_range attribute of an argparse Action.
578
558
 
579
559
  This function is added by cmd2 as a method called ``get_nargs_range()`` to ``argparse.Action`` class.
580
560
 
@@ -583,15 +563,14 @@ def _action_get_nargs_range(self: argparse.Action) -> Optional[Tuple[int, Union[
583
563
  :param self: argparse Action being queried
584
564
  :return: The value of nargs_range or None if attribute does not exist
585
565
  """
586
- return cast(Optional[Tuple[int, Union[int, float]]], getattr(self, ATTR_NARGS_RANGE, None))
566
+ return cast(Optional[tuple[int, Union[int, float]]], getattr(self, ATTR_NARGS_RANGE, None))
587
567
 
588
568
 
589
569
  setattr(argparse.Action, 'get_nargs_range', _action_get_nargs_range)
590
570
 
591
571
 
592
- def _action_set_nargs_range(self: argparse.Action, nargs_range: Optional[Tuple[int, Union[int, float]]]) -> None:
593
- """
594
- Set the nargs_range attribute of an argparse Action.
572
+ def _action_set_nargs_range(self: argparse.Action, nargs_range: Optional[tuple[int, Union[int, float]]]) -> None:
573
+ """Set the nargs_range attribute of an argparse Action.
595
574
 
596
575
  This function is added by cmd2 as a method called ``set_nargs_range()`` to ``argparse.Action`` class.
597
576
 
@@ -610,8 +589,7 @@ setattr(argparse.Action, 'set_nargs_range', _action_set_nargs_range)
610
589
  # Patch argparse.Action with accessors for suppress_tab_hint attribute
611
590
  ############################################################################################################
612
591
  def _action_get_suppress_tab_hint(self: argparse.Action) -> bool:
613
- """
614
- Get the suppress_tab_hint attribute of an argparse Action.
592
+ """Get the suppress_tab_hint attribute of an argparse Action.
615
593
 
616
594
  This function is added by cmd2 as a method called ``get_suppress_tab_hint()`` to ``argparse.Action`` class.
617
595
 
@@ -627,8 +605,7 @@ setattr(argparse.Action, 'get_suppress_tab_hint', _action_get_suppress_tab_hint)
627
605
 
628
606
 
629
607
  def _action_set_suppress_tab_hint(self: argparse.Action, suppress_tab_hint: bool) -> None:
630
- """
631
- Set the suppress_tab_hint attribute of an argparse Action.
608
+ """Set the suppress_tab_hint attribute of an argparse Action.
632
609
 
633
610
  This function is added by cmd2 as a method called ``set_suppress_tab_hint()`` to ``argparse.Action`` class.
634
611
 
@@ -647,13 +624,12 @@ setattr(argparse.Action, 'set_suppress_tab_hint', _action_set_suppress_tab_hint)
647
624
  # Allow developers to add custom action attributes
648
625
  ############################################################################################################
649
626
 
650
- CUSTOM_ACTION_ATTRIBS: Set[str] = set()
627
+ CUSTOM_ACTION_ATTRIBS: set[str] = set()
651
628
  _CUSTOM_ATTRIB_PFX = '_attr_'
652
629
 
653
630
 
654
- def register_argparse_argument_parameter(param_name: str, param_type: Optional[Type[Any]]) -> None:
655
- """
656
- Registers a custom argparse argument parameter.
631
+ def register_argparse_argument_parameter(param_name: str, param_type: Optional[type[Any]]) -> None:
632
+ """Register a custom argparse argument parameter.
657
633
 
658
634
  The registered name will then be a recognized keyword parameter to the parser's `add_argument()` function.
659
635
 
@@ -672,15 +648,14 @@ def register_argparse_argument_parameter(param_name: str, param_type: Optional[T
672
648
  getter_name = f'get_{param_name}'
673
649
 
674
650
  def _action_get_custom_parameter(self: argparse.Action) -> Any:
675
- f"""
676
- Get the custom {param_name} attribute of an argparse Action.
651
+ """Get the custom attribute of an argparse Action.
677
652
 
678
- This function is added by cmd2 as a method called ``{getter_name}()`` to ``argparse.Action`` class.
653
+ This function is added by cmd2 as a method called ``get_<param_name>()`` to ``argparse.Action`` class.
679
654
 
680
- To call: ``action.{getter_name}()``
655
+ To call: ``action.get_<param_name>()``
681
656
 
682
657
  :param self: argparse Action being queried
683
- :return: The value of {param_name} or None if attribute does not exist
658
+ :return: The value of the custom attribute or None if attribute does not exist
684
659
  """
685
660
  return getattr(self, attr_name, None)
686
661
 
@@ -689,12 +664,11 @@ def register_argparse_argument_parameter(param_name: str, param_type: Optional[T
689
664
  setter_name = f'set_{param_name}'
690
665
 
691
666
  def _action_set_custom_parameter(self: argparse.Action, value: Any) -> None:
692
- f"""
693
- Set the custom {param_name} attribute of an argparse Action.
667
+ """Set the custom attribute of an argparse Action.
694
668
 
695
- This function is added by cmd2 as a method called ``{setter_name}()`` to ``argparse.Action`` class.
669
+ This function is added by cmd2 as a method called ``set_<param_name>()`` to ``argparse.Action`` class.
696
670
 
697
- To call: ``action.{setter_name}({param_name})``
671
+ To call: ``action.set_<param_name>(<param_value>)``
698
672
 
699
673
  :param self: argparse Action being updated
700
674
  :param value: value being assigned
@@ -720,15 +694,14 @@ orig_actions_container_add_argument = argparse._ActionsContainer.add_argument
720
694
  def _add_argument_wrapper(
721
695
  self: argparse._ActionsContainer,
722
696
  *args: Any,
723
- nargs: Union[int, str, Tuple[int], Tuple[int, int], Tuple[int, float], None] = None,
697
+ nargs: Union[int, str, tuple[int], tuple[int, int], tuple[int, float], None] = None,
724
698
  choices_provider: Optional[ChoicesProviderFunc] = None,
725
699
  completer: Optional[CompleterFunc] = None,
726
700
  suppress_tab_hint: bool = False,
727
701
  descriptive_header: Optional[str] = None,
728
702
  **kwargs: Any,
729
703
  ) -> argparse.Action:
730
- """
731
- Wrapper around _ActionsContainer.add_argument() which supports more settings used by cmd2
704
+ """Wrap ActionsContainer.add_argument() which supports more settings used by cmd2.
732
705
 
733
706
  # Args from original function
734
707
  :param self: instance of the _ActionsContainer being added to
@@ -771,7 +744,7 @@ def _add_argument_wrapper(
771
744
  nargs_range = None
772
745
 
773
746
  if nargs is not None:
774
- nargs_adjusted: Union[int, str, Tuple[int], Tuple[int, int], Tuple[int, float], None]
747
+ nargs_adjusted: Union[int, str, tuple[int], tuple[int, int], tuple[int, float], None]
775
748
  # Check if nargs was given as a range
776
749
  if isinstance(nargs, tuple):
777
750
  # Handle 1-item tuple by setting max to INFINITY
@@ -821,10 +794,7 @@ def _add_argument_wrapper(
821
794
  kwargs['nargs'] = nargs_adjusted
822
795
 
823
796
  # Extract registered custom keyword arguments
824
- custom_attribs: Dict[str, Any] = {}
825
- for keyword, value in kwargs.items():
826
- if keyword in CUSTOM_ACTION_ATTRIBS:
827
- custom_attribs[keyword] = value
797
+ custom_attribs = {keyword: value for keyword, value in kwargs.items() if keyword in CUSTOM_ACTION_ATTRIBS}
828
798
  for keyword in custom_attribs:
829
799
  del kwargs[keyword]
830
800
 
@@ -864,12 +834,8 @@ orig_argument_parser_get_nargs_pattern = argparse.ArgumentParser._get_nargs_patt
864
834
  def _get_nargs_pattern_wrapper(self: argparse.ArgumentParser, action: argparse.Action) -> str:
865
835
  # Wrapper around ArgumentParser._get_nargs_pattern behavior to support nargs ranges
866
836
  nargs_range = action.get_nargs_range() # type: ignore[attr-defined]
867
- if nargs_range is not None:
868
- if nargs_range[1] == constants.INFINITY:
869
- range_max = ''
870
- else:
871
- range_max = nargs_range[1] # type: ignore[assignment]
872
-
837
+ if nargs_range:
838
+ range_max = '' if nargs_range[1] == constants.INFINITY else nargs_range[1]
873
839
  nargs_pattern = f'(-*A{{{nargs_range[0]},{range_max}}}-*)'
874
840
 
875
841
  # if this is an optional action, -- is not allowed
@@ -919,9 +885,8 @@ setattr(argparse.ArgumentParser, '_match_argument', _match_argument_wrapper)
919
885
  ATTR_AP_COMPLETER_TYPE = 'ap_completer_type'
920
886
 
921
887
 
922
- def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> Optional[Type['ArgparseCompleter']]:
923
- """
924
- Get the ap_completer_type attribute of an argparse ArgumentParser.
888
+ def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> Optional[type['ArgparseCompleter']]: # noqa: N802
889
+ """Get the ap_completer_type attribute of an argparse ArgumentParser.
925
890
 
926
891
  This function is added by cmd2 as a method called ``get_ap_completer_type()`` to ``argparse.ArgumentParser`` class.
927
892
 
@@ -930,15 +895,14 @@ def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> Opti
930
895
  :param self: ArgumentParser being queried
931
896
  :return: An ArgparseCompleter-based class or None if attribute does not exist
932
897
  """
933
- return cast(Optional[Type['ArgparseCompleter']], getattr(self, ATTR_AP_COMPLETER_TYPE, None))
898
+ return cast(Optional[type['ArgparseCompleter']], getattr(self, ATTR_AP_COMPLETER_TYPE, None))
934
899
 
935
900
 
936
901
  setattr(argparse.ArgumentParser, 'get_ap_completer_type', _ArgumentParser_get_ap_completer_type)
937
902
 
938
903
 
939
- def _ArgumentParser_set_ap_completer_type(self: argparse.ArgumentParser, ap_completer_type: Type['ArgparseCompleter']) -> None:
940
- """
941
- Set the ap_completer_type attribute of an argparse ArgumentParser.
904
+ def _ArgumentParser_set_ap_completer_type(self: argparse.ArgumentParser, ap_completer_type: type['ArgparseCompleter']) -> None: # noqa: N802
905
+ """Set the ap_completer_type attribute of an argparse ArgumentParser.
942
906
 
943
907
  This function is added by cmd2 as a method called ``set_ap_completer_type()`` to ``argparse.ArgumentParser`` class.
944
908
 
@@ -956,9 +920,9 @@ setattr(argparse.ArgumentParser, 'set_ap_completer_type', _ArgumentParser_set_ap
956
920
  ############################################################################################################
957
921
  # Patch ArgumentParser._check_value to support CompletionItems as choices
958
922
  ############################################################################################################
959
- def _ArgumentParser_check_value(self: argparse.ArgumentParser, action: argparse.Action, value: Any) -> None:
960
- """
961
- Custom override of ArgumentParser._check_value that supports CompletionItems as choices.
923
+ def _ArgumentParser_check_value(_self: argparse.ArgumentParser, action: argparse.Action, value: Any) -> None: # noqa: N802
924
+ """Check_value that supports CompletionItems as choices (Custom override of ArgumentParser._check_value).
925
+
962
926
  When evaluating choices, input is compared to CompletionItem.orig_value instead of the
963
927
  CompletionItem instance.
964
928
 
@@ -989,9 +953,8 @@ setattr(argparse.ArgumentParser, '_check_value', _ArgumentParser_check_value)
989
953
  ############################################################################################################
990
954
 
991
955
 
992
- def _SubParsersAction_remove_parser(self: argparse._SubParsersAction, name: str) -> None: # type: ignore
993
- """
994
- Removes a sub-parser from a sub-parsers group. Used to remove subcommands from a parser.
956
+ def _SubParsersAction_remove_parser(self: argparse._SubParsersAction, name: str) -> None: # type: ignore[type-arg] # noqa: N802
957
+ """Remove a sub-parser from a sub-parsers group. Used to remove subcommands from a parser.
995
958
 
996
959
  This function is added by cmd2 as a method called ``remove_parser()`` to ``argparse._SubParsersAction`` class.
997
960
 
@@ -1029,7 +992,7 @@ setattr(argparse._SubParsersAction, 'remove_parser', _SubParsersAction_remove_pa
1029
992
 
1030
993
 
1031
994
  class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1032
- """Custom help formatter to configure ordering of help text"""
995
+ """Custom help formatter to configure ordering of help text."""
1033
996
 
1034
997
  def _format_usage(
1035
998
  self,
@@ -1043,15 +1006,15 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1043
1006
 
1044
1007
  # if usage is specified, use that
1045
1008
  if usage is not None:
1046
- usage %= dict(prog=self._prog)
1009
+ usage %= {"prog": self._prog}
1047
1010
 
1048
1011
  # if no optionals or positionals are available, usage is just prog
1049
1012
  elif not actions:
1050
- usage = '%(prog)s' % dict(prog=self._prog)
1013
+ usage = f'{self._prog}'
1051
1014
 
1052
1015
  # if optionals and positionals are available, calculate usage
1053
1016
  else:
1054
- prog = '%(prog)s' % dict(prog=self._prog)
1017
+ prog = f'{self._prog}'
1055
1018
 
1056
1019
  # split optionals from positionals
1057
1020
  optionals = []
@@ -1069,8 +1032,8 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1069
1032
  # End cmd2 customization
1070
1033
 
1071
1034
  # build full usage string
1072
- format = self._format_actions_usage
1073
- action_usage = format(required_options + optionals + positionals, groups) # type: ignore[arg-type]
1035
+ format_actions = self._format_actions_usage
1036
+ action_usage = format_actions(required_options + optionals + positionals, groups) # type: ignore[arg-type]
1074
1037
  usage = ' '.join([s for s in [prog, action_usage] if s])
1075
1038
 
1076
1039
  # wrap the usage parts if it's too long
@@ -1080,26 +1043,20 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1080
1043
 
1081
1044
  # break usage into wrappable parts
1082
1045
  part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
1083
- req_usage = format(required_options, groups) # type: ignore[arg-type]
1084
- opt_usage = format(optionals, groups) # type: ignore[arg-type]
1085
- pos_usage = format(positionals, groups) # type: ignore[arg-type]
1046
+ req_usage = format_actions(required_options, groups) # type: ignore[arg-type]
1047
+ opt_usage = format_actions(optionals, groups) # type: ignore[arg-type]
1048
+ pos_usage = format_actions(positionals, groups) # type: ignore[arg-type]
1086
1049
  req_parts = re.findall(part_regexp, req_usage)
1087
1050
  opt_parts = re.findall(part_regexp, opt_usage)
1088
1051
  pos_parts = re.findall(part_regexp, pos_usage)
1089
- assert ' '.join(req_parts) == req_usage
1090
- assert ' '.join(opt_parts) == opt_usage
1091
- assert ' '.join(pos_parts) == pos_usage
1092
1052
 
1093
1053
  # End cmd2 customization
1094
1054
 
1095
1055
  # helper for wrapping lines
1096
- def get_lines(parts: List[str], indent: str, prefix: Optional[str] = None) -> List[str]:
1097
- lines: List[str] = []
1098
- line: List[str] = []
1099
- if prefix is not None:
1100
- line_len = len(prefix) - 1
1101
- else:
1102
- line_len = len(indent) - 1
1056
+ def get_lines(parts: list[str], indent: str, prefix: Optional[str] = None) -> list[str]:
1057
+ lines: list[str] = []
1058
+ line: list[str] = []
1059
+ line_len = len(prefix) - 1 if prefix is not None else len(indent) - 1
1103
1060
  for part in parts:
1104
1061
  if line_len + 1 + len(part) > text_width and line:
1105
1062
  lines.append(indent + ' '.join(line))
@@ -1118,14 +1075,14 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1118
1075
  indent = ' ' * (len(prefix) + len(prog) + 1)
1119
1076
  # Begin cmd2 customization
1120
1077
  if req_parts:
1121
- lines = get_lines([prog] + req_parts, indent, prefix)
1078
+ lines = get_lines([prog, *req_parts], indent, prefix)
1122
1079
  lines.extend(get_lines(opt_parts, indent))
1123
1080
  lines.extend(get_lines(pos_parts, indent))
1124
1081
  elif opt_parts:
1125
- lines = get_lines([prog] + opt_parts, indent, prefix)
1082
+ lines = get_lines([prog, *opt_parts], indent, prefix)
1126
1083
  lines.extend(get_lines(pos_parts, indent))
1127
1084
  elif pos_parts:
1128
- lines = get_lines([prog] + pos_parts, indent, prefix)
1085
+ lines = get_lines([prog, *pos_parts], indent, prefix)
1129
1086
  else:
1130
1087
  lines = [prog]
1131
1088
  # End cmd2 customization
@@ -1142,13 +1099,13 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1142
1099
  lines.extend(get_lines(opt_parts, indent))
1143
1100
  lines.extend(get_lines(pos_parts, indent))
1144
1101
  # End cmd2 customization
1145
- lines = [prog] + lines
1102
+ lines = [prog, *lines]
1146
1103
 
1147
1104
  # join lines into usage
1148
1105
  usage = '\n'.join(lines)
1149
1106
 
1150
1107
  # prefix with 'Usage:'
1151
- return '%s%s\n\n' % (prefix, usage)
1108
+ return f'{prefix}{usage}\n\n'
1152
1109
 
1153
1110
  def _format_action_invocation(self, action: argparse.Action) -> str:
1154
1111
  if not action.option_strings:
@@ -1156,37 +1113,35 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1156
1113
  (metavar,) = self._metavar_formatter(action, default)(1)
1157
1114
  return metavar
1158
1115
 
1159
- else:
1160
- parts: List[str] = []
1116
+ parts: list[str] = []
1161
1117
 
1162
- # if the Optional doesn't take a value, format is:
1163
- # -s, --long
1164
- if action.nargs == 0:
1165
- parts.extend(action.option_strings)
1166
- return ', '.join(parts)
1118
+ # if the Optional doesn't take a value, format is:
1119
+ # -s, --long
1120
+ if action.nargs == 0:
1121
+ parts.extend(action.option_strings)
1122
+ return ', '.join(parts)
1167
1123
 
1168
- # Begin cmd2 customization (less verbose)
1169
- # if the Optional takes a value, format is:
1170
- # -s, --long ARGS
1171
- else:
1172
- default = self._get_default_metavar_for_optional(action)
1173
- args_string = self._format_args(action, default)
1124
+ # Begin cmd2 customization (less verbose)
1125
+ # if the Optional takes a value, format is:
1126
+ # -s, --long ARGS
1127
+ default = self._get_default_metavar_for_optional(action)
1128
+ args_string = self._format_args(action, default)
1174
1129
 
1175
- return ', '.join(action.option_strings) + ' ' + args_string
1176
- # End cmd2 customization
1130
+ return ', '.join(action.option_strings) + ' ' + args_string
1131
+ # End cmd2 customization
1177
1132
 
1178
1133
  def _determine_metavar(
1179
1134
  self,
1180
1135
  action: argparse.Action,
1181
- default_metavar: Union[str, Tuple[str, ...]],
1182
- ) -> Union[str, Tuple[str, ...]]:
1183
- """Custom method to determine what to use as the metavar value of an action"""
1136
+ default_metavar: Union[str, tuple[str, ...]],
1137
+ ) -> Union[str, tuple[str, ...]]:
1138
+ """Determine what to use as the metavar value of an action."""
1184
1139
  if action.metavar is not None:
1185
1140
  result = action.metavar
1186
1141
  elif action.choices is not None:
1187
1142
  choice_strs = [str(choice) for choice in action.choices]
1188
1143
  # Begin cmd2 customization (added space after comma)
1189
- result = '{%s}' % ', '.join(choice_strs)
1144
+ result = f'{", ".join(choice_strs)}'
1190
1145
  # End cmd2 customization
1191
1146
  else:
1192
1147
  result = default_metavar
@@ -1195,48 +1150,44 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
1195
1150
  def _metavar_formatter(
1196
1151
  self,
1197
1152
  action: argparse.Action,
1198
- default_metavar: Union[str, Tuple[str, ...]],
1199
- ) -> Callable[[int], Tuple[str, ...]]:
1153
+ default_metavar: Union[str, tuple[str, ...]],
1154
+ ) -> Callable[[int], tuple[str, ...]]:
1200
1155
  metavar = self._determine_metavar(action, default_metavar)
1201
1156
 
1202
- def format(tuple_size: int) -> Tuple[str, ...]:
1157
+ def format_tuple(tuple_size: int) -> tuple[str, ...]:
1203
1158
  if isinstance(metavar, tuple):
1204
1159
  return metavar
1205
- else:
1206
- return (metavar,) * tuple_size
1160
+ return (metavar,) * tuple_size
1207
1161
 
1208
- return format
1162
+ return format_tuple
1209
1163
 
1210
- def _format_args(self, action: argparse.Action, default_metavar: Union[str, Tuple[str, ...]]) -> str:
1211
- """Customized to handle ranged nargs and make other output less verbose"""
1164
+ def _format_args(self, action: argparse.Action, default_metavar: Union[str, tuple[str, ...]]) -> str:
1165
+ """Handle ranged nargs and make other output less verbose."""
1212
1166
  metavar = self._determine_metavar(action, default_metavar)
1213
1167
  metavar_formatter = self._metavar_formatter(action, default_metavar)
1214
1168
 
1215
1169
  # Handle nargs specified as a range
1216
1170
  nargs_range = action.get_nargs_range() # type: ignore[attr-defined]
1217
1171
  if nargs_range is not None:
1218
- if nargs_range[1] == constants.INFINITY:
1219
- range_str = f'{nargs_range[0]}+'
1220
- else:
1221
- range_str = f'{nargs_range[0]}..{nargs_range[1]}'
1172
+ range_str = f'{nargs_range[0]}+' if nargs_range[1] == constants.INFINITY else f'{nargs_range[0]}..{nargs_range[1]}'
1222
1173
 
1223
- return '{}{{{}}}'.format('%s' % metavar_formatter(1), range_str)
1174
+ return '{}{{{}}}'.format('%s' % metavar_formatter(1), range_str) # noqa: UP031
1224
1175
 
1225
1176
  # Make this output less verbose. Do not customize the output when metavar is a
1226
1177
  # tuple of strings. Allow argparse's formatter to handle that instead.
1227
- elif isinstance(metavar, str):
1178
+ if isinstance(metavar, str):
1228
1179
  if action.nargs == ZERO_OR_MORE:
1229
- return '[%s [...]]' % metavar_formatter(1)
1230
- elif action.nargs == ONE_OR_MORE:
1231
- return '%s [...]' % metavar_formatter(1)
1232
- elif isinstance(action.nargs, int) and action.nargs > 1:
1233
- return '{}{{{}}}'.format('%s' % metavar_formatter(1), action.nargs)
1180
+ return '[%s [...]]' % metavar_formatter(1) # noqa: UP031
1181
+ if action.nargs == ONE_OR_MORE:
1182
+ return '%s [...]' % metavar_formatter(1) # noqa: UP031
1183
+ if isinstance(action.nargs, int) and action.nargs > 1:
1184
+ return '{}{{{}}}'.format('%s' % metavar_formatter(1), action.nargs) # noqa: UP031
1234
1185
 
1235
1186
  return super()._format_args(action, default_metavar) # type: ignore[arg-type]
1236
1187
 
1237
1188
 
1238
1189
  class Cmd2ArgumentParser(argparse.ArgumentParser):
1239
- """Custom ArgumentParser class that improves error and help output"""
1190
+ """Custom ArgumentParser class that improves error and help output."""
1240
1191
 
1241
1192
  def __init__(
1242
1193
  self,
@@ -1245,43 +1196,68 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
1245
1196
  description: Optional[str] = None,
1246
1197
  epilog: Optional[str] = None,
1247
1198
  parents: Sequence[argparse.ArgumentParser] = (),
1248
- formatter_class: Type[argparse.HelpFormatter] = Cmd2HelpFormatter,
1199
+ formatter_class: type[argparse.HelpFormatter] = Cmd2HelpFormatter,
1249
1200
  prefix_chars: str = '-',
1250
1201
  fromfile_prefix_chars: Optional[str] = None,
1251
1202
  argument_default: Optional[str] = None,
1252
1203
  conflict_handler: str = 'error',
1253
1204
  add_help: bool = True,
1254
1205
  allow_abbrev: bool = True,
1206
+ exit_on_error: bool = True,
1207
+ suggest_on_error: bool = False,
1208
+ color: bool = False,
1255
1209
  *,
1256
- ap_completer_type: Optional[Type['ArgparseCompleter']] = None,
1210
+ ap_completer_type: Optional[type['ArgparseCompleter']] = None,
1257
1211
  ) -> None:
1258
- """
1259
- # Custom parameter added by cmd2
1212
+ """Initialize the Cmd2ArgumentParser instance, a custom ArgumentParser added by cmd2.
1260
1213
 
1261
1214
  :param ap_completer_type: optional parameter which specifies a subclass of ArgparseCompleter for custom tab completion
1262
1215
  behavior on this parser. If this is None or not present, then cmd2 will use
1263
1216
  argparse_completer.DEFAULT_AP_COMPLETER when tab completing this parser's arguments
1264
1217
  """
1265
- super(Cmd2ArgumentParser, self).__init__(
1266
- prog=prog,
1267
- usage=usage,
1268
- description=description,
1269
- epilog=epilog,
1270
- parents=parents if parents else [],
1271
- formatter_class=formatter_class, # type: ignore[arg-type]
1272
- prefix_chars=prefix_chars,
1273
- fromfile_prefix_chars=fromfile_prefix_chars,
1274
- argument_default=argument_default,
1275
- conflict_handler=conflict_handler,
1276
- add_help=add_help,
1277
- allow_abbrev=allow_abbrev,
1278
- )
1218
+ if sys.version_info >= (3, 14):
1219
+ # Python >= 3.14 so pass new arguments to parent argparse.ArgumentParser class
1220
+ super().__init__(
1221
+ prog=prog,
1222
+ usage=usage,
1223
+ description=description,
1224
+ epilog=epilog,
1225
+ parents=parents if parents else [],
1226
+ formatter_class=formatter_class, # type: ignore[arg-type]
1227
+ prefix_chars=prefix_chars,
1228
+ fromfile_prefix_chars=fromfile_prefix_chars,
1229
+ argument_default=argument_default,
1230
+ conflict_handler=conflict_handler,
1231
+ add_help=add_help,
1232
+ allow_abbrev=allow_abbrev,
1233
+ exit_on_error=exit_on_error, # added in Python 3.9
1234
+ suggest_on_error=suggest_on_error, # added in Python 3.14
1235
+ color=color, # added in Python 3.14
1236
+ )
1237
+ else:
1238
+ # Python < 3.14, so don't pass new arguments to parent argparse.ArgumentParser class
1239
+ super().__init__(
1240
+ prog=prog,
1241
+ usage=usage,
1242
+ description=description,
1243
+ epilog=epilog,
1244
+ parents=parents if parents else [],
1245
+ formatter_class=formatter_class, # type: ignore[arg-type]
1246
+ prefix_chars=prefix_chars,
1247
+ fromfile_prefix_chars=fromfile_prefix_chars,
1248
+ argument_default=argument_default,
1249
+ conflict_handler=conflict_handler,
1250
+ add_help=add_help,
1251
+ allow_abbrev=allow_abbrev,
1252
+ exit_on_error=exit_on_error, # added in Python 3.9
1253
+ )
1279
1254
 
1280
1255
  self.set_ap_completer_type(ap_completer_type) # type: ignore[attr-defined]
1281
1256
 
1282
- def add_subparsers(self, **kwargs: Any) -> argparse._SubParsersAction: # type: ignore
1283
- """
1284
- Custom override. Sets a default title if one was not given.
1257
+ def add_subparsers(self, **kwargs: Any) -> argparse._SubParsersAction: # type: ignore[type-arg]
1258
+ """Add a subcommand parser.
1259
+
1260
+ Set a default title if one was not given.f
1285
1261
 
1286
1262
  :param kwargs: additional keyword arguments
1287
1263
  :return: argparse Subparser Action
@@ -1292,23 +1268,27 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
1292
1268
  return super().add_subparsers(**kwargs)
1293
1269
 
1294
1270
  def error(self, message: str) -> NoReturn:
1295
- """Custom override that applies custom formatting to the error message"""
1271
+ """Print a usage message, including the message, to sys.stderr and terminates the program with a status code of 2.
1272
+
1273
+ Custom override that applies custom formatting to the error message.
1274
+ """
1296
1275
  lines = message.split('\n')
1297
- linum = 0
1298
1276
  formatted_message = ''
1299
- for line in lines:
1277
+ for linum, line in enumerate(lines):
1300
1278
  if linum == 0:
1301
1279
  formatted_message = 'Error: ' + line
1302
1280
  else:
1303
1281
  formatted_message += '\n ' + line
1304
- linum += 1
1305
1282
 
1306
1283
  self.print_usage(sys.stderr)
1307
1284
  formatted_message = ansi.style_error(formatted_message)
1308
1285
  self.exit(2, f'{formatted_message}\n\n')
1309
1286
 
1310
1287
  def format_help(self) -> str:
1311
- """Copy of format_help() from argparse.ArgumentParser with tweaks to separately display required parameters"""
1288
+ """Return a string containing a help message, including the program usage and information about the arguments.
1289
+
1290
+ Copy of format_help() from argparse.ArgumentParser with tweaks to separately display required parameters.
1291
+ """
1312
1292
  formatter = self._get_formatter()
1313
1293
 
1314
1294
  # usage
@@ -1361,7 +1341,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
1361
1341
  # determine help from format above
1362
1342
  return formatter.format_help() + '\n'
1363
1343
 
1364
- def _print_message(self, message: str, file: Optional[IO[str]] = None) -> None:
1344
+ def _print_message(self, message: str, file: Optional[IO[str]] = None) -> None: # type: ignore[override]
1365
1345
  # Override _print_message to use style_aware_write() since we use ANSI escape characters to support color
1366
1346
  if message:
1367
1347
  if file is None:
@@ -1370,32 +1350,34 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
1370
1350
 
1371
1351
 
1372
1352
  class Cmd2AttributeWrapper:
1373
- """
1374
- Wraps a cmd2-specific attribute added to an argparse Namespace.
1353
+ """Wraps a cmd2-specific attribute added to an argparse Namespace.
1354
+
1375
1355
  This makes it easy to know which attributes in a Namespace are
1376
1356
  arguments from a parser and which were added by cmd2.
1377
1357
  """
1378
1358
 
1379
1359
  def __init__(self, attribute: Any) -> None:
1360
+ """Initialize Cmd2AttributeWrapper instances."""
1380
1361
  self.__attribute = attribute
1381
1362
 
1382
1363
  def get(self) -> Any:
1383
- """Get the value of the attribute"""
1364
+ """Get the value of the attribute."""
1384
1365
  return self.__attribute
1385
1366
 
1386
1367
  def set(self, new_val: Any) -> None:
1387
- """Set the value of the attribute"""
1368
+ """Set the value of the attribute."""
1388
1369
  self.__attribute = new_val
1389
1370
 
1390
1371
 
1391
1372
  # The default ArgumentParser class for a cmd2 app
1392
- DEFAULT_ARGUMENT_PARSER: Type[argparse.ArgumentParser] = Cmd2ArgumentParser
1373
+ DEFAULT_ARGUMENT_PARSER: type[argparse.ArgumentParser] = Cmd2ArgumentParser
1393
1374
 
1394
1375
 
1395
- def set_default_argument_parser_type(parser_type: Type[argparse.ArgumentParser]) -> None:
1396
- """
1397
- Set the default ArgumentParser class for a cmd2 app. This must be called prior to loading cmd2.py if
1398
- you want to override the parser for cmd2's built-in commands. See examples/override_parser.py.
1376
+ def set_default_argument_parser_type(parser_type: type[argparse.ArgumentParser]) -> None:
1377
+ """Set the default ArgumentParser class for a cmd2 app.
1378
+
1379
+ This must be called prior to loading cmd2.py if you want to override the parser for cmd2's built-in commands.
1380
+ See examples/override_parser.py.
1399
1381
  """
1400
- global DEFAULT_ARGUMENT_PARSER
1382
+ global DEFAULT_ARGUMENT_PARSER # noqa: PLW0603
1401
1383
  DEFAULT_ARGUMENT_PARSER = parser_type