mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 18:51:29 +00:00
subcommand: Add type annotations
This should make it easier for people unfamiliar with how the command parsers work to follow along. Bug: None Change-Id: I6a6a2100cb881610a14b298303a3040e9ea5ffb5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6508214 Reviewed-by: Scott Lee <ddoman@chromium.org> Auto-Submit: Michael Cui <mlcui@google.com> Commit-Queue: Scott Lee <ddoman@chromium.org>
This commit is contained in:
@@ -42,9 +42,15 @@ Explanation:
|
|||||||
import difflib
|
import difflib
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from typing import NoReturn
|
||||||
|
|
||||||
|
CommandFunction = Callable[[optparse.OptionParser, list[str]], int]
|
||||||
|
|
||||||
|
|
||||||
def usage(more):
|
def usage(more: str) -> Callable[[CommandFunction], CommandFunction]:
|
||||||
"""Adds a 'usage_more' property to a CMD function."""
|
"""Adds a 'usage_more' property to a CMD function."""
|
||||||
def hook(fn):
|
def hook(fn):
|
||||||
fn.usage_more = more
|
fn.usage_more = more
|
||||||
@@ -53,7 +59,7 @@ def usage(more):
|
|||||||
return hook
|
return hook
|
||||||
|
|
||||||
|
|
||||||
def epilog(text):
|
def epilog(text: str) -> Callable[[CommandFunction], CommandFunction]:
|
||||||
"""Adds an 'epilog' property to a CMD function.
|
"""Adds an 'epilog' property to a CMD function.
|
||||||
|
|
||||||
It will be shown in the epilog. Usually useful for examples.
|
It will be shown in the epilog. Usually useful for examples.
|
||||||
@@ -65,7 +71,7 @@ def epilog(text):
|
|||||||
return hook
|
return hook
|
||||||
|
|
||||||
|
|
||||||
def CMDhelp(parser, args):
|
def CMDhelp(parser: optparse.OptionParser, args: list[str]) -> NoReturn:
|
||||||
"""Prints list of commands or help for a specific command."""
|
"""Prints list of commands or help for a specific command."""
|
||||||
# This is the default help implementation. It can be disabled or overridden
|
# This is the default help implementation. It can be disabled or overridden
|
||||||
# if wanted.
|
# if wanted.
|
||||||
@@ -85,13 +91,14 @@ def _get_color_module():
|
|||||||
'third_party.colorama')
|
'third_party.colorama')
|
||||||
|
|
||||||
|
|
||||||
def _function_to_name(name):
|
def _function_to_name(name: str) -> str:
|
||||||
"""Returns the name of a CMD function."""
|
"""Returns the name of a CMD function."""
|
||||||
return name[3:].replace('_', '-')
|
return name[3:].replace('_', '-')
|
||||||
|
|
||||||
|
|
||||||
class CommandDispatcher(object):
|
class CommandDispatcher(object):
|
||||||
def __init__(self, module):
|
|
||||||
|
def __init__(self, module: str):
|
||||||
"""module is the name of the main python module where to look for
|
"""module is the name of the main python module where to look for
|
||||||
commands.
|
commands.
|
||||||
|
|
||||||
@@ -104,7 +111,7 @@ class CommandDispatcher(object):
|
|||||||
"""
|
"""
|
||||||
self.module = sys.modules[module]
|
self.module = sys.modules[module]
|
||||||
|
|
||||||
def enumerate_commands(self):
|
def enumerate_commands(self) -> dict[str, CommandFunction]:
|
||||||
"""Returns a dict of command and their handling function.
|
"""Returns a dict of command and their handling function.
|
||||||
|
|
||||||
The commands must be in the '__main__' modules. To import a command
|
The commands must be in the '__main__' modules. To import a command
|
||||||
@@ -124,7 +131,7 @@ class CommandDispatcher(object):
|
|||||||
cmds.setdefault('help', CMDhelp)
|
cmds.setdefault('help', CMDhelp)
|
||||||
return cmds
|
return cmds
|
||||||
|
|
||||||
def find_nearest_command(self, name_asked):
|
def find_nearest_command(self, name_asked: str) -> CommandFunction | None:
|
||||||
"""Retrieves the function to handle a command as supplied by the user.
|
"""Retrieves the function to handle a command as supplied by the user.
|
||||||
|
|
||||||
It automatically tries to guess the _intended command_ by handling typos
|
It automatically tries to guess the _intended command_ by handling typos
|
||||||
@@ -157,7 +164,7 @@ class CommandDispatcher(object):
|
|||||||
|
|
||||||
return commands[hamming_commands[0][1]]
|
return commands[hamming_commands[0][1]]
|
||||||
|
|
||||||
def _gen_commands_list(self):
|
def _gen_commands_list(self) -> str:
|
||||||
"""Generates the short list of supported commands."""
|
"""Generates the short list of supported commands."""
|
||||||
commands = self.enumerate_commands()
|
commands = self.enumerate_commands()
|
||||||
docs = sorted(
|
docs = sorted(
|
||||||
@@ -179,7 +186,8 @@ class CommandDispatcher(object):
|
|||||||
(green, length, cmd_name, reset, doc)
|
(green, length, cmd_name, reset, doc)
|
||||||
for cmd_name, doc in docs))
|
for cmd_name, doc in docs))
|
||||||
|
|
||||||
def _add_command_usage(self, parser, command):
|
def _add_command_usage(self, parser: optparse.OptionParser,
|
||||||
|
command: CommandFunction) -> None:
|
||||||
"""Modifies an OptionParser object with the function's documentation."""
|
"""Modifies an OptionParser object with the function's documentation."""
|
||||||
cmd_name = _function_to_name(command.__name__)
|
cmd_name = _function_to_name(command.__name__)
|
||||||
if cmd_name == 'help':
|
if cmd_name == 'help':
|
||||||
@@ -211,7 +219,7 @@ class CommandDispatcher(object):
|
|||||||
parser.set_usage('usage: %%prog %s [options]%s' % (cmd_name, extra))
|
parser.set_usage('usage: %%prog %s [options]%s' % (cmd_name, extra))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_command_summary(cmd_name, command):
|
def _create_command_summary(cmd_name: str, command: CommandFunction) -> str:
|
||||||
"""Creates a oneliner summary from the command's docstring."""
|
"""Creates a oneliner summary from the command's docstring."""
|
||||||
if cmd_name != _function_to_name(command.__name__):
|
if cmd_name != _function_to_name(command.__name__):
|
||||||
# Skip aliases. For example using at module level:
|
# Skip aliases. For example using at module level:
|
||||||
@@ -223,7 +231,7 @@ class CommandDispatcher(object):
|
|||||||
return line
|
return line
|
||||||
return (line[0].lower() + line[1:]).strip()
|
return (line[0].lower() + line[1:]).strip()
|
||||||
|
|
||||||
def execute(self, parser, args):
|
def execute(self, parser: optparse.OptionParser, args: list[str]) -> int:
|
||||||
"""Dispatches execution to the right command.
|
"""Dispatches execution to the right command.
|
||||||
|
|
||||||
Fallbacks to 'help' if not disabled.
|
Fallbacks to 'help' if not disabled.
|
||||||
@@ -231,8 +239,8 @@ class CommandDispatcher(object):
|
|||||||
# Unconditionally disable format_description() and format_epilog().
|
# Unconditionally disable format_description() and format_epilog().
|
||||||
# Technically, a formatter should be used but it's not worth (yet) the
|
# Technically, a formatter should be used but it's not worth (yet) the
|
||||||
# trouble.
|
# trouble.
|
||||||
parser.format_description = lambda _: parser.description or ''
|
parser.format_description = lambda formatter: parser.description or ''
|
||||||
parser.format_epilog = lambda _: parser.epilog or ''
|
parser.format_epilog = lambda formatter: parser.epilog or ''
|
||||||
|
|
||||||
if args:
|
if args:
|
||||||
if args[0] in ('-h', '--help') and len(args) > 1:
|
if args[0] in ('-h', '--help') and len(args) > 1:
|
||||||
|
|||||||
Reference in New Issue
Block a user