Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions lib/cli_command_parser/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Context(AbstractContextManager): # Extending AbstractContextManager to ma
config: CommandConfig
prog: OptStr = None
allow_argv_prog: Bool = True
_command_obj: CommandObj = None
_command_obj: CommandObj | None = None
_terminal_width: int | None
_provided: dict[ParamOrGroup, int]

Expand All @@ -56,8 +56,8 @@ def __init__(
command_cls: CommandType | None = None,
*,
parent: Context | None = None,
config: AnyConfig = None,
terminal_width: int = None,
config: AnyConfig | None = None,
terminal_width: int | None = None,
allow_argv_prog: Bool = None,
command: CommandObj | None = None,
**kwargs,
Expand Down Expand Up @@ -100,7 +100,7 @@ def _set_argv(self, prog: OptStr, argv: Argv):
self.remaining = list(self.argv)

def _sub_context(
self, command_cls: CommandType, argv: Argv = None, command: CommandObj = None, **kwargs
self, command_cls: CommandType, argv: Argv = None, command: CommandObj | None = None, **kwargs
) -> Context:
return self.__class__(
self.remaining if argv is None else argv,
Expand Down Expand Up @@ -151,7 +151,7 @@ def terminal_width(self) -> int:

def get_parsed(
self,
command: Command = None,
command: Command | None = None,
*,
exclude: Collection[Parameter] = (),
recursive: Bool = True,
Expand Down Expand Up @@ -443,7 +443,7 @@ def get_current_context(silent: bool = False) -> Context | None:


def get_or_create_context(
command_cls: CommandType, argv: Argv = None, *, command: CommandObj = None, **kwargs
command_cls: CommandType, argv: Argv = None, *, command: CommandObj | None = None, **kwargs
) -> Context:
"""
Used internally by Commands to re-use an existing user-activated Context, or to create a new Context if there was
Expand All @@ -469,7 +469,7 @@ def get_context(command: Command) -> Context:


def get_parsed(
command: Command, to_call: Callable = None, default: Any = None, include_defaults: Bool = True
command: Command, to_call: Callable | None = None, default: Any = None, include_defaults: Bool = True
) -> dict[str, Any]:
"""
Provides a way to obtain all of the arguments that were parsed for the given Command as a dictionary.
Expand Down
20 changes: 14 additions & 6 deletions lib/cli_command_parser/conversion/argparse_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Script:
_parser_classes = {}
path: Path | None

def __init__(self, src_text: str, smart_loop_handling: bool = True, path: PathLike = None):
def __init__(self, src_text: str, smart_loop_handling: bool = True, path: PathLike | None = None):
self.smart_loop_handling = smart_loop_handling
self._parsers = []
self.path = Path(path) if path else None
Expand Down Expand Up @@ -143,13 +143,15 @@ def _add_visit_func(cls, name: str) -> bool:
cls.visit_funcs.add(name)
return True

def __init_subclass__(cls, represents: RepresentedCallable = None, **kwargs):
def __init_subclass__(cls, represents: RepresentedCallable | None = None, **kwargs):
super().__init_subclass__(**kwargs)
if represents:
cls.represents = represents
cls._sig = None

def __init__(self, node: InitNode, parent: AstCallable | Script, tracked_refs: TrackedRefMap, call: Call = None):
def __init__(
self, node: InitNode, parent: AstCallable | Script, tracked_refs: TrackedRefMap, call: Call | None = None
):
self.init_node = node
if not call:
call = node.value if isinstance(node, Assign) else node # type: Call
Expand Down Expand Up @@ -253,7 +255,9 @@ def __init_subclass__(cls, children: Collection[str] = (), **kwargs):
if children:
cls._children = (*cls._children, *children)

def __init__(self, node: InitNode, parent: AstCallable | Script, tracked_refs: TrackedRefMap, call: Call = None):
def __init__(
self, node: InitNode, parent: AstCallable | Script, tracked_refs: TrackedRefMap, call: Call | None = None
):
super().__init__(node, parent, tracked_refs, call)
self.args = []
self.groups = []
Expand Down Expand Up @@ -314,7 +318,9 @@ class AstArgumentParser(ArgCollection, represents=ArgumentParser, children=('sub
sub_parsers: list[SubParser]
add_subparsers = AddVisitedChild(SubparsersAction, '_subparsers_actions')

def __init__(self, node: InitNode, parent: AstCallable | Script, tracked_refs: TrackedRefMap, call: Call = None):
def __init__(
self, node: InitNode, parent: AstCallable | Script, tracked_refs: TrackedRefMap, call: Call | None = None
):
super().__init__(node, parent, tracked_refs, call)
self._subparsers_actions = []
# Note: sub_parsers aren't included in grouped_children since they need different handling during conversion
Expand All @@ -324,7 +330,9 @@ def __repr__(self) -> str:
sub_parsers = len(self.sub_parsers)
return f'<{self.__class__.__name__}[{sub_parsers=}]: ``{self.init_call_repr()}``>'

def _add_subparser(self, node: InitNode, call: Call, tracked_refs: TrackedRefMap, sub_parser_cls: ParserCls = None):
def _add_subparser(
self, node: InitNode, call: Call, tracked_refs: TrackedRefMap, sub_parser_cls: ParserCls | None = None
):
# Using default of None since the class hasn't been defined at the time it would need to be set as default
return self._add_child(sub_parser_cls or SubParser, self.sub_parsers, node, call, tracked_refs)

Expand Down
8 changes: 4 additions & 4 deletions lib/cli_command_parser/conversion/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ def convert_script(script: Script, add_methods: bool = False) -> str:


class Converter(Generic[AC], ABC):
converts: Type[AC] = None
converts: Type[AC] | None = None
newline_between_members: bool = False
_ac_converter_map = {}

def __init_subclass__(cls, converts: Type[AC] = None, newline_between_members: bool = None, **kwargs):
def __init_subclass__(cls, converts: Type[AC] | None = None, newline_between_members: bool | None = None, **kwargs):
super().__init_subclass__(**kwargs)
if converts:
cls.converts = converts
Expand Down Expand Up @@ -165,8 +165,8 @@ class ParserConverter(CollectionConverter[AstArgumentParser], converts=AstArgume
def __init__(
self,
parser: AstArgumentParser,
parent: ParserConverter = None,
counter: count = None,
parent: ParserConverter | None = None,
counter: count | None = None,
*,
add_methods: bool = False,
):
Expand Down
48 changes: 25 additions & 23 deletions lib/cli_command_parser/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .formatting.restructured_text import MODULE_TEMPLATE, rst_header, rst_toc_tree

if TYPE_CHECKING:
from .typing import Bool, CommandCls, PathLike, Strings
from .typing import Bool, CommandCls, OptStr, PathLike, Strings

Commands = dict[str, CommandCls]

Expand All @@ -34,14 +34,14 @@


def render_script_rst(
path: PathLike, top_only: Bool = True, fix_name: Bool = True, fix_name_func: NameFunc = None
path: PathLike, top_only: Bool = True, fix_name: Bool = True, fix_name_func: NameFunc | None = None
) -> str:
"""Load all Commands from the file with the given path, and generate a single RST string based on those Commands"""
commands = load_commands(path, top_only)
return _render_commands_rst(commands, fix_name, fix_name_func)


def render_command_rst(command: CommandCls, fix_name: Bool = True, fix_name_func: NameFunc = None) -> str:
def render_command_rst(command: CommandCls, fix_name: Bool = True, fix_name_func: NameFunc | None = None) -> str:
"""
:param command: The :class:`.Command` to document
:param fix_name: Whether the file name should be re-formatted from CamelCase / snake_case to separate Title Case
Expand All @@ -53,7 +53,7 @@ def render_command_rst(command: CommandCls, fix_name: Bool = True, fix_name_func
return get_formatter(command).format_rst(fix_name, fix_name_func)


def _render_commands_rst(commands: Commands, fix_name: Bool = True, fix_name_func: NameFunc = None) -> str:
def _render_commands_rst(commands: Commands, fix_name: Bool = True, fix_name_func: NameFunc | None = None) -> str:
# This could be better, but it's relatively unlikely to have multiple top level commands in a script...
# For the same reason that main() does not try to pick one, this will just combine all of them.
parts = []
Expand Down Expand Up @@ -199,7 +199,7 @@ def __init__(
newline: str = '\n',
ext: str = '.rst',
module_template: str = MODULE_TEMPLATE,
skip_modules: Strings = None,
skip_modules: Strings | None = None,
):
self.output_dir = Path(output_dir)
self.dry_run = dry_run
Expand All @@ -212,9 +212,9 @@ def __init__(
def document_script(
self,
path: Path,
subdir: str = None,
name: str = None,
replacements: Mapping[str, str] = None,
subdir: OptStr = None,
name: OptStr = None,
replacements: Mapping[str, str] | None = None,
top_only: Bool = True,
**kwargs,
) -> str:
Expand Down Expand Up @@ -253,13 +253,13 @@ def document_script(
def document_scripts(
self,
paths: Iterable[Path],
subdir: str = None,
subdir: OptStr = None,
top_only: Bool = True,
*,
index_name: str = None,
index_header: str = None,
index_subdir: str = None,
caption: str = None,
index_name: OptStr = None,
index_header: OptStr = None,
index_subdir: OptStr = None,
caption: OptStr = None,
**kwargs,
):
names = [self.document_script(path, subdir, top_only=top_only, **kwargs) for path in paths]
Expand All @@ -269,7 +269,7 @@ def document_scripts(
name, index_header or name.title(), names, content_subdir=subdir, caption=caption, subdir=index_subdir
)

def document_module(self, module: str, subdir: str = None):
def document_module(self, module: str, subdir: OptStr = None):
"""
Generate an RST file to document a Python module.

Expand All @@ -285,13 +285,13 @@ def document_package(
self,
pkg_name: str,
pkg_path: Path,
subdir: str = None,
subdir: OptStr = None,
*,
name: str = None,
header: str = None,
name: OptStr = None,
header: OptStr = None,
index: Bool = True,
empty: Bool = False,
caption: str = None,
caption: OptStr = None,
max_depth: int = 4,
) -> list[str]:
"""
Expand Down Expand Up @@ -331,7 +331,9 @@ def document_package(
)
return contents

def _generate_code_rsts(self, pkg_name: str, pkg_path: Path, subdir: str = None, max_depth: int = 4) -> list[str]:
def _generate_code_rsts(
self, pkg_name: str, pkg_path: Path, subdir: OptStr = None, max_depth: int = 4
) -> list[str]:
contents = []
for path in pkg_path.iterdir():
if path.is_dir():
Expand All @@ -355,9 +357,9 @@ def write_index(
header: str,
contents: Strings,
*,
content_subdir: str = None,
subdir: str = None,
caption: str = None,
content_subdir: OptStr = None,
subdir: OptStr = None,
caption: OptStr = None,
max_depth: int = 4,
**kwargs,
):
Expand All @@ -379,7 +381,7 @@ def write_index(
rendered = rst_toc_tree(header, content_fmt, contents, caption=caption, max_depth=max_depth, **kwargs)
self.write_rst(name, rendered, subdir)

def write_rst(self, name: str, content: str, subdir: str = None):
def write_rst(self, name: str, content: str, subdir: OptStr = None):
target_dir = self.output_dir.joinpath(subdir) if subdir else self.output_dir
if not self.dry_run and not target_dir.exists():
target_dir.mkdir(parents=True)
Expand Down
17 changes: 10 additions & 7 deletions lib/cli_command_parser/formatting/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from ..core import CommandMeta
from ..metadata import ProgramMetadata
from ..parameters import BaseOption, BasePositional, Parameter, PassThru, SubCommand
from ..typing import Bool, CommandAny, CommandCls, CommandType
from ..typing import Bool, CommandAny, CommandCls, CommandType, OptStr

__all__ = ['CommandHelpFormatter', 'get_formatter']

Expand Down Expand Up @@ -78,7 +78,7 @@ def _iter_params(self) -> Iterator[BasePositional | BaseOption | PassThru]:
if params.pass_thru is not None:
yield params.pass_thru

def _usage_parts(self, sub_cmd_choice: str = None, allow_sys_argv: Bool = True) -> Iterator[str]:
def _usage_parts(self, sub_cmd_choice: OptStr = None, allow_sys_argv: Bool = True) -> Iterator[str]:
yield 'usage:'
yield self._meta.get_prog(allow_sys_argv)
if sub_cmd_choice:
Expand All @@ -91,7 +91,7 @@ def _usage_parts(self, sub_cmd_choice: str = None, allow_sys_argv: Bool = True)
def format_usage(
self,
delim: str = ' ',
sub_cmd_choice: str = None,
sub_cmd_choice: OptStr = None,
allow_sys_argv: Bool = True,
cont_indent: int = 4,
) -> str:
Expand Down Expand Up @@ -149,7 +149,7 @@ def _format_rst(
def _cmd_rst_lines(
self,
config: CommandConfig,
sub_cmd_choice: str = None,
sub_cmd_choice: OptStr = None,
allow_sys_argv: Bool = False,
include_epilog: Bool = False,
) -> Iterator[str]:
Expand Down Expand Up @@ -184,7 +184,7 @@ def _sub_cmds_rst_lines(
config: CommandConfig,
sub_command: SubCommand,
level: int,
choice_base: str = None,
choice_base: OptStr = None,
depth: int = 0,
allow_sys_argv: Bool = False,
):
Expand Down Expand Up @@ -228,12 +228,15 @@ def get_formatter(command: CommandAny) -> CommandHelpFormatter:

def get_usage_sub_cmds(command: CommandCls):
cmd_mcs: Type[CommandMeta] = command.__class__ # Using metaclass to avoid potentially overwritten attrs
if not (parent := cmd_mcs.parent(command, False)): # type: CommandType

parent: CommandMeta
if not (parent := cmd_mcs.parent(command, False)):
return

yield from get_usage_sub_cmds(parent)

if not (sub_cmd_param := cmd_mcs.params(parent).sub_command): # type: SubCommand
sub_cmd_param: SubCommand
if not (sub_cmd_param := cmd_mcs.params(parent).sub_command):
return

try:
Expand Down
6 changes: 3 additions & 3 deletions lib/cli_command_parser/formatting/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def iter_usage_parts(self, include_meta: Bool = False, full: Bool = False) -> It
"""Format the Parameter for use in the list of Parameters with their ``help='...'`` descriptions"""
yield self.format_usage(include_meta=include_meta, full=full)

def format_description(self, rst: Bool = False, description: str = None) -> str:
def format_description(self, rst: Bool = False, description: OptStr = None) -> str:
param = self.param
if description is None:
description = param.help or ''
Expand Down Expand Up @@ -170,7 +170,7 @@ def iter_usage_parts(self, include_meta: Bool = False, full: Bool = False) -> It
metavar = self._format_usage_metavar()
yield from (f'{opt} {metavar}' for opt in opts.option_strs())

def format_description(self, rst: Bool = False, description: str = None) -> str:
def format_description(self, rst: Bool = False, description: OptStr = None) -> str:
description = super().format_description(rst, description)
param: BaseOption = self.param
if param.env_var and (param.show_env_var or (param.show_env_var is None and ctx.config.show_env_vars)):
Expand Down Expand Up @@ -436,7 +436,7 @@ def format_usage(self, include_meta: Bool = False, full: Bool = False, delim: st
members = (mem.formatter.format_usage(include_meta, full, delim) for mem in self.param.members)
return self.maybe_wrap_usage(self._get_choice_delim().join(members))

def format_description(self, rst: Bool = False, description: str = None) -> str:
def format_description(self, rst: Bool = False, description: OptStr = None) -> str:
if description:
return description
group = self.param
Expand Down
Loading