Formatting: Format all python code with black.
This CL is probably not what you're looking for, it's only
automated formatting. Ignore it with
`git blame --ignore-rev <revision>` for this commit.
BUG=b:233893248
TEST=CQ
Change-Id: I66591d7a738d241aed3290138c0f68065ab10a6d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/3879174
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Tested-by: Alex Klein <saklein@chromium.org>
diff --git a/cli/command.py b/cli/command.py
index 6484faa..a8f7d0a 100644
--- a/cli/command.py
+++ b/cli/command.py
@@ -24,161 +24,183 @@
# Paths for finding and importing subcommand modules.
-_SUBCOMMAND_MODULE_DIRECTORY = os.path.join(os.path.dirname(__file__), 'cros')
-_SUBCOMMAND_MODULE_PREFIX = 'cros_'
+_SUBCOMMAND_MODULE_DIRECTORY = os.path.join(os.path.dirname(__file__), "cros")
+_SUBCOMMAND_MODULE_PREFIX = "cros_"
_commands = dict()
def UseProgressBar():
- """Determine whether the progress bar is to be used or not.
+ """Determine whether the progress bar is to be used or not.
- We only want the progress bar to display for the brillo commands which operate
- at logging level NOTICE. If the user wants to see the noisy output, then they
- can execute the command at logging level INFO or DEBUG.
- """
- return logging.getLogger().getEffectiveLevel() == logging.NOTICE
+ We only want the progress bar to display for the brillo commands which operate
+ at logging level NOTICE. If the user wants to see the noisy output, then they
+ can execute the command at logging level INFO or DEBUG.
+ """
+ return logging.getLogger().getEffectiveLevel() == logging.NOTICE
def ImportCommand(name):
- """Directly import the specified subcommand.
+ """Directly import the specified subcommand.
- This method imports the module which must contain the single subcommand. When
- the module is loaded, the declared command (those that use command_decorator)
- will automatically get added to |_commands|.
+ This method imports the module which must contain the single subcommand. When
+ the module is loaded, the declared command (those that use command_decorator)
+ will automatically get added to |_commands|.
- Args:
- name: The subcommand to load.
+ Args:
+ name: The subcommand to load.
- Returns:
- A reference to the subcommand class.
- """
- module_path = os.path.join(_SUBCOMMAND_MODULE_DIRECTORY,
- 'cros_%s' % (name.replace('-', '_'),))
- import_path = os.path.relpath(os.path.realpath(module_path),
- os.path.dirname(constants.CHROMITE_DIR))
- module_parts = import_path.split(os.path.sep)
- importlib.import_module('.'.join(module_parts))
- return _commands[name]
+ Returns:
+ A reference to the subcommand class.
+ """
+ module_path = os.path.join(
+ _SUBCOMMAND_MODULE_DIRECTORY, "cros_%s" % (name.replace("-", "_"),)
+ )
+ import_path = os.path.relpath(
+ os.path.realpath(module_path), os.path.dirname(constants.CHROMITE_DIR)
+ )
+ module_parts = import_path.split(os.path.sep)
+ importlib.import_module(".".join(module_parts))
+ return _commands[name]
def ListCommands():
- """Return the set of available subcommands.
+ """Return the set of available subcommands.
- We assume that there is a direct one-to-one relationship between the module
- name on disk and the command that module implements. We assume this as a
- performance requirement (to avoid importing every subcommand every time even
- though we'd only ever run a single one), and to avoid 3rd party module usage
- in one subcommand breaking all other subcommands (not a great solution).
- """
- # Filenames use underscores due to python naming limitations, but subcommands
- # use dashes as they're easier for humans to type.
- # Strip off the leading "cros_" and the trailing ".py".
- return set(x[5:-3].replace('_', '-')
- for x in os.listdir(_SUBCOMMAND_MODULE_DIRECTORY)
- if (x.startswith(_SUBCOMMAND_MODULE_PREFIX) and x.endswith('.py')
- and not x.endswith('_unittest.py')))
+ We assume that there is a direct one-to-one relationship between the module
+ name on disk and the command that module implements. We assume this as a
+ performance requirement (to avoid importing every subcommand every time even
+ though we'd only ever run a single one), and to avoid 3rd party module usage
+ in one subcommand breaking all other subcommands (not a great solution).
+ """
+ # Filenames use underscores due to python naming limitations, but subcommands
+ # use dashes as they're easier for humans to type.
+ # Strip off the leading "cros_" and the trailing ".py".
+ return set(
+ x[5:-3].replace("_", "-")
+ for x in os.listdir(_SUBCOMMAND_MODULE_DIRECTORY)
+ if (
+ x.startswith(_SUBCOMMAND_MODULE_PREFIX)
+ and x.endswith(".py")
+ and not x.endswith("_unittest.py")
+ )
+ )
class InvalidCommandError(Exception):
- """Error that occurs when command class fails validity checks."""
+ """Error that occurs when command class fails validity checks."""
def command_decorator(name):
- """Decorator to check validity and add class to list of usable commands."""
+ """Decorator to check validity and add class to list of usable commands."""
- def inner_decorator(original_class):
- """Inner Decorator that actually wraps the class."""
- if not hasattr(original_class, '__doc__'):
- raise InvalidCommandError('All handlers must have docstrings: %s' %
- original_class)
+ def inner_decorator(original_class):
+ """Inner Decorator that actually wraps the class."""
+ if not hasattr(original_class, "__doc__"):
+ raise InvalidCommandError(
+ "All handlers must have docstrings: %s" % original_class
+ )
- if not issubclass(original_class, CliCommand):
- raise InvalidCommandError('All Commands must derive from CliCommand: %s' %
- original_class)
+ if not issubclass(original_class, CliCommand):
+ raise InvalidCommandError(
+ "All Commands must derive from CliCommand: %s" % original_class
+ )
- _commands[name] = original_class
- original_class.name = name
+ _commands[name] = original_class
+ original_class.name = name
- return original_class
+ return original_class
- return inner_decorator
+ return inner_decorator
class CliCommand(object):
- """All CLI commands must derive from this class.
+ """All CLI commands must derive from this class.
- This class provides the abstract interface for all CLI commands. When
- designing a new command, you must sub-class from this class and use the
- command_decorator decorator. You must specify a class docstring as that will
- be used as the usage for the sub-command.
+ This class provides the abstract interface for all CLI commands. When
+ designing a new command, you must sub-class from this class and use the
+ command_decorator decorator. You must specify a class docstring as that will
+ be used as the usage for the sub-command.
- In addition your command should implement AddParser which is passed in a
- parser that you can add your own custom arguments. See argparse for more
- information.
- """
- # Indicates whether command uses cache related commandline options.
- use_caching_options = False
-
- def __init__(self, options):
- self.options = options
-
- @classmethod
- def AddParser(cls, parser):
- """Add arguments for this command to the parser."""
- parser.set_defaults(command_class=cls)
-
- @classmethod
- def ProcessOptions(cls,
- parser: commandline.ArgumentParser,
- options: commandline.ArgumentNamespace) -> None:
- """Validate & post-process options before freezing."""
-
- @classmethod
- def AddDeviceArgument(cls, parser, schemes=commandline.DEVICE_SCHEME_SSH,
- positional=False):
- """Add a device argument to the parser.
-
- This standardizes the help message across all subcommands.
-
- Args:
- parser: The parser to add the device argument to.
- schemes: List of device schemes or single scheme to allow.
- positional: Whether it should be a positional or named argument.
+ In addition your command should implement AddParser which is passed in a
+ parser that you can add your own custom arguments. See argparse for more
+ information.
"""
- help_strings = []
- schemes = list(cros_build_lib.iflatten_instance(schemes))
- if commandline.DEVICE_SCHEME_SSH in schemes:
- help_strings.append('Target a device with [user@]hostname[:port]. '
- 'IPv4/IPv6 addresses are allowed, but IPv6 must '
- 'use brackets (e.g. [::1]).')
- if commandline.DEVICE_SCHEME_USB in schemes:
- help_strings.append('Target removable media with usb://[path].')
- if commandline.DEVICE_SCHEME_SERVO in schemes:
- help_strings.append('Target a servo by port or serial number with '
- 'servo:port[:port] or servo:serial:serial-number. '
- 'e.g. servo:port:1234 or servo:serial:C1230024192.')
- if commandline.DEVICE_SCHEME_FILE in schemes:
- help_strings.append('Target a local file with file://path.')
- if positional:
- parser.add_argument('device',
- type=commandline.DeviceParser(schemes),
- help=' '.join(help_strings))
- else:
- parser.add_argument('-d', '--device',
- type=commandline.DeviceParser(schemes),
- help=' '.join(help_strings))
- def Run(self):
- """The command to run."""
- raise NotImplementedError()
+ # Indicates whether command uses cache related commandline options.
+ use_caching_options = False
- def TranslateToChrootArgv(self):
- """Hook to get the argv for reexecution inside the chroot.
+ def __init__(self, options):
+ self.options = options
- By default, return the same args used to execute it in the first place.
- Hook allows commands to translate specific arguments, i.e. change paths to
- chroot paths.
- """
- return sys.argv[:]
+ @classmethod
+ def AddParser(cls, parser):
+ """Add arguments for this command to the parser."""
+ parser.set_defaults(command_class=cls)
+
+ @classmethod
+ def ProcessOptions(
+ cls,
+ parser: commandline.ArgumentParser,
+ options: commandline.ArgumentNamespace,
+ ) -> None:
+ """Validate & post-process options before freezing."""
+
+ @classmethod
+ def AddDeviceArgument(
+ cls, parser, schemes=commandline.DEVICE_SCHEME_SSH, positional=False
+ ):
+ """Add a device argument to the parser.
+
+ This standardizes the help message across all subcommands.
+
+ Args:
+ parser: The parser to add the device argument to.
+ schemes: List of device schemes or single scheme to allow.
+ positional: Whether it should be a positional or named argument.
+ """
+ help_strings = []
+ schemes = list(cros_build_lib.iflatten_instance(schemes))
+ if commandline.DEVICE_SCHEME_SSH in schemes:
+ help_strings.append(
+ "Target a device with [user@]hostname[:port]. "
+ "IPv4/IPv6 addresses are allowed, but IPv6 must "
+ "use brackets (e.g. [::1])."
+ )
+ if commandline.DEVICE_SCHEME_USB in schemes:
+ help_strings.append("Target removable media with usb://[path].")
+ if commandline.DEVICE_SCHEME_SERVO in schemes:
+ help_strings.append(
+ "Target a servo by port or serial number with "
+ "servo:port[:port] or servo:serial:serial-number. "
+ "e.g. servo:port:1234 or servo:serial:C1230024192."
+ )
+ if commandline.DEVICE_SCHEME_FILE in schemes:
+ help_strings.append("Target a local file with file://path.")
+ if positional:
+ parser.add_argument(
+ "device",
+ type=commandline.DeviceParser(schemes),
+ help=" ".join(help_strings),
+ )
+ else:
+ parser.add_argument(
+ "-d",
+ "--device",
+ type=commandline.DeviceParser(schemes),
+ help=" ".join(help_strings),
+ )
+
+ def Run(self):
+ """The command to run."""
+ raise NotImplementedError()
+
+ def TranslateToChrootArgv(self):
+ """Hook to get the argv for reexecution inside the chroot.
+
+ By default, return the same args used to execute it in the first place.
+ Hook allows commands to translate specific arguments, i.e. change paths to
+ chroot paths.
+ """
+ return sys.argv[:]