cmd2 2.6.0__py3-none-any.whl → 2.6.2__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/cmd2.py CHANGED
@@ -144,6 +144,7 @@ from .table_creator import (
144
144
  from .utils import (
145
145
  Settable,
146
146
  get_defining_class,
147
+ get_types,
147
148
  strip_doc_annotations,
148
149
  suggest_similar,
149
150
  )
@@ -253,17 +254,11 @@ class _CommandParsers:
253
254
  command = command_method.__name__[len(COMMAND_FUNC_PREFIX) :]
254
255
 
255
256
  parser_builder = getattr(command_method, constants.CMD_ATTR_ARGPARSER, None)
256
- parent = self._cmd.find_commandset_for_command(command) or self._cmd
257
- parser = self._cmd._build_parser(parent, parser_builder)
258
- if parser is None:
257
+ if parser_builder is None:
259
258
  return None
260
259
 
261
- # argparser defaults the program name to sys.argv[0], but we want it to be the name of our command
262
- from .decorators import (
263
- _set_parser_prog,
264
- )
265
-
266
- _set_parser_prog(parser, command)
260
+ parent = self._cmd.find_commandset_for_command(command) or self._cmd
261
+ parser = self._cmd._build_parser(parent, parser_builder, command)
267
262
 
268
263
  # If the description has not been set, then use the method docstring if one exists
269
264
  if parser.description is None and hasattr(command_method, '__wrapped__') and command_method.__wrapped__.__doc__:
@@ -757,24 +752,41 @@ class Cmd(cmd.Cmd):
757
752
  def _build_parser(
758
753
  self,
759
754
  parent: CommandParent,
760
- parser_builder: Optional[
761
- Union[
762
- argparse.ArgumentParser,
763
- Callable[[], argparse.ArgumentParser],
764
- StaticArgParseBuilder,
765
- ClassArgParseBuilder,
766
- ]
755
+ parser_builder: Union[
756
+ argparse.ArgumentParser,
757
+ Callable[[], argparse.ArgumentParser],
758
+ StaticArgParseBuilder,
759
+ ClassArgParseBuilder,
767
760
  ],
768
- ) -> Optional[argparse.ArgumentParser]:
769
- parser: Optional[argparse.ArgumentParser] = None
761
+ prog: str,
762
+ ) -> argparse.ArgumentParser:
763
+ """Build argument parser for a command/subcommand.
764
+
765
+ :param parent: CommandParent object which owns the command using the parser.
766
+ This function assumes that parent is where parser_builder
767
+ is defined when parser_builder is a classmethod.
768
+ :param parser_builder: means used to build the parser
769
+ :param prog: prog value to set in new parser
770
+ :return: new parser
771
+ :raises TypeError: if parser_builder is invalid type
772
+ """
770
773
  if isinstance(parser_builder, staticmethod):
771
774
  parser = parser_builder.__func__()
772
775
  elif isinstance(parser_builder, classmethod):
773
- parser = parser_builder.__func__(parent if not None else self) # type: ignore[arg-type]
776
+ parser = parser_builder.__func__(parent.__class__)
774
777
  elif callable(parser_builder):
775
778
  parser = parser_builder()
776
779
  elif isinstance(parser_builder, argparse.ArgumentParser):
777
780
  parser = copy.deepcopy(parser_builder)
781
+ else:
782
+ raise TypeError(f"Invalid type for parser_builder: {type(parser_builder)}")
783
+
784
+ from .decorators import (
785
+ _set_parser_prog,
786
+ )
787
+
788
+ _set_parser_prog(parser, prog)
789
+
778
790
  return parser
779
791
 
780
792
  def _install_command_function(self, command_func_name: str, command_method: CommandFunc, context: str = '') -> None:
@@ -962,12 +974,7 @@ class Cmd(cmd.Cmd):
962
974
 
963
975
  target_parser = find_subcommand(command_parser, subcommand_names)
964
976
 
965
- subcmd_parser = cast(argparse.ArgumentParser, self._build_parser(cmdset, subcmd_parser_builder))
966
- from .decorators import (
967
- _set_parser_prog,
968
- )
969
-
970
- _set_parser_prog(subcmd_parser, f'{command_name} {subcommand_name}')
977
+ subcmd_parser = self._build_parser(cmdset, subcmd_parser_builder, f'{command_name} {subcommand_name}')
971
978
  if subcmd_parser.description is None and method.__doc__:
972
979
  subcmd_parser.description = strip_doc_annotations(method.__doc__)
973
980
 
@@ -2609,7 +2616,7 @@ class Cmd(cmd.Cmd):
2609
2616
  # caused by certain binary characters having been printed to it.
2610
2617
  import subprocess
2611
2618
 
2612
- proc = subprocess.Popen(['stty', 'sane']) # noqa: S603, S607
2619
+ proc = subprocess.Popen(['stty', 'sane']) # noqa: S607
2613
2620
  proc.communicate()
2614
2621
 
2615
2622
  data = plugin.CommandFinalizationData(stop, statement)
@@ -3597,8 +3604,8 @@ class Cmd(cmd.Cmd):
3597
3604
  max_arg_num = 0
3598
3605
  arg_nums = set()
3599
3606
 
3600
- while True:
3601
- try:
3607
+ try:
3608
+ while True:
3602
3609
  cur_match = normal_matches.__next__()
3603
3610
 
3604
3611
  # Get the number string between the braces
@@ -3612,9 +3619,8 @@ class Cmd(cmd.Cmd):
3612
3619
  max_arg_num = max(max_arg_num, cur_num)
3613
3620
 
3614
3621
  arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=False))
