nubia/internal/registry.py (78 lines of code) (raw):

#!/usr/bin/env python3 # Copyright (c) Facebook, Inc. and its affiliates. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. # from prompt_toolkit.completion import WordCompleter from termcolor import cprint from nubia.internal.cmdbase import Command from nubia.internal.helpers import try_await from nubia.internal.io.eventbus import Listener class CommandsRegistry: """ A registry that holds all commands implementations and creates a quick access point for resolving a command string into the corresponding handling object """ def __init__(self, parser, listeners): self._completer = WordCompleter([], ignore_case=True, sentence=True) # maps a command to Command Instance self._cmd_instance_map = {} # objects interested in receiving messages self._listeners = [] # argparser so each command can add its options self._parser = parser for lst in listeners: self.register_listener(lst(self)) async def register_command(self, cmd_instance, override=False): if not isinstance(cmd_instance, Command): raise TypeError( "Invalid command instance, must be an instance of " "subclass of Command" ) cmd_instance.set_command_registry(self) cmd_keys = cmd_instance.get_command_names() for cmd in cmd_keys: if not cmd_instance.get_help(cmd): cprint( ( "[WARNING] The command {} will not be loaded. " "Please provide a help message by either defining a " "docstring or filling the help argument in the " "@command annotation" ).format(cmd_keys[0]), "red", ) return None await try_await(cmd_instance.add_arguments(self._parser)) if not override: conflicts = [cmd for cmd in cmd_keys if cmd in self._cmd_instance_map] if conflicts: raise ValueError( "Some other command instance has registered " "the name(s) {}".format(conflicts) ) if isinstance(cmd_instance, Listener): self._listeners.append(cmd_instance) for cmd in cmd_keys: self._cmd_instance_map[cmd.lower()] = cmd_instance if cmd not in self._completer.words: self._completer.words.append(cmd) self._completer.meta_dict[cmd] = cmd_instance.get_help_short(cmd) aliases = cmd_instance.get_cli_aliases() for alias in aliases: self._cmd_instance_map[alias.lower()] = cmd_instance def register_priority_listener(self, instance): """ Registers a listener that get the top priority in callbacks """ if not isinstance(instance, Listener): raise TypeError("Only Listeners can be registered") self._listeners.insert(0, instance) def register_listener(self, instance): if not isinstance(instance, Listener): raise TypeError("Only Listeners can be registered") self._listeners.append(instance) def __contains__(self, cmd): return cmd.lower() in self._cmd_instance_map def get_completer(self): return self._completer def get_all_commands(self): return set(self._cmd_instance_map.values()) def get_all_commands_map(self): return self._cmd_instance_map def find_command(self, cmd): return self._cmd_instance_map.get(cmd.lower()) def get_completions(self, document, complete_event): return self._completer.get_completions(document, complete_event) async def dispatch_message(self, msg, *args, **kwargs): for mod in self._listeners: await try_await(mod.react(msg, *args, **kwargs)) def set_cli_args(self, args): self._args = args def get_cli_arg(self, arg): return getattr(self._args, arg, None)