From b8fa8317506ec715ee6b41d9137defb2c7802bae Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Fri, 24 Jan 2025 22:06:08 -0500 Subject: [PATCH 1/2] Fixed docstring style for mkdocstrings - parameters are now shown correctly --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index d2646eed..c421960a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -86,6 +86,7 @@ plugins: filters: - "!^_" merge_init_into_class: true + docstring_style: sphinx docstring_section_style: spacy signature_crossrefs: true show_symbol_type_heading: true From 1184985fcfa92e1476b59ad9770898801a4b0dbc Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Fri, 24 Jan 2025 22:22:22 -0500 Subject: [PATCH 2/2] Fix how exceptions raised are documented in Sphinx style --- cmd2/ansi.py | 12 ++++++------ cmd2/argparse_completer.py | 6 +++--- cmd2/argparse_custom.py | 9 ++++----- cmd2/cmd2.py | 22 ++++++++++----------- cmd2/command_definition.py | 6 +++--- cmd2/decorators.py | 2 +- cmd2/parsing.py | 4 ++-- cmd2/table_creator.py | 40 +++++++++++++++++++------------------- cmd2/utils.py | 32 +++++++++++++++--------------- 9 files changed, 66 insertions(+), 67 deletions(-) diff --git a/cmd2/ansi.py b/cmd2/ansi.py index f25a0089..8242957a 100644 --- a/cmd2/ansi.py +++ b/cmd2/ansi.py @@ -165,7 +165,7 @@ def clear_screen(clear_type: int = 2) -> str: 2 - clear entire screen 3 - clear entire screen and delete all lines saved in the scrollback buffer :return: the clear screen string - :raises: ValueError if clear_type is not a valid value + :raises ValueError: if clear_type is not a valid value """ if 0 <= clear_type <= 3: return f"{CSI}{clear_type}J" @@ -182,7 +182,7 @@ def clear_line(clear_type: int = 2) -> str: 1 - clear from cursor to beginning of the line 2 - clear entire line :return: the clear line string - :raises: ValueError if clear_type is not a valid value + :raises ValueError: if clear_type is not a valid value """ if 0 <= clear_type <= 2: return f"{CSI}{clear_type}K" @@ -915,7 +915,7 @@ def __init__(self, r: int, g: int, b: int) -> None: :param r: integer from 0-255 for the red component of the color :param g: integer from 0-255 for the green component of the color :param b: integer from 0-255 for the blue component of the color - :raises: ValueError if r, g, or b is not in the range 0-255 + :raises ValueError: if r, g, or b is not in the range 0-255 """ if any(c < 0 or c > 255 for c in [r, g, b]): raise ValueError("RGB values must be integers in the range of 0 to 255") @@ -944,7 +944,7 @@ def __init__(self, r: int, g: int, b: int) -> None: :param r: integer from 0-255 for the red component of the color :param g: integer from 0-255 for the green component of the color :param b: integer from 0-255 for the blue component of the color - :raises: ValueError if r, g, or b is not in the range 0-255 + :raises ValueError: if r, g, or b is not in the range 0-255 """ if any(c < 0 or c > 255 for c in [r, g, b]): raise ValueError("RGB values must be integers in the range of 0 to 255") @@ -988,8 +988,8 @@ def style( :param overline: apply the overline style if True. Defaults to False. :param strikethrough: apply the strikethrough style if True. Defaults to False. :param underline: apply the underline style if True. Defaults to False. - :raises: TypeError if fg isn't None or a subclass of FgColor - :raises: TypeError if bg isn't None or a subclass of BgColor + :raises TypeError: if fg isn't None or a subclass of FgColor + :raises TypeError: if bg isn't None or a subclass of BgColor :return: the stylized string """ # List of strings that add style diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index 9bb86e9f..8dd543c2 100644 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -226,7 +226,7 @@ def complete( :param cmd_set: if tab completing a command, the CommandSet the command's function belongs to, if applicable. Defaults to None. - :raises: CompletionError for various types of tab completion errors + :raises CompletionError: for various types of tab completion errors """ if not tokens: return [] @@ -264,7 +264,7 @@ def update_mutex_groups(arg_action: argparse.Action) -> None: Check if an argument belongs to a mutually exclusive group and either mark that group as complete or print an error if the group has already been completed :param arg_action: the action of the argument - :raises: CompletionError if the group is already completed + :raises CompletionError: if the group is already completed """ # Check if this action is in a mutually exclusive group for group in self._parser._mutually_exclusive_groups: @@ -679,7 +679,7 @@ def _complete_arg( """ Tab completion routine for an argparse argument :return: list of completions - :raises: CompletionError if the completer or choices function this calls raises one + :raises CompletionError: if the completer or choices function this calls raises one """ # Check if the arg provides choices to the user arg_choices: Union[List[str], ChoicesCallable] diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py index 71f61cc2..68249d85 100644 --- a/cmd2/argparse_custom.py +++ b/cmd2/argparse_custom.py @@ -300,7 +300,6 @@ def __init__(self, value: object, description: str = '', *args: Any) -> None: :param value: the value being tab completed :param description: description text to display :param args: args for str __init__ - :param kwargs: kwargs for str __init__ """ super().__init__(*args) self.description = description @@ -473,7 +472,7 @@ def _action_set_choices_callable(self: argparse.Action, choices_callable: Choice :param self: action being edited :param choices_callable: the ChoicesCallable instance to use - :raises: TypeError if used on incompatible action type + :raises TypeError: if used on incompatible action type """ # Verify consistent use of parameters if self.choices is not None: @@ -504,7 +503,7 @@ def _action_set_choices_provider( :param self: action being edited :param choices_provider: the choices_provider instance to use - :raises: TypeError if used on incompatible action type + :raises TypeError: if used on incompatible action type """ self._set_choices_callable(ChoicesCallable(is_completer=False, to_call=choices_provider)) # type: ignore[attr-defined] @@ -525,7 +524,7 @@ def _action_set_completer( :param self: action being edited :param completer: the completer instance to use - :raises: TypeError if used on incompatible action type + :raises TypeError: if used on incompatible action type """ self._set_choices_callable(ChoicesCallable(is_completer=True, to_call=completer)) # type: ignore[attr-defined] @@ -758,7 +757,7 @@ def _add_argument_wrapper( See the header of this file for more information :return: the created argument action - :raises: ValueError on incorrect parameter usage + :raises ValueError: on incorrect parameter usage """ # Verify consistent use of arguments choices_callables = [choices_provider, completer] diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index b888421d..7e34b7dc 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1134,7 +1134,7 @@ def remove_settable(self, name: str) -> None: Convenience method for removing a settable parameter from ``self.settables`` :param name: name of the settable being removed - :raises: KeyError if the Settable matches this name + :raises KeyError: if the Settable matches this name """ try: del self._settables[name] @@ -2701,8 +2701,8 @@ def _complete_statement(self, line: str, *, orig_rl_history_length: Optional[int This is used to assist in combining multiline readline history entries and is only populated by cmd2. Defaults to None. :return: the completed Statement - :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation) - :raises: EmptyStatement when the resulting Statement is blank + :raises Cmd2ShlexError: if a shlex error occurs (e.g. No closing quotation) + :raises EmptyStatement: when the resulting Statement is blank """ def combine_rl_history(statement: Statement) -> None: @@ -2788,8 +2788,8 @@ def _input_line_to_statement(self, line: str, *, orig_rl_history_length: Optiona This is used to assist in combining multiline readline history entries and is only populated by cmd2. Defaults to None. :return: parsed command line as a Statement - :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation) - :raises: EmptyStatement when the resulting Statement is blank + :raises Cmd2ShlexError: if a shlex error occurs (e.g. No closing quotation) + :raises EmptyStatement: when the resulting Statement is blank """ used_macros = [] orig_line = None @@ -2879,7 +2879,7 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState: :param statement: a parsed statement from the user :return: A bool telling if an error occurred and a utils.RedirectionSavedState object - :raises: RedirectionError if an error occurs trying to pipe or redirect + :raises RedirectionError: if an error occurs trying to pipe or redirect """ import io import subprocess @@ -3135,7 +3135,7 @@ def read_input( :param parser: an argument parser which supports the tab completion of multiple arguments :return: the line read from stdin with all trailing new lines removed - :raises: any exceptions raised by input() and stdin.readline() + :raises Exception: any exceptions raised by input() and stdin.readline() """ readline_configured = False saved_completer: Optional[CompleterFunc] = None @@ -3260,7 +3260,7 @@ def _read_command_line(self, prompt: str) -> str: :param prompt: prompt to display to user :return: command line text of 'eof' if an EOFError was caught - :raises: whatever exceptions are raised by input() except for EOFError + :raises Exception: whatever exceptions are raised by input() except for EOFError """ try: # Wrap in try since terminal_lock may not be locked @@ -5080,7 +5080,7 @@ def run_editor(self, file_path: Optional[str] = None) -> None: Run a text editor and optionally open a file with it :param file_path: optional path of the file to edit. Defaults to None. - :raises: EnvironmentError if self.editor is not set + :raises EnvironmentError: if self.editor is not set """ if not self.editor: raise EnvironmentError("Please use 'set editor' to specify your text editing program of choice.") @@ -5515,9 +5515,9 @@ def _report_disabled_command_usage(self, *_args: Any, message_to_print: str, **_ """ Report when a disabled command has been run or had help called on it - :param args: not used + :param _args: not used :param message_to_print: the message reporting that the command is disabled - :param kwargs: not used + :param _kwargs: not used """ # Set apply_style to False so message_to_print's style is not overridden self.perror(message_to_print, apply_style=False) diff --git a/cmd2/command_definition.py b/cmd2/command_definition.py index 002a1773..5bac8ef3 100644 --- a/cmd2/command_definition.py +++ b/cmd2/command_definition.py @@ -114,7 +114,7 @@ def _cmd(self) -> 'cmd2.Cmd': Override this property if you need to change its return type to a child class of Cmd. - :raises: CommandSetRegistrationError if CommandSet is not registered. + :raises CommandSetRegistrationError: if CommandSet is not registered. """ if self.__cmd_internal is None: raise CommandSetRegistrationError('This CommandSet is not registered') @@ -127,7 +127,7 @@ def on_register(self, cmd: 'cmd2.Cmd') -> None: requiring access to the Cmd object (e.g. configure commands and their parsers based on CLI state data). :param cmd: The cmd2 main application - :raises: CommandSetRegistrationError if CommandSet is already registered. + :raises CommandSetRegistrationError: if CommandSet is already registered. """ if self.__cmd_internal is None: self.__cmd_internal = cmd @@ -185,7 +185,7 @@ def remove_settable(self, name: str) -> None: Convenience method for removing a settable parameter from the CommandSet :param name: name of the settable being removed - :raises: KeyError if the Settable matches this name + :raises KeyError: if the Settable matches this name """ try: del self._settables[name] diff --git a/cmd2/decorators.py b/cmd2/decorators.py index cb254952..343beaa2 100644 --- a/cmd2/decorators.py +++ b/cmd2/decorators.py @@ -354,7 +354,7 @@ def cmd_wrapper(*args: Any, **kwargs: Dict[str, Any]) -> Optional[bool]: contiguously somewhere in the list :param kwargs: any keyword arguments being passed to command function :return: return value of command function - :raises: Cmd2ArgparseError if argparse has error parsing command line + :raises Cmd2ArgparseError: if argparse has error parsing command line """ cmd2_app, statement_arg = _parse_positionals(args) statement, parsed_arglist = cmd2_app.statement_parser.get_command_arg_list( diff --git a/cmd2/parsing.py b/cmd2/parsing.py index 3d82193f..c42ac22b 100644 --- a/cmd2/parsing.py +++ b/cmd2/parsing.py @@ -376,7 +376,7 @@ def tokenize(self, line: str) -> List[str]: :param line: the command line being lexed :return: A list of tokens - :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation) + :raises Cmd2ShlexError: if a shlex error occurs (e.g. No closing quotation) """ # expand shortcuts and aliases @@ -404,7 +404,7 @@ def parse(self, line: str) -> Statement: :param line: the command line being parsed :return: a new [cmd2.parsing.Statement][] object - :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation) + :raises Cmd2ShlexError: if a shlex error occurs (e.g. No closing quotation) """ # handle the special case/hardcoded terminator of a blank line diff --git a/cmd2/table_creator.py b/cmd2/table_creator.py index 409e7a99..285253c8 100644 --- a/cmd2/table_creator.py +++ b/cmd2/table_creator.py @@ -92,8 +92,8 @@ def __init__( (defaults to True) :param max_data_lines: maximum lines allowed in a data cell. If line count exceeds this, then the final line displayed will be truncated with an ellipsis. (defaults to INFINITY) - :raises: ValueError if width is less than 1 - :raises: ValueError if max_data_lines is less than 1 + :raises ValueError: if width is less than 1 + :raises ValueError: if max_data_lines is less than 1 """ self.header = header @@ -138,7 +138,7 @@ def __init__(self, cols: Sequence[Column], *, tab_width: int = 4) -> None: :param cols: column definitions for this table :param tab_width: all tabs will be replaced with this many spaces. If a row's fill_char is a tab, then it will be converted to one space. - :raises: ValueError if tab_width is less than 1 + :raises ValueError: if tab_width is less than 1 """ if tab_width < 1: raise ValueError("Tab width cannot be less than 1") @@ -443,9 +443,9 @@ def generate_row( :param post_line: string to print after each line of a row. This can be used for padding after the last cell's text and a right row border. (Defaults to blank) :return: row string - :raises: ValueError if row_data isn't the same length as self.cols - :raises: TypeError if fill_char is more than one character (not including ANSI style sequences) - :raises: ValueError if fill_char, pre_line, inter_cell, or post_line contains an unprintable + :raises ValueError: if row_data isn't the same length as self.cols + :raises TypeError: if fill_char is more than one character (not including ANSI style sequences) + :raises ValueError: if fill_char, pre_line, inter_cell, or post_line contains an unprintable character like a newline """ @@ -570,10 +570,10 @@ def __init__( want a divider row. Defaults to dash. (Cannot be a line breaking character) :param header_bg: optional background color for header cells (defaults to None) :param data_bg: optional background color for data cells (defaults to None) - :raises: ValueError if tab_width is less than 1 - :raises: ValueError if column_spacing is less than 0 - :raises: TypeError if divider_char is longer than one character - :raises: ValueError if divider_char is an unprintable character + :raises ValueError: if tab_width is less than 1 + :raises ValueError: if column_spacing is less than 0 + :raises TypeError: if divider_char is longer than one character + :raises ValueError: if divider_char is an unprintable character """ super().__init__(cols, tab_width=tab_width) @@ -626,8 +626,8 @@ def base_width(cls, num_cols: int, *, column_spacing: int = 2) -> int: :param num_cols: how many columns the table will have :param column_spacing: how many spaces to place between columns. Defaults to 2. :return: base width - :raises: ValueError if column_spacing is less than 0 - :raises: ValueError if num_cols is less than 1 + :raises ValueError: if column_spacing is less than 0 + :raises ValueError: if num_cols is less than 1 """ if num_cols < 1: raise ValueError("Column count cannot be less than 1") @@ -685,7 +685,7 @@ def generate_data_row(self, row_data: Sequence[Any]) -> str: :param row_data: data with an entry for each column in the row :return: data row string - :raises: ValueError if row_data isn't the same length as self.cols + :raises ValueError: if row_data isn't the same length as self.cols """ if len(row_data) != len(self.cols): raise ValueError("Length of row_data must match length of cols") @@ -712,7 +712,7 @@ def generate_table(self, table_data: Sequence[Sequence[Any]], *, include_header: :param include_header: If True, then a header will be included at top of table. (Defaults to True) :param row_spacing: A number 0 or greater specifying how many blank lines to place between each row (Defaults to 1) - :raises: ValueError if row_spacing is less than 0 + :raises ValueError: if row_spacing is less than 0 """ if row_spacing < 0: raise ValueError("Row spacing cannot be less than 0") @@ -771,8 +771,8 @@ def __init__( :param border_bg: optional background color for borders (defaults to None) :param header_bg: optional background color for header cells (defaults to None) :param data_bg: optional background color for data cells (defaults to None) - :raises: ValueError if tab_width is less than 1 - :raises: ValueError if padding is less than 0 + :raises ValueError: if tab_width is less than 1 + :raises ValueError: if padding is less than 0 """ super().__init__(cols, tab_width=tab_width) self.empty_data = [EMPTY] * len(self.cols) @@ -827,7 +827,7 @@ def base_width(cls, num_cols: int, *, column_borders: bool = True, padding: int :param column_borders: if True, borders between columns will be included in the calculation (Defaults to True) :param padding: number of spaces between text and left/right borders of cell :return: base width - :raises: ValueError if num_cols is less than 1 + :raises ValueError: if num_cols is less than 1 """ if num_cols < 1: raise ValueError("Column count cannot be less than 1") @@ -976,7 +976,7 @@ def generate_data_row(self, row_data: Sequence[Any]) -> str: :param row_data: data with an entry for each column in the row :return: data row string - :raises: ValueError if row_data isn't the same length as self.cols + :raises ValueError: if row_data isn't the same length as self.cols """ if len(row_data) != len(self.cols): raise ValueError("Length of row_data must match length of cols") @@ -1077,8 +1077,8 @@ def __init__( :param header_bg: optional background color for header cells (defaults to None) :param odd_bg: optional background color for odd numbered data rows (defaults to None) :param even_bg: optional background color for even numbered data rows (defaults to StdBg.DARK_GRAY) - :raises: ValueError if tab_width is less than 1 - :raises: ValueError if padding is less than 0 + :raises ValueError: if tab_width is less than 1 + :raises ValueError: if padding is less than 0 """ super().__init__( cols, diff --git a/cmd2/utils.py b/cmd2/utils.py index e3480aa1..2ad86417 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -101,7 +101,7 @@ def to_bool(val: Any) -> bool: :param val: value being converted :return: boolean value expressed in the passed in value - :raises: ValueError if the string does not contain a value corresponding to a boolean value + :raises ValueError: if the string does not contain a value corresponding to a boolean value """ if isinstance(val, str): if val.capitalize() == str(True): @@ -209,7 +209,7 @@ def is_text_file(file_path: str) -> bool: :param file_path: path to the file being checked :return: True if the file is a non-empty text file, otherwise False - :raises OSError if file can't be read + :raises OSError: if file can't be read """ import codecs @@ -858,9 +858,9 @@ def align_text( :param truncate: if True, then each line will be shortened to fit within the display width. The truncated portions are replaced by a '…' character. Defaults to False. :return: aligned text - :raises: TypeError if fill_char is more than one character (not including ANSI style sequences) - :raises: ValueError if text or fill_char contains an unprintable character - :raises: ValueError if width is less than 1 + :raises TypeError: if fill_char is more than one character (not including ANSI style sequences) + :raises ValueError: if text or fill_char contains an unprintable character + :raises ValueError: if width is less than 1 """ import io import shutil @@ -982,9 +982,9 @@ def align_left( :param truncate: if True, then text will be shortened to fit within the display width. The truncated portion is replaced by a '…' character. Defaults to False. :return: left-aligned text - :raises: TypeError if fill_char is more than one character (not including ANSI style sequences) - :raises: ValueError if text or fill_char contains an unprintable character - :raises: ValueError if width is less than 1 + :raises TypeError: if fill_char is more than one character (not including ANSI style sequences) + :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) @@ -1005,9 +1005,9 @@ def align_center( :param truncate: if True, then text will be shortened to fit within the display width. The truncated portion is replaced by a '…' character. Defaults to False. :return: centered text - :raises: TypeError if fill_char is more than one character (not including ANSI style sequences) - :raises: ValueError if text or fill_char contains an unprintable character - :raises: ValueError if width is less than 1 + :raises TypeError: if fill_char is more than one character (not including ANSI style sequences) + :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) @@ -1028,9 +1028,9 @@ def align_right( :param truncate: if True, then text will be shortened to fit within the display width. The truncated portion is replaced by a '…' character. Defaults to False. :return: right-aligned text - :raises: TypeError if fill_char is more than one character (not including ANSI style sequences) - :raises: ValueError if text or fill_char contains an unprintable character - :raises: ValueError if width is less than 1 + :raises TypeError: if fill_char is more than one character (not including ANSI style sequences) + :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) @@ -1053,8 +1053,8 @@ def truncate_line(line: str, max_width: int, *, tab_width: int = 4) -> str: :param max_width: the maximum display width the resulting string is allowed to have :param tab_width: any tabs in the text will be replaced with this many spaces :return: line that has a display width less than or equal to width - :raises: ValueError if text contains an unprintable character like a newline - :raises: ValueError if max_width is less than 1 + :raises ValueError: if text contains an unprintable character like a newline + :raises ValueError: if max_width is less than 1 """ import io