3615
-
3616
- except StopIteration:
3617
- break
3622
+ except StopIteration:
3623
+ pass
3618
3624
 
3619
3625
  # Make sure the argument numbers are continuous
3620
3626
  if len(arg_nums) != max_arg_num:
@@ -3624,16 +3630,16 @@ class Cmd(cmd.Cmd):
3624
3630
  # Find all escaped arguments
3625
3631
  escaped_matches = re.finditer(MacroArg.macro_escaped_arg_pattern, value)
3626
3632
 
3627
- while True:
3628
- try:
3633
+ try:
3634
+ while True:
3629
3635
  cur_match = escaped_matches.__next__()
3630
3636
 
3631
3637
  # Get the number string between the braces
3632
3638
  cur_num_str = re.findall(MacroArg.digit_pattern, cur_match.group())[0]
3633
3639
 
3634
3640
  arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=True))
3635
- except StopIteration:
3636
- break
3641
+ except StopIteration:
3642
+ pass
3637
3643
 
3638
3644
  # Set the macro
3639
3645
  result = "overwritten" if args.name in self.macros else "created"
@@ -5545,10 +5551,10 @@ class Cmd(cmd.Cmd):
5545
5551
  def _validate_prepostloop_callable(cls, func: Callable[[], None]) -> None:
5546
5552
  """Check parameter and return types for preloop and postloop hooks."""
5547
5553
  cls._validate_callable_param_count(func, 0)
5548
- # make sure there is no return notation
5549
- signature = inspect.signature(func)
5550
- if signature.return_annotation is not None:
5551
- raise TypeError(f"{func.__name__} must declare return a return type of 'None'")
5554
+ # make sure there is no return annotation or the return is specified as None
5555
+ _, ret_ann = get_types(func)
5556
+ if ret_ann is not None:
5557
+ raise TypeError(f"{func.__name__} must have a return type of 'None', got: {ret_ann}")
5552
5558
 
5553
5559
  def register_preloop_hook(self, func: Callable[[], None]) -> None:
5554
5560
  """Register a function to be called at the beginning of the command loop."""
@@ -5564,11 +5570,13 @@ class Cmd(cmd.Cmd):
5564
5570
  def _validate_postparsing_callable(cls, func: Callable[[plugin.PostparsingData], plugin.PostparsingData]) -> None:
5565
5571
  """Check parameter and return types for postparsing hooks."""
5566
5572
  cls._validate_callable_param_count(cast(Callable[..., Any], func), 1)
5567
- signature = inspect.signature(func)
5568
- _, param = next(iter(signature.parameters.items()))
5569
- if param.annotation != plugin.PostparsingData:
5573
+ type_hints, ret_ann = get_types(func)
5574
+ if not type_hints:
5575
+ raise TypeError(f"{func.__name__} parameter is missing a type hint, expected: 'cmd2.plugin.PostparsingData'")
5576
+ par_ann = next(iter(type_hints.values()))
5577
+ if par_ann != plugin.PostparsingData:
5570
5578
  raise TypeError(f"{func.__name__} must have one parameter declared with type 'cmd2.plugin.PostparsingData'")
