diff --git a/CHANGELOG.md b/CHANGELOG.md index 21a8ff2d1b..a34c371309 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## dev +- Allow skipping maintenance tasks during list command + ## 1.4.1 - Set default logging level to WARNING, so debug log messages won't be shown without passing additional flags such as `--verbose` diff --git a/src/pipx/commands/list_packages.py b/src/pipx/commands/list_packages.py index ba584d3341..dba22e721d 100644 --- a/src/pipx/commands/list_packages.py +++ b/src/pipx/commands/list_packages.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Any, Collection, Dict, Tuple -from pipx import constants +from pipx import constants, shared_libs from pipx.colors import bold from pipx.commands.common import VenvProblems, get_venv_summary, venv_health_check from pipx.constants import EXIT_CODE_LIST_PROBLEM, EXIT_CODE_OK, ExitCode @@ -89,12 +89,17 @@ def list_packages( include_injected: bool, json_format: bool, short_format: bool, + skip_maintenance: bool, ) -> ExitCode: """Returns pipx exit code.""" venv_dirs: Collection[Path] = sorted(venv_container.iter_venv_dirs()) if not venv_dirs: print(f"nothing has been installed with pipx {sleep}", file=sys.stderr) + if skip_maintenance: + shared_libs.shared_libs.skip_upgrade = True + logger.info("Skipping shared libs maintenance tasks") + venv_container.verify_shared_libs() if json_format: diff --git a/src/pipx/main.py b/src/pipx/main.py index 1ad7b6bf92..49c7fb3907 100644 --- a/src/pipx/main.py +++ b/src/pipx/main.py @@ -263,7 +263,9 @@ def run_pipx_command(args: argparse.Namespace) -> ExitCode: # noqa: C901 force=args.force, ) elif args.command == "list": - return commands.list_packages(venv_container, args.include_injected, args.json, args.short) + return commands.list_packages( + venv_container, args.include_injected, args.json, args.short, args.skip_maintenance + ) elif args.command == "uninstall": return commands.uninstall(venv_dir, constants.LOCAL_BIN_DIR, constants.LOCAL_MAN_DIR, verbose) elif args.command == "uninstall-all": @@ -566,6 +568,7 @@ def _add_list(subparsers: argparse._SubParsersAction, shared_parser: argparse.Ar g = p.add_mutually_exclusive_group() g.add_argument("--json", action="store_true", help="Output rich data in json format.") g.add_argument("--short", action="store_true", help="List packages only.") + g.add_argument("--skip-maintenance", action="store_true", help="Skip maintenance tasks.") def _add_run(subparsers: argparse._SubParsersAction, shared_parser: argparse.ArgumentParser) -> None: diff --git a/src/pipx/shared_libs.py b/src/pipx/shared_libs.py index 366e84aea6..9429b01252 100644 --- a/src/pipx/shared_libs.py +++ b/src/pipx/shared_libs.py @@ -31,6 +31,7 @@ def __init__(self) -> None: self._site_packages: Optional[Path] = None self.has_been_updated_this_run = False self.has_been_logged_this_run = False + self.skip_upgrade = False @property def site_packages(self) -> Path: @@ -65,7 +66,7 @@ def is_valid(self) -> bool: @property def needs_upgrade(self) -> bool: - if self.has_been_updated_this_run: + if self.has_been_updated_this_run or self.skip_upgrade: return False if not self.pip_path.is_file(): diff --git a/tests/test_list.py b/tests/test_list.py index 9b6ef401fa..f6db6d1ce0 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -1,5 +1,7 @@ import json +import os import re +import time import pytest # type: ignore @@ -12,7 +14,7 @@ run_pipx_cli, ) from package_info import PKG -from pipx import constants +from pipx import constants, shared_libs from pipx.pipx_metadata_file import PackageInfo, _json_decoder_object_hook @@ -128,3 +130,27 @@ def test_list_short(pipx_temp_env, monkeypatch, capsys): assert "pycowsay 0.0.0.2" in captured.out assert "pylint 2.3.1" in captured.out + + +def test_skip_maintenance(pipx_temp_env): + assert not run_pipx_cli(["install", PKG["pycowsay"]["spec"]]) + assert not run_pipx_cli(["install", PKG["pylint"]["spec"]]) + + now = time.time() + shared_libs.shared_libs.create(verbose=True) + shared_libs.shared_libs.has_been_updated_this_run = False + + access_time = now # this can be anything + os.utime(shared_libs.shared_libs.pip_path, (access_time, -shared_libs.SHARED_LIBS_MAX_AGE_SEC - 5 * 60 + now)) + assert shared_libs.shared_libs.needs_upgrade + run_pipx_cli(["list"]) + assert shared_libs.shared_libs.has_been_updated_this_run + assert not shared_libs.shared_libs.needs_upgrade + + os.utime(shared_libs.shared_libs.pip_path, (access_time, -shared_libs.SHARED_LIBS_MAX_AGE_SEC - 5 * 60 + now)) + shared_libs.shared_libs.has_been_updated_this_run = False + assert shared_libs.shared_libs.needs_upgrade + run_pipx_cli(["list", "--skip-maintenance"]) + shared_libs.shared_libs.skip_upgrade = False + assert not shared_libs.shared_libs.has_been_updated_this_run + assert shared_libs.shared_libs.needs_upgrade