diff --git a/src/ape/cli/options.py b/src/ape/cli/options.py index 3b3b0735e4..0b78ff10c0 100644 --- a/src/ape/cli/options.py +++ b/src/ape/cli/options.py @@ -72,7 +72,12 @@ def _create_verbosity_kwargs( cli_logger = _logger or logger def set_level(ctx, param, value): - cli_logger._load_from_sys_argv(default=value.upper() if isinstance(value, str) else value) + if isinstance(value, str): + value = value.upper() + if value.startswith("LOGLEVEL."): + value = value.split(".")[-1].strip() + + cli_logger._load_from_sys_argv(default=value) level_names = [lvl.name for lvl in LogLevel] names_str = f"{', '.join(level_names[:-1])}, or {level_names[-1]}" diff --git a/src/ape/logging.py b/src/ape/logging.py index ad564f305a..fd4161c90d 100644 --- a/src/ape/logging.py +++ b/src/ape/logging.py @@ -175,9 +175,11 @@ def set_level(self, level: Union[str, int, LogLevel]): """ if level == self._logger.level: return - elif isinstance(level, LogLevel): level = level.value + elif isinstance(level, str) and level.lower().startswith("loglevel."): + # Seen in some environments. + level = level.split(".")[-1].strip() self._logger.setLevel(level) for _logger in self._extra_loggers.values(): @@ -274,8 +276,11 @@ def _get_level(level: Optional[Union[str, int, LogLevel]] = None) -> str: return DEFAULT_LOG_LEVEL elif isinstance(level, LogLevel): return level.name - elif isinstance(level, int) or level.isnumeric(): + elif isinstance(level, int) or (isinstance(level, str) and level.isnumeric()): return LogLevel(int(level)).name + elif isinstance(level, str) and level.lower().startswith("loglevel."): + # Handle 'LogLevel.' prefix. + return level.split(".")[-1].strip() return level diff --git a/src/ape_test/_cli.py b/src/ape_test/_cli.py index 7ede439617..2547c27bc6 100644 --- a/src/ape_test/_cli.py +++ b/src/ape_test/_cli.py @@ -12,7 +12,7 @@ from watchdog.observers import Observer from ape.cli import ape_cli_context -from ape.logging import LogLevel +from ape.logging import LogLevel, _get_level from ape.utils import ManagerAccessMixin, cached_property # Copied from https://github.com/olzhasar/pytest-watcher/blob/master/pytest_watcher/watcher.py @@ -75,12 +75,38 @@ def _run_main_loop(delay: float, pytest_args: Sequence[str]) -> None: time.sleep(delay) +def _validate_pytest_args(*pytest_args) -> list[str]: + threshold = len(pytest_args) - 1 + args_iter = iter(pytest_args) + valid_args = [] + for idx, argument in enumerate(args_iter): + if idx >= threshold: + # If the last arg is -v without a value, it is a valid + # pytest arg. + valid_args.append(argument) + break + + elif argument == "-v": + # Ensure this is a pytest -v and not ape's -v. + next_arg = next(args_iter) + lvl_name = _get_level(next_arg) + if lvl_name in [x.name for x in LogLevel]: + # Ape log level found, cannot use. + continue + + else: + valid_args.append(argument) + + return valid_args + + @click.command( add_help_option=False, # NOTE: This allows pass-through to pytest's help short_help="Launches pytest and runs the tests for a project", context_settings=dict(ignore_unknown_options=True), ) -@ape_cli_context(default_log_level=LogLevel.WARNING) +# NOTE: Using '.value' because more performant. +@ape_cli_context(default_log_level=LogLevel.WARNING.value) @click.option( "-w", "--watch", @@ -119,6 +145,7 @@ def cli(cli_ctx, watch, watch_folders, watch_delay, pytest_args): cli_ctx.logger.warning(f"Folder '{folder}' doesn't exist or isn't a folder.") observer.start() + pytest_args = _validate_pytest_args(pytest_args) try: _run_ape_test(pytest_args) diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py index cf8a4e0806..0e5cb20878 100644 --- a/tests/functional/test_cli.py +++ b/tests/functional/test_cli.py @@ -434,11 +434,13 @@ def test_verbosity_option(runner): def cmd(): click.echo(f"__expected_{logger.level}") - result = runner.invoke(cmd, ["--verbosity", logger.level]) + result = runner.invoke(cmd, ("--verbosity", logger.level)) assert f"__expected_{logger.level}" in result.output -@pytest.mark.parametrize("level", (LogLevel.WARNING, LogLevel.WARNING.name, LogLevel.WARNING.value)) +@pytest.mark.parametrize( + "level", (LogLevel.WARNING, LogLevel.WARNING.name, LogLevel.WARNING.value, "LogLevel.WARNING") +) def test_verbosity_option_change_default(runner, level): @click.command() @verbosity_option(default=level) diff --git a/tests/functional/test_logging.py b/tests/functional/test_logging.py index 9811e1a74a..9bf53cd768 100644 --- a/tests/functional/test_logging.py +++ b/tests/functional/test_logging.py @@ -101,7 +101,9 @@ def cmd(cli_ctx): assert "SUCCESS" not in result.output -@pytest.mark.parametrize("level", (LogLevel.INFO, LogLevel.INFO.value, LogLevel.INFO.name)) +@pytest.mark.parametrize( + "level", (LogLevel.INFO, LogLevel.INFO.value, LogLevel.INFO.name, "LogLevel.INFO") +) def test_set_level(level): logger.set_level(level) assert logger.level == LogLevel.INFO.value