def test_traceback(self, _get_cleaned_args): """ Make sure the --trace option works. """ def test_command(): print("Command called") def test_exception(): raise Exception("Bad things") cli = CLI() cli.register(test_command) cli.register(test_exception) with patch("builtins.print", side_effect=print_) as print_mock: # Make sure commands work as usual if no exceptions are raised. config = Config( params=["test_command", "--trace"], output="Command called" ) _get_cleaned_args.return_value = config.params cli.run() print_mock.assert_called_with(config.output) print_mock.reset_mock() # Make sure a traceback is shown if an exception is raised. with patch("targ.traceback.format_exc") as traceback_mock: with self.assertRaises(SystemExit): _get_cleaned_args.return_value = [ "test_exception", "--trace", ] cli.run() traceback_mock.assert_called_once()
def test_invalid_command_name(self): """ Make sure invalid app names are rejected. """ with self.assertRaises(ValueError): CLI().register(add, command_name="contains spaces") # Shouldn't raise an exception CLI().register(add, command_name="my_command")
def test_register(self): """ Make sure a command can be registered. """ cli = CLI() cli.register(add) self.assertTrue(len(cli.commands) == 1) self.assertTrue(cli.commands[0].command is add)
def main(): """ The entrypoint to the Piccolo CLI. """ # In case it's run from an entrypoint: sys.path.insert(0, os.getcwd()) ########################################################################### # Run in diagnose mode if requested. diagnose = get_diagnose_flag() if diagnose: print("Diagnosis...") if Finder(diagnose=True).get_app_registry(): print("Everything OK") return ########################################################################### cli = CLI(description="Piccolo CLI") ########################################################################### # Register the base apps. for _app_config in [ app_config, asgi_config, meta_config, migrations_config, playground_config, project_config, shell_config, sql_shell_config, user_config, ]: for command in _app_config.commands: cli.register(command, group_name=_app_config.app_name) ########################################################################### # Get user defined apps. try: APP_REGISTRY: AppRegistry = Finder().get_app_registry() except (ImportError, AttributeError): print("Can't import the APP_REGISTRY from piccolo_conf - some " "commands may be missing. If this is a new project don't worry. " f"To see a full traceback use `piccolo {DIAGNOSE_FLAG}`") else: for app_name, _app_config in APP_REGISTRY.app_configs.items(): for command in _app_config.commands: if cli.command_exists(group_name=app_name, command_name=command.__name__): # Skipping - already registered. continue cli.register(command, group_name=app_name) ########################################################################### cli.run()
def test_float_arg(self, _get_cleaned_args): """ Test command arguments which are of type float. """ def test_command(arg1: float): """ A command for testing float arguments. """ if type(arg1) is float: print("arg1 is float") else: raise ValueError("arg1 is the wrong type") cli = CLI() cli.register(test_command) with patch("builtins.print", side_effect=print_) as print_mock: configs: t.List[Config] = [ Config( params=["test_command", "1.11"], output="arg1 is float", ), Config( params=["test_command", "--arg1=1.11"], output="arg1 is float", ), ] for config in configs: _get_cleaned_args.return_value = config.params cli.run() print_mock.assert_called_with(config.output) print_mock.reset_mock()
def test_optional_bool_arg(self, _get_cleaned_args): """ Test command arguments which are of type Optional[bool]. """ def test_command(arg1: t.Optional[bool] = None): """ A command for testing optional boolean arguments. """ if arg1 is None: print("arg1 is None") elif arg1 is True: print("arg1 is True") elif arg1 is False: print("arg1 is False") else: raise ValueError("arg1 is the wrong type") cli = CLI() cli.register(test_command) with patch("builtins.print", side_effect=print_) as print_mock: configs: t.List[Config] = [ Config( params=["test_command", "--arg1"], output="arg1 is True", ), Config( params=["test_command", "--arg1=True"], output="arg1 is True", ), Config( params=["test_command", "--arg1=true"], output="arg1 is True", ), Config( params=["test_command", "--arg1=t"], output="arg1 is True", ), Config( params=["test_command", "--arg1=False"], output="arg1 is False", ), Config( params=["test_command", "--arg1=false"], output="arg1 is False", ), Config( params=["test_command", "--arg1=f"], output="arg1 is False", ), Config(params=["test_command"], output="arg1 is None"), ] for config in configs: _get_cleaned_args.return_value = config.params cli.run() print_mock.assert_called_with(config.output) print_mock.reset_mock()
def test_help_flag(self, _get_cleaned_args): """ If the --help flag is passed in, then help text should be shown. """ _get_cleaned_args.return_value = ["add", "--help"] cli = CLI() cli.register(add) with patch("targ.Command.print_help") as print_help: cli.run() print_help.assert_called_once() # And just run it once without patching, to make sure no errors # are raised cli.run()
def test_no_command(self, _get_cleaned_args): """ If no command name is given, then help text should be shown. """ _get_cleaned_args.return_value = [] cli = CLI() cli.register(add) with patch("targ.CLI.get_help_text") as get_help_text: cli.run() get_help_text.assert_called_once() # And just run it once without patching, to make sure no errors # are raised cli.run()
def test_run_solo(self, _get_cleaned_args: MagicMock): """ Make sure a command is run correctly, when the CLI is in solo mode. """ _get_cleaned_args.return_value = ["1", "2"] cli = CLI() cli.register(add) with patch("builtins.print", side_effect=print_) as print_mock: cli.run(solo=True) print_mock.assert_called_with(3)
def test_run_group(self, _get_cleaned_args: MagicMock): """ Make sure a command is run correctly, when the command has been registered in a group. """ _get_cleaned_args.return_value = ["math", "add", "1", "2"] cli = CLI() cli.register(add, group_name="math") with patch("builtins.print", side_effect=print_) as print_mock: cli.run() print_mock.assert_called_with(3)
def test_no_type_annotations(self, _get_cleaned_args): """ Make sure a command with no type annotations still works - the arguments passed to the function will just be strings. """ def test_command(name): print(name) cli = CLI() cli.register(test_command) with patch("builtins.print", side_effect=print_) as print_mock: configs: t.List[Config] = [ Config(params=["test_command", "hello"], output="hello"), ] for config in configs: _get_cleaned_args.return_value = config.params cli.run() print_mock.assert_called_with(config.output) print_mock.reset_mock()
def test_aliases(self, _get_cleaned_args): """ Make sure commands with aliases can be called correctly. """ def test_command(): print("Command called") cli = CLI() cli.register(test_command, aliases=["tc"]) with patch("builtins.print", side_effect=print_) as print_mock: configs: t.List[Config] = [ Config(params=["test_command"], output="Command called"), Config(params=["tc"], output="Command called"), ] for config in configs: _get_cleaned_args.return_value = config.params cli.run() print_mock.assert_called_with(config.output) print_mock.reset_mock()
def main(): """ The entrypoint to the Piccolo CLI. """ # In case it's run from an entrypoint: sys.path.insert(0, os.getcwd()) ########################################################################### # Run in diagnose mode if requested. diagnose = get_diagnose_flag() if diagnose: print("Diagnosis...") if Finder(diagnose=True).get_app_registry(): print("Everything OK") return ########################################################################### cli = CLI(description="Piccolo CLI") ########################################################################### # Register the base apps. for _app_config in [ app_config, asgi_config, fixtures_config, meta_config, migrations_config, playground_config, project_config, schema_config, shell_config, sql_shell_config, tester_config, user_config, ]: for command in _app_config.commands: cli.register( command.callable, group_name=_app_config.app_name, aliases=command.aliases, ) ########################################################################### # Get user defined apps. try: APP_REGISTRY: AppRegistry = Finder().get_app_registry() except (ImportError, AttributeError): print("Can't import the APP_REGISTRY from piccolo_conf - some " "commands may be missing. If this is a new project don't worry. " f"To see a full traceback use `piccolo {DIAGNOSE_FLAG}`") else: for app_name, _app_config in APP_REGISTRY.app_configs.items(): for command in _app_config.commands: if cli.command_exists(group_name=app_name, command_name=command.callable.__name__): # Skipping - already registered. continue cli.register( command.callable, group_name=app_name, aliases=command.aliases, ) if "migrations" not in sys.argv: # Show a warning if any migrations haven't been run. # Don't run it if it looks like the user is running a migration # command, as this information is redundant. try: havent_ran_count = run_sync( CheckMigrationManager(app_name="all").havent_ran_count()) if havent_ran_count: message = (f"{havent_ran_count} migration hasn't" if havent_ran_count == 1 else f"{havent_ran_count} migrations haven't") colored_warning( message=("=> {} been run - the app " "might not behave as expected.\n" "To check which use:\n" " piccolo migrations check\n" "To run all migrations:\n" " piccolo migrations forwards all\n" ).format(message), level=Level.high, ) except Exception: pass ########################################################################### cli.run()
def test_bool_arg(self, _get_cleaned_args): """ Test the different formats for boolean flags. """ def test_command(arg1: bool = False): """ A command for testing boolean arguments. """ if arg1 is True: print("arg1 is True") elif arg1 is False: print("arg1 is False") else: raise ValueError("arg1 is the wrong type") cli = CLI() cli.register(test_command) with patch("builtins.print", side_effect=print_) as print_mock: configs: t.List[Config] = [ Config(params=["test_command"], output="arg1 is False"), Config(params=["test_command", "f"], output="arg1 is False"), Config( params=["test_command", "false"], output="arg1 is False" ), Config( params=["test_command", "False"], output="arg1 is False" ), Config( params=["test_command", "--arg1=f"], output="arg1 is False" ), Config( params=["test_command", "--arg1=false"], output="arg1 is False", ), Config( params=["test_command", "--arg1=False"], output="arg1 is False", ), Config(params=["test_command", "t"], output="arg1 is True"), Config(params=["test_command", "true"], output="arg1 is True"), Config(params=["test_command", "True"], output="arg1 is True"), Config( params=["test_command", "--arg1"], output="arg1 is True" ), Config( params=["test_command", "--arg1=t"], output="arg1 is True" ), Config( params=["test_command", "--arg1=true"], output="arg1 is True", ), Config( params=["test_command", "--arg1=True"], output="arg1 is True", ), ] for config in configs: _get_cleaned_args.return_value = config.params cli.run() print_mock.assert_called_with(config.output) print_mock.reset_mock()
from targ import CLI def add(a: int, b: int): """ Add the two numbers. :param a: The first number. :param b: The second number. """ print(a + b) if __name__ == "__main__": cli = CLI() cli.register(add) cli.run(solo=True)
:param seconds: The number of seconds to countdown. """ print(f"Sleeping for {seconds}") await asyncio.sleep(seconds) print("Finished") def raise_error(): """ A command which raises an Exception. """ print("Raising an exception") raise ValueError("Something went wrong!") if __name__ == "__main__": cli = CLI() cli.register(say_hello) cli.register(echo) cli.register(add, aliases=["+"]) cli.register(print_pi) cli.register(compound_interest) cli.register(compound_interest_decimal) cli.register(create, group_name="user") cli.register(timer) cli.register(add, command_name="sum") cli.register(print_address) cli.register(raise_error) cli.run()