summaryrefslogtreecommitdiff
path: root/cmd2/utils.py
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2021-02-20 16:28:30 -0500
committerGitHub <noreply@github.com>2021-02-20 16:28:30 -0500
commita7119e1b26a8bae531b118b7cb8c4b195f731df6 (patch)
tree46b53d0f530d6ae273c4379272684ee80026658a /cmd2/utils.py
parent06aaf962689840631325c70ea7e9056d176c7f67 (diff)
parent486b8c726a7d657ef320e68598077c31fa664790 (diff)
downloadcmd2-git-a7119e1b26a8bae531b118b7cb8c4b195f731df6.tar.gz
Merge pull request #1052 from python-cmd2/black
Add black and isort GitHub Action Workflows
Diffstat (limited to 'cmd2/utils.py')
-rw-r--r--cmd2/utils.py109
1 files changed, 69 insertions, 40 deletions
diff --git a/cmd2/utils.py b/cmd2/utils.py
index 1f5de366..9920ad64 100644
--- a/cmd2/utils.py
+++ b/cmd2/utils.py
@@ -93,11 +93,18 @@ def str_to_bool(val: str) -> bool:
class Settable:
"""Used to configure a cmd2 instance member to be settable via the set command in the CLI"""
- def __init__(self, name: str, val_type: Callable, description: str, *,
- onchange_cb: Callable[[str, Any, Any], Any] = None,
- choices: Iterable = None,
- choices_provider: Optional[Callable] = None,
- completer: Optional[Callable] = None):
+
+ def __init__(
+ self,
+ name: str,
+ val_type: Callable,
+ description: str,
+ *,
+ onchange_cb: Callable[[str, Any, Any], Any] = None,
+ choices: Iterable = None,
+ choices_provider: Optional[Callable] = None,
+ completer: Optional[Callable] = None
+ ):
"""
Settable Initializer
@@ -135,8 +142,7 @@ class Settable:
self.completer = completer
-def namedtuple_with_defaults(typename: str, field_names: Union[str, List[str]],
- default_values: collections_abc.Iterable = ()):
+def namedtuple_with_defaults(typename: str, field_names: Union[str, List[str]], default_values: collections_abc.Iterable = ()):
"""
Convenience function for defining a namedtuple with default values
@@ -423,8 +429,8 @@ class StdSim:
Class to simulate behavior of sys.stdout or sys.stderr.
Stores contents in internal buffer and optionally echos to the inner stream it is simulating.
"""
- def __init__(self, inner_stream, *, echo: bool = False,
- encoding: str = 'utf-8', errors: str = 'replace') -> None:
+
+ def __init__(self, inner_stream, *, echo: bool = False, encoding: str = 'utf-8', errors: str = 'replace') -> None:
"""
StdSim Initializer
:param inner_stream: the wrapped stream. Should be a TextIO or StdSim instance.
@@ -507,6 +513,7 @@ class ByteBuf:
"""
Used by StdSim to write binary data and stores the actual bytes written
"""
+
# Used to know when to flush the StdSim
NEWLINES = [b'\n', b'\r']
@@ -537,8 +544,8 @@ class ProcReader:
Used to capture stdout and stderr from a Popen process if any of those were set to subprocess.PIPE.
If neither are pipes, then the process will run normally and no output will be captured.
"""
- def __init__(self, proc: subprocess.Popen, stdout: Union[StdSim, TextIO],
- stderr: Union[StdSim, TextIO]) -> None:
+
+ def __init__(self, proc: subprocess.Popen, stdout: Union[StdSim, TextIO], stderr: Union[StdSim, TextIO]) -> None:
"""
ProcReader initializer
:param proc: the Popen process being read from
@@ -549,11 +556,9 @@ class ProcReader:
self._stdout = stdout
self._stderr = stderr
- self._out_thread = threading.Thread(name='out_thread', target=self._reader_thread_func,
- kwargs={'read_stdout': True})
+ self._out_thread = threading.Thread(name='out_thread', target=self._reader_thread_func, kwargs={'read_stdout': True})
- self._err_thread = threading.Thread(name='out_thread', target=self._reader_thread_func,
- kwargs={'read_stdout': False})
+ self._err_thread = threading.Thread(name='out_thread', target=self._reader_thread_func, kwargs={'read_stdout': False})
# Start the reader threads for pipes only
if self._proc.stdout is not None:
@@ -564,6 +569,7 @@ class ProcReader:
def send_sigint(self) -> None:
"""Send a SIGINT to the process similar to if <Ctrl>+C were pressed"""
import signal
+
if sys.platform.startswith('win'):
# cmd2 started the Windows process in a new process group. Therefore
# a CTRL_C_EVENT can't be sent to it. Send a CTRL_BREAK_EVENT instead.
@@ -641,6 +647,7 @@ class ContextFlag:
while a critical code section has set the flag to True. Because signal handling is always done on the
main thread, this class is not thread-safe since there is no need.
"""
+
def __init__(self) -> None:
# When this flag has a positive value, it is considered set.
# When it is 0, it is not set. It should never go below 0.
@@ -660,8 +667,14 @@ class ContextFlag:
class RedirectionSavedState:
"""Created by each command to store information required to restore state after redirection"""
- def __init__(self, self_stdout: Union[StdSim, IO[str]], sys_stdout: Union[StdSim, IO[str]],
- pipe_proc_reader: Optional[ProcReader], saved_redirecting: bool) -> None:
+
+ def __init__(
+ self,
+ self_stdout: Union[StdSim, IO[str]],
+ sys_stdout: Union[StdSim, IO[str]],
+ pipe_proc_reader: Optional[ProcReader],
+ saved_redirecting: bool,
+ ) -> None:
"""
RedirectionSavedState initializer
:param self_stdout: saved value of Cmd.stdout
@@ -683,13 +696,21 @@ class RedirectionSavedState:
class TextAlignment(Enum):
"""Horizontal text alignment"""
+
LEFT = 1
CENTER = 2
RIGHT = 3
-def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ',
- width: Optional[int] = None, tab_width: int = 4, truncate: bool = False) -> str:
+def align_text(
+ text: str,
+ alignment: TextAlignment,
+ *,
+ fill_char: str = ' ',
+ width: Optional[int] = None,
+ tab_width: int = 4,
+ truncate: bool = False
+) -> str:
"""
Align text for display within a given width. Supports characters with display widths greater than 1.
ANSI style sequences do not count toward the display width. If text has line breaks, then each line is aligned
@@ -713,7 +734,9 @@ def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ',
import io
import shutil
- from . import ansi
+ from . import (
+ ansi,
+ )
if width is None:
width = shutil.get_terminal_size().columns
@@ -770,7 +793,7 @@ def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ',
line_width = ansi.style_aware_wcswidth(line)
if line_width == -1:
- raise(ValueError("Text to align contains an unprintable character"))
+ raise (ValueError("Text to align contains an unprintable character"))
# Get the styles in this line
line_styles = get_styles_in_text(line)
@@ -821,8 +844,9 @@ def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ',
return text_buf.getvalue()
-def align_left(text: str, *, fill_char: str = ' ', width: Optional[int] = None,
- tab_width: int = 4, truncate: bool = False) -> str:
+def align_left(
+ text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4, truncate: bool = False
+) -> str:
"""
Left align text for display within a given width. Supports characters with display widths greater than 1.
ANSI style sequences do not count toward the display width. If text has line breaks, then each line is aligned
@@ -840,12 +864,12 @@ def align_left(text: str, *, fill_char: str = ' ', width: Optional[int] = None,
:raises: ValueError if text or fill_char contains an unprintable character
:raises: ValueError if width is less than 1
"""
- return align_text(text, TextAlignment.LEFT, fill_char=fill_char, width=width,
- tab_width=tab_width, truncate=truncate)
+ return align_text(text, TextAlignment.LEFT, fill_char=fill_char, width=width, tab_width=tab_width, truncate=truncate)
-def align_center(text: str, *, fill_char: str = ' ', width: Optional[int] = None,
- tab_width: int = 4, truncate: bool = False) -> str:
+def align_center(
+ text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4, truncate: bool = False
+) -> str:
"""
Center text for display within a given width. Supports characters with display widths greater than 1.
ANSI style sequences do not count toward the display width. If text has line breaks, then each line is aligned
@@ -863,12 +887,12 @@ def align_center(text: str, *, fill_char: str = ' ', width: Optional[int] = None
:raises: ValueError if text or fill_char contains an unprintable character
:raises: ValueError if width is less than 1
"""
- return align_text(text, TextAlignment.CENTER, fill_char=fill_char, width=width,
- tab_width=tab_width, truncate=truncate)
+ return align_text(text, TextAlignment.CENTER, fill_char=fill_char, width=width, tab_width=tab_width, truncate=truncate)
-def align_right(text: str, *, fill_char: str = ' ', width: Optional[int] = None,
- tab_width: int = 4, truncate: bool = False) -> str:
+def align_right(
+ text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4, truncate: bool = False
+) -> str:
"""
Right align text for display within a given width. Supports characters with display widths greater than 1.
ANSI style sequences do not count toward the display width. If text has line breaks, then each line is aligned
@@ -886,8 +910,7 @@ def align_right(text: str, *, fill_char: str = ' ', width: Optional[int] = None,
:raises: ValueError if text or fill_char contains an unprintable character
:raises: ValueError if width is less than 1
"""
- return align_text(text, TextAlignment.RIGHT, fill_char=fill_char, width=width,
- tab_width=tab_width, truncate=truncate)
+ return align_text(text, TextAlignment.RIGHT, fill_char=fill_char, width=width, tab_width=tab_width, truncate=truncate)
def truncate_line(line: str, max_width: int, *, tab_width: int = 4) -> str:
@@ -912,7 +935,10 @@ def truncate_line(line: str, max_width: int, *, tab_width: int = 4) -> str:
:raises: ValueError if max_width is less than 1
"""
import io
- from . import ansi
+
+ from . import (
+ ansi,
+ )
# Handle tabs
line = line.replace('\t', ' ' * tab_width)
@@ -975,7 +1001,9 @@ def get_styles_in_text(text: str) -> Dict[int, str]:
:param text: text to search for style sequences
"""
- from . import ansi
+ from . import (
+ ansi,
+ )
start = 0
styles = collections.OrderedDict()
@@ -1038,16 +1066,15 @@ def get_defining_class(meth) -> Type:
"""
if isinstance(meth, functools.partial):
return get_defining_class(meth.func)
- if inspect.ismethod(meth) or (inspect.isbuiltin(meth)
- and getattr(meth, '__self__') is not None
- and getattr(meth.__self__, '__class__')):
+ if inspect.ismethod(meth) or (
+ inspect.isbuiltin(meth) and getattr(meth, '__self__') is not None and getattr(meth.__self__, '__class__')
+ ):
for cls in inspect.getmro(meth.__self__.__class__):
if meth.__name__ in cls.__dict__:
return cls
meth = getattr(meth, '__func__', meth) # fallback to __qualname__ parsing
if inspect.isfunction(meth):
- cls = getattr(inspect.getmodule(meth),
- meth.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0])
+ cls = getattr(inspect.getmodule(meth), meth.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0])
if isinstance(cls, type):
return cls
return getattr(meth, '__objclass__', None) # handle special descriptor objects
@@ -1055,6 +1082,7 @@ def get_defining_class(meth) -> Type:
class CompletionMode(Enum):
"""Enum for what type of tab completion to perform in cmd2.Cmd.read_input()"""
+
# Tab completion will be disabled during read_input() call
# Use of custom up-arrow history supported
NONE = 1
@@ -1072,6 +1100,7 @@ class CompletionMode(Enum):
class CustomCompletionSettings:
"""Used by cmd2.Cmd.complete() to tab complete strings other than command arguments"""
+
def __init__(self, parser: argparse.ArgumentParser, *, preserve_quotes: bool = False):
"""
Initializer