5571
- if signature.return_annotation != plugin.PostparsingData:
5579
+ if ret_ann != plugin.PostparsingData:
5572
5580
  raise TypeError(f"{func.__name__} must declare return a return type of 'cmd2.plugin.PostparsingData'")
5573
5581
 
5574
5582
  def register_postparsing_hook(self, func: Callable[[plugin.PostparsingData], plugin.PostparsingData]) -> None:
@@ -5583,21 +5591,21 @@ class Cmd(cmd.Cmd):
5583
5591
  cls, func: Callable[[CommandDataType], CommandDataType], data_type: type[CommandDataType]
5584
5592
  ) -> None:
5585
5593
  """Check parameter and return types for pre and post command hooks."""
5586
- signature = inspect.signature(func)
5587
5594
  # validate that the callable has the right number of parameters
5588
5595
  cls._validate_callable_param_count(cast(Callable[..., Any], func), 1)
5596
+
5597
+ type_hints, ret_ann = get_types(func)
5598
+ if not type_hints:
5599
+ raise TypeError(f"{func.__name__} parameter is missing a type hint, expected: {data_type}")
5600
+ param_name, par_ann = next(iter(type_hints.items()))
5589
5601
  # validate the parameter has the right annotation
5590
- paramname = next(iter(signature.parameters.keys()))
5591
- param = signature.parameters[paramname]
5592
- if param.annotation != data_type:
5593
- raise TypeError(f'argument 1 of {func.__name__} has incompatible type {param.annotation}, expected {data_type}')
5602
+ if par_ann != data_type:
5603
+ raise TypeError(f'argument 1 of {func.__name__} has incompatible type {par_ann}, expected {data_type}')
5594
5604
  # validate the return value has the right annotation
5595
- if signature.return_annotation == signature.empty:
5605
+ if ret_ann is None:
5596
5606
  raise TypeError(f'{func.__name__} does not have a declared return type, expected {data_type}')
5597
- if signature.return_annotation != data_type:
5598
- raise TypeError(
5599
- f'{func.__name__} has incompatible return type {signature.return_annotation}, expected {data_type}'
5600
- )
5607
+ if ret_ann != data_type:
5608
+ raise TypeError(f'{func.__name__} has incompatible return type {ret_ann}, expected {data_type}')
5601
5609
 
5602
5610
  def register_precmd_hook(self, func: Callable[[plugin.PrecommandData], plugin.PrecommandData]) -> None:
5603
5611
  """Register a hook to be called before the command function."""
@@ -5615,12 +5623,16 @@ class Cmd(cmd.Cmd):
5615
5623
  ) -> None:
5616
5624
  """Check parameter and return types for command finalization hooks."""
5617
5625
  cls._validate_callable_param_count(func, 1)
5618
- signature = inspect.signature(func)
5619
- _, param = next(iter(signature.parameters.items()))
5620
- if param.annotation != plugin.CommandFinalizationData:
5621
- raise TypeError(f"{func.__name__} must have one parameter declared with type {plugin.CommandFinalizationData}")
5622
- if signature.return_annotation != plugin.CommandFinalizationData:
5623
- raise TypeError("{func.__name__} must declare return a return type of {plugin.CommandFinalizationData}")
5626
+ type_hints, ret_ann = get_types(func)
5627
+ if not type_hints:
5628
+ raise TypeError(f"{func.__name__} parameter is missing a type hint, expected: {plugin.CommandFinalizationData}")
5629
+ _, par_ann = next(iter(type_hints.items()))
5630
+ if par_ann != plugin.CommandFinalizationData:
5631
+ raise TypeError(
5632
+ f"{func.__name__} must have one parameter declared with type {plugin.CommandFinalizationData}, got: {par_ann}"
5633
+ )
5634
+ if ret_ann != plugin.CommandFinalizationData:
5635
+ raise TypeError(f"{func.__name__} must declare return a return type of {plugin.CommandFinalizationData}")
5624
5636
 
5625
5637
  def register_cmdfinalization_hook(
5626
5638
  self, func: Callable[[plugin.CommandFinalizationData], plugin.CommandFinalizationData]
cmd2/decorators.py CHANGED
@@ -393,6 +393,14 @@ def with_argparser(
393
393
 
394
394
  command_name = func.__name__[len(constants.COMMAND_FUNC_PREFIX) :]
395
395
 
396
+ if isinstance(parser, argparse.ArgumentParser):
397
+ # Set parser's prog value for backward compatibility within the cmd2 2.0 family.
398
+ # This will be removed in cmd2 3.0 since we never reference this parser object's prog value.
399
+ # Since it's possible for the same parser object to be passed into multiple with_argparser()
400
+ # calls, we only set prog on the deep copies of this parser based on the specific do_xxxx
401
+ # instance method they are associated with.
402
+ _set_parser_prog(parser, command_name)
403
+
396
404
  # Set some custom attributes for this command
397
405
  setattr(cmd_wrapper, constants.CMD_ATTR_ARGPARSER, parser)
398
406
  setattr(cmd_wrapper, constants.CMD_ATTR_PRESERVE_QUOTES, preserve_quotes)
cmd2/utils.py CHANGED
@@ -14,29 +14,12 @@ import sys
14
14
  import threading
15
15
  import unicodedata
16
16
  from collections.abc import Callable, Iterable
17
- from difflib import (
18
- SequenceMatcher,
19
- )
20
- from enum import (
21
- Enum,
22
- )
23
- from typing import (
24
- TYPE_CHECKING,
25
- Any,
26
- Optional,
27
- TextIO,
28
- TypeVar,
29
- Union,
30
- cast,
31
- )
32
-
33
- from . import (
34
- constants,
35
- )
36
- from .argparse_custom import (
37
- ChoicesProviderFunc,
38
- CompleterFunc,
39
- )
17
+ from difflib import SequenceMatcher
18
+ from enum import Enum
19
+ from typing import TYPE_CHECKING, Any, Optional, TextIO, TypeVar, Union, cast, get_type_hints
20
+
21
+ from . import constants
22
+ from .argparse_custom import ChoicesProviderFunc, CompleterFunc
40
23
 
41
24
  if TYPE_CHECKING: # pragma: no cover
42
25
  import cmd2 # noqa: F401
@@ -1261,3 +1244,27 @@ def suggest_similar(
1261
1244
  best_simil = simil
1262
1245
  proposed_command = each
1263
1246
  return proposed_command
1247
+
1248
+
1249
+ def get_types(func_or_method: Callable[..., Any]) -> tuple[dict[str, Any], Any]:
1250
+ """Use typing.get_type_hints() to extract type hints for parameters and return value.
1251
+
1252
+ This exists because the inspect module doesn't have a safe way of doing this that works
1253
+ both with and without importing annotations from __future__ until Python 3.10.
1254
+
1255
+ TODO: Once cmd2 only supports Python 3.10+, change to use inspect.get_annotations(eval_str=True)
1256
+
1257
+ :param func_or_method: Function or method to return the type hints for
1258
+ :return tuple with first element being dictionary mapping param names to type hints
1259
+ and second element being return type hint, unspecified, returns None
1260
+ """
1261
+ try:
1262
+ type_hints = get_type_hints(func_or_method) # Get dictionary of type hints
1263
+ except TypeError as exc:
1264
+ raise ValueError("Argument passed to get_types should be a function or method") from exc
1265
+ ret_ann = type_hints.pop('return', None) # Pop off the return annotation if it exists
1266
+ if inspect.ismethod(func_or_method):
1267
+ type_hints.pop('self', None) # Pop off `self` hint for methods
1268
+ if ret_ann is type(None):
1269
+ ret_ann = None # Simplify logic to just return None instead of NoneType
1270
+ return type_hints, ret_ann
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 2.6.0
3
+ Version: 2.6.2
4
4
  Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
5
5
  Author: cmd2 Contributors
6
6
  License: The MIT License (MIT)
7
7
 
8
- Copyright (c) 2008-2024 Catherine Devlin and others
8
+ Copyright (c) 2008-2025 Catherine Devlin and others
9
9
 
10
10
  Permission is hereby granted, free of charge, to any person obtaining a copy
11
11
  of this software and associated documentation files (the "Software"), to deal
@@ -39,6 +39,7 @@ Classifier: Programming Language :: Python :: 3.11
39
39
  Classifier: Programming Language :: Python :: 3.12
40
40
  Classifier: Programming Language :: Python :: 3.13
41
41
  Classifier: Programming Language :: Python :: 3.14
42
+ Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
42
43
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
43
44
  Requires-Python: >=3.9
44
45
  Description-Content-Type: text/markdown
@@ -80,22 +81,22 @@ when using cmd.
80
81
 
81
82
  ![system schema](https://raw.githubusercontent.com/python-cmd2/cmd2/master/.github/images/graph.drawio.png)
82
83
 
83
- When creating solutions developers have no shortage of tools to create rich and smart user interfaces.
84
- System administrators have long been duct taping together brittle workflows based on a menagerie of simple command line
85
- tools created by strangers on github and the guy down the hall.
86
- Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to fade quickly.
87
- On the other hand, Web and traditional desktop GUIs are first in class when it comes to easily discovering
88
- functionality.
89
- The price we pay for beautifully colored displays is complexity required to aggregate disperate applications into larger
90
- systems.
91
- `cmd2` fills the niche between high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and
92
- smart workflow automation systems.
93
-
94
- The `cmd2` framework provides a great mixture of both worlds. Application designers can easily create complex
95
- applications and rely on the cmd2 library to offer effortless user facing help and extensive tab completion.
96
- When users become comfortable with functionality, cmd2 turns into a feature rich library enabling a smooth transition to
97
- full automation. If designed with enough forethought, a well implemented cmd2 application can serve as a boutique
98
- workflow tool. `cmd2` pulls off this flexibility based on two pillars of philosophy:
84
+ When creating solutions developers have no shortage of tools to create rich and smart user
85
+ interfaces. System administrators have long been duct taping together brittle workflows based on a
86
+ menagerie of simple command line tools created by strangers on github and the guy down the hall.
87
+ Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to
88
+ fade quickly. On the other hand, Web and traditional desktop GUIs are first in class when it comes
89
+ to easily discovering functionality. The price we pay for beautifully colored displays is complexity
90
+ required to aggregate disperate applications into larger systems. `cmd2` fills the niche between
91
+ high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and smart
92
+ workflow automation systems.
93
+
94
+ The `cmd2` framework provides a great mixture of both worlds. Application designers can easily
95
+ create complex applications and rely on the cmd2 library to offer effortless user facing help and
96
+ extensive tab completion. When users become comfortable with functionality, cmd2 turns into a
97
+ feature rich library enabling a smooth transition to full automation. If designed with enough
98
+ forethought, a well implemented cmd2 application can serve as a boutique workflow tool. `cmd2` pulls
99
+ off this flexibility based on two pillars of philosophy:
99
100
 
100
101
  - Tab Completion
101
102
  - Automation Transition
@@ -104,8 +105,8 @@ workflow tool. `cmd2` pulls off this flexibility based on two pillars of philoso
104
105
 
105
106
  <a href="https://imgflip.com/i/63h03x"><img src="https://i.imgflip.com/63h03x.jpg" title="made at imgflip.com" width="70%" height="%70"/></a>
106
107
 
107
- Deep extensive tab completion and help text generation based on the argparse library create the first pillar of 'ease of
108
- command discovery'. The following is a list of features in this category.
108
+ Deep extensive tab completion and help text generation based on the argparse library create the
109
+ first pillar of 'ease of command discovery'. The following is a list of features in this category.
109
110
 
110
111
  - Great tab completion of commands, subcommands, file system paths, and shell commands.
111
112
  - Custom tab completion for user designed commands via simple function overloading.
@@ -116,13 +117,15 @@ command discovery'. The following is a list of features in this category.
116
117
 
117
118
  <a href="https://imgflip.com/i/66t0y0"><img src="https://i.imgflip.com/66t0y0.jpg" title="made at imgflip.com" width="70%" height="70%"/></a>
118
119
 
119
- cmd2 creates the second pillar of 'ease of transition to automation' through alias/macro creation, command line argument
120
- parsing and execution of cmd2 scripting.
120
+ cmd2 creates the second pillar of 'ease of transition to automation' through alias/macro creation,
121
+ command line argument parsing and execution of cmd2 scripting.
121
122
 
122
123
  - Flexible alias and macro creation for quick abstraction of commands.
123
124
  - Text file scripting of your application with `run_script` (`@`) and `_relative_run_script` (`@@`)
124
- - Powerful and flexible built-in Python scripting of your application using the `run_pyscript` command
125
- - Transcripts for use with built-in regression can be automatically generated from `history -t` or `run_script -t`
125
+ - Powerful and flexible built-in Python scripting of your application using the `run_pyscript`
126
+ command
127
+ - Transcripts for use with built-in regression can be automatically generated from `history -t` or
128
+ `run_script -t`
126
129
 
127
130
  ## Installation
128
131
 
@@ -132,11 +135,12 @@ On all operating systems, the latest stable version of `cmd2` can be installed u
132
135
  pip install -U cmd2
133
136
  ```
134
137
 
135
- cmd2 works with Python 3.9+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party dependencies.
138
+ cmd2 works with Python 3.9+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party
139
+ dependencies. It works with both conventional CPython and free-threaded variants.
136
140
 
137
141
  For information on other installation options, see
138
- [Installation Instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html) in the cmd2
139
- documentation.
142
+ [Installation Instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html) in the
143
+ cmd2 documentation.
140
144
 
141
145
  ## Documentation
142
146
 
@@ -144,7 +148,8 @@ The latest documentation for cmd2 can be read online here: https://cmd2.readthed
144
148
 
145
149
  It is available in HTML, PDF, and ePub formats.
146
150
 
147
- The best way to learn the cmd2 api is to delve into the example applications located in source under examples.
151
+ The best way to learn the cmd2 api is to delve into the example applications located in source under
152
+ examples.
148
153
 
149
154
  ## Tutorials
150
155
 
@@ -153,13 +158,15 @@ The best way to learn the cmd2 api is to delve into the example applications loc
153
158
  - [slides](https://github.com/python-cmd2/talks/blob/master/PyOhio_2019/cmd2-PyOhio_2019.pdf)
154
159
  - [example code](https://github.com/python-cmd2/talks/tree/master/PyOhio_2019/examples)
155
160
  - [Cookiecutter](https://github.com/cookiecutter/cookiecutter) Templates from community
156
- - Basic cookiecutter template for cmd2 application : https://github.com/jayrod/cookiecutter-python-cmd2
157
- - Advanced cookiecutter template with external plugin
158
- support : https://github.com/jayrod/cookiecutter-python-cmd2-ext-plug
161
+ - Basic cookiecutter template for cmd2 application :
162
+ https://github.com/jayrod/cookiecutter-python-cmd2
163
+ - Advanced cookiecutter template with external plugin support :
164
+ https://github.com/jayrod/cookiecutter-python-cmd2-ext-plug
159
165
  - [cmd2 example applications](https://github.com/python-cmd2/cmd2/tree/master/examples)
160
166
  - Basic cmd2 examples to demonstrate how to use various features
161
167
  - [Advanced Examples](https://github.com/jayrod/cmd2-example-apps)
162
- - More complex examples that demonstrate more featuers about how to put together a complete application
168
+ - More complex examples that demonstrate more featuers about how to put together a complete
169
+ application
163
170
 
164
171
  ## Hello World
165
172
 
@@ -187,10 +194,10 @@ if __name__ == '__main__':
187
194
 
188
195
  ## Found a bug?
189
196
 
190
- If you think you've found a bug, please first read through the
191
- open [Issues](https://github.com/python-cmd2/cmd2/issues). If you're confident it's a new bug, go ahead and create a new
192
- GitHub issue. Be sure to include as much information as possible so we can reproduce the bug. At a minimum, please state
193
- the following:
197
+ If you think you've found a bug, please first read through the open
198
+ [Issues](https://github.com/python-cmd2/cmd2/issues). If you're confident it's a new bug, go ahead
199
+ and create a new GitHub issue. Be sure to include as much information as possible so we can
200
+ reproduce the bug. At a minimum, please state the following:
194
201
 
195
202
  - `cmd2` version
196
203
  - Python version
@@ -232,4 +239,5 @@ Possibly defunct but still good examples
232
239
  | [FLASHMINGO](https://github.com/mandiant/flashmingo) | Automatic analysis of SWF files based on some heuristics. Extensible via plugins. | [Mandiant](https://github.com/mandiant) |
233
240
  | [psiTurk](https://github.com/NYUCCL/psiTurk) | An open platform for science on Amazon Mechanical Turk | [NYU Computation and Cognition Lab](https://github.com/NYUCCL) |
234
241
 
235
- Note: If you have created an application based on `cmd2` that you would like us to mention here, please get in touch.
242
+ Note: If you have created an application based on `cmd2` that you would like us to mention here,
243
+ please get in touch.
@@ -3,10 +3,10 @@ cmd2/ansi.py,sha256=XwBvFnB51LYYjIpfEge6mcr5X63dUxiV0aJlOOJ_2tQ,31965
3
3
  cmd2/argparse_completer.py,sha256=F_5hiX9fYpEhV42mz7v7qeS7KuInAS6xU6KekLxYzsQ,35863
4
4
  cmd2/argparse_custom.py,sha256=Q7N-2TSctfjn3TEZezQNaT5y0w8sdGpmUA5_DCPa_Pk,59131
5
5
  cmd2/clipboard.py,sha256=HLZWY-W3mkpF_OqQet-F8pS3rlXpiE5vxUyPV_yHvIU,507
6
- cmd2/cmd2.py,sha256=7U-uTdWSMumFjvDIYUvd5V0Bg87Av9V4yG-aODUTr-Q,261285
6
+ cmd2/cmd2.py,sha256=-LkAwuakQGF_oZTUsmtQfPTILtCT-F7LNE7Ej2l9PVc,261740
7
7
  cmd2/command_definition.py,sha256=_wF39nig5MP0grSOZ1hFehP5fCGusUNHMn9PIs6pmcU,7648
8
8
  cmd2/constants.py,sha256=duEqGhhvdUV7AYxE8VGZ4wyFBcN2y2bLPd5iefW4tSU,1943
9
- cmd2/decorators.py,sha256=9Jiml8HGc-UyUtWTns3TwW8ZHte4NchfGgHe-_1CcDM,20075
9
+ cmd2/decorators.py,sha256=t0gBy3aRz5ke0jHyP5YOszdQ61t5aV8j0eNyLPX6hmg,20644
10
10
  cmd2/exceptions.py,sha256=fYciAnLCpvPYkXCtmADhxtcvjbxVagRjhp41eYwAQo8,3444
11
11
  cmd2/history.py,sha256=elJPuvV7BnUEgpWnixNyl2yGtR6sz3nwvpyFwaeFqRA,14800
12
12
  cmd2/parsing.py,sha256=BsyQTTkuEg4FiQP9o2O28KjXodFgXkXmvk_VkAe-Ryw,28057
@@ -16,9 +16,9 @@ cmd2/py_bridge.py,sha256=TKl2d7sgptDdccuO1PWG8m83Nww2bGCzsY4_wqjKTjg,4935
16
16
  cmd2/rl_utils.py,sha256=sWapqwDR_GvOgy5NJ7c-i6nUU4dqpKpGQ8-Olwi3tuU,11335
17
17
  cmd2/table_creator.py,sha256=nF3VEgGHvfhHBh_yoMAiV1WaDdR8hIareIAogzIPq5M,47177
18
18
  cmd2/transcript.py,sha256=Ws0lW_oBFxCQCKSwvnDUS1x3ya163YXnV-O5aTU0z7k,9207
19
- cmd2/utils.py,sha256=vY4JdnTbKJ2nhkDva_4Jiw1RY7eOoqkcinP6sVhgLyU,49486
20
- cmd2-2.6.0.dist-info/licenses/LICENSE,sha256=QXrW0Z0merk9mncyUkn-sgRxhT8_o1dL5HEaBNH47Q4,1099
21
- cmd2-2.6.0.dist-info/METADATA,sha256=k_YfbO5kXJByal_dPlrs6B3dbtKI1DizrDoX8Qd5xzc,17133
22
- cmd2-2.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- cmd2-2.6.0.dist-info/top_level.txt,sha256=gJbOJmyrARwLhm5diXAtzlNQdxbDZ8iRJ8HJi65_5hg,5
24
- cmd2-2.6.0.dist-info/RECORD,,
19
+ cmd2/utils.py,sha256=NqDIkY4LiAlnv_Un7MFHxszoH2KgEWQ7NJOwQurIn_E,50698
20
+ cmd2-2.6.2.dist-info/licenses/LICENSE,sha256=9qPeHY4u2fkSz0JQGT-P4T3QqTWTqnQJ_8LkZUhSdFY,1099
21
+ cmd2-2.6.2.dist-info/METADATA,sha256=PXmEeU5Cspekoxefr9LjKqHJ44zXV4hUdwGUrBTeygs,17292
22
+ cmd2-2.6.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ cmd2-2.6.2.dist-info/top_level.txt,sha256=gJbOJmyrARwLhm5diXAtzlNQdxbDZ8iRJ8HJi65_5hg,5
24
+ cmd2-2.6.2.dist-info/RECORD,,
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2008-2024 Catherine Devlin and others
3
+ Copyright (c) 2008-2025 Catherine Devlin and others
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
File without changes