From d0bce105c1404805701cdc11b8ae57cf9ad3a2ee Mon Sep 17 00:00:00 2001 From: shouzy <82171453+realshouzy@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:31:31 +0200 Subject: [PATCH] Futher improve logging - Move logger instance inside main - Rename _StdOutFilter to _NonErrorFilter - Improve dictConfig - Use hexadecimal escape sequences --- pip_manage/_logging.py | 24 ++++++++++---------- pip_manage/pip_purge.py | 49 ++++++++++++++++++++-------------------- pip_manage/pip_review.py | 43 +++++++++++++++++------------------ 3 files changed, 57 insertions(+), 59 deletions(-) diff --git a/pip_manage/_logging.py b/pip_manage/_logging.py index c57cdcb3..8ce34b4a 100644 --- a/pip_manage/_logging.py +++ b/pip_manage/_logging.py @@ -13,7 +13,7 @@ from typing_extensions import override -class _StdOutFilter(logging.Filter): +class _NonErrorFilter(logging.Filter): @override def filter(self, record: logging.LogRecord) -> bool: return record.levelno <= logging.INFO @@ -21,13 +21,13 @@ def filter(self, record: logging.LogRecord) -> bool: class _ColoredFormatter(logging.Formatter): COLORS: ClassVar[dict[str, str]] = { - "DEBUG": "\033[0;37m", - "INFO": "\033[0;32m", - "WARNING": "\033[0;33m", - "ERROR": "\033[0;31m", - "CRITICAL": "\033[1;31m", + "DEBUG": "\x1b[0;37m", + "INFO": "\x1b[0;32m", + "WARNING": "\x1b[0;33m", + "ERROR": "\x1b[0;31m", + "CRITICAL": "\x1b[1;31m", } - RESET: ClassVar[Literal["\033[0m"]] = "\033[0m" + RESET: ClassVar[Literal["\x1b[0m"]] = "\x1b[0m" @override def format(self, record: logging.LogRecord) -> str: @@ -36,7 +36,7 @@ def format(self, record: logging.LogRecord) -> str: return super().format(record) -def setup_logging(*, verbose: bool) -> None: +def setup_logging(logger_name: str, *, verbose: bool) -> None: level: Literal["DEBUG", "INFO"] = "DEBUG" if verbose else "INFO" logging.config.dictConfig( { @@ -52,7 +52,7 @@ def setup_logging(*, verbose: bool) -> None: }, "filters": { "StdOutFilter": { - "()": _StdOutFilter, + "()": _NonErrorFilter, }, }, "handlers": { @@ -71,11 +71,11 @@ def setup_logging(*, verbose: bool) -> None: }, }, "loggers": { - "root": { - "level": level, + "": { + "level": "DEBUG", "handlers": ["stdout", "stderr"], - "propagate": True, }, + logger_name: {"level": level, "propagate": True}, }, }, ) diff --git a/pip_manage/pip_purge.py b/pip_manage/pip_purge.py index a54872b5..3d08f0ea 100755 --- a/pip_manage/pip_purge.py +++ b/pip_manage/pip_purge.py @@ -29,8 +29,6 @@ """ ) -_logger: logging.Logger = logging.getLogger(__title__) - def _parse_args( args: Sequence[str] | None = None, @@ -189,49 +187,50 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915 ) -> int: args, forwarded = _parse_args(argv) uninstall_args: list[str] = filter_forwards_include(forwarded, UNINSTALL_ONLY) - setup_logging(verbose=args.verbose) + setup_logging(__title__, verbose=args.verbose) + logger: logging.Logger = logging.getLogger(__title__) - _logger.debug("Forwarded arguments: %s", forwarded) - _logger.debug("Arguments forwarded to 'pip uninstall': %s", uninstall_args) + logger.debug("Forwarded arguments: %s", forwarded) + logger.debug("Arguments forwarded to 'pip uninstall': %s", uninstall_args) if unrecognized_args := set(forwarded).difference(uninstall_args): formatted_unrecognized_arg: list[str] = [ f"'{unrecognized_arg}'" for unrecognized_arg in sorted(unrecognized_args) ] - _logger.warning( + logger.warning( "Unrecognized arguments: %s", ", ".join(formatted_unrecognized_arg), ) try: requirements: list[str] = _read_from_requirements(args.requirements) except OSError as err: - _logger.error("Could not open requirements file: %s", err) + logger.error("Could not open requirements file: %s", err) return 1 if not (packages := [*args.packages, *requirements]): - _logger.error("You must give at least one requirement to uninstall") + logger.error("You must give at least one requirement to uninstall") return 1 package_dependencies: dict[str, _DependencyInfo] = {} for package in packages: if not _is_installed(package): - _logger.warning("Skipping %s as it is not installed", package) + logger.warning("Skipping %s as it is not installed", package) continue if package in args.exclude: - _logger.debug("Skipping %s", package) + logger.debug("Skipping %s", package) continue package_dependencies[package] = dependency_info = _get_dependencies_of_package( package, ignore_extra=args.ignore_extra, ) - _logger.debug( + logger.debug( "%s requires: %s", package, dependency_info.dependencies, ) - _logger.debug( + logger.debug( "%s is required by: %s", package, dependency_info.dependents, @@ -245,12 +244,12 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915 dependent_package, ignore_extra=args.ignore_extra, ) - _logger.debug( + logger.debug( "%s requires: %s", dependent_package, dependent_package_dependency_info.dependencies, ) - _logger.debug( + logger.debug( "%s is required by: %s", dependent_package, dependent_package_dependency_info.dependents, @@ -261,11 +260,11 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915 # If a package has dependents that are NOT supposed to also by uninstalled, # it removes the package from package_dependencies. for package_name, dependency_info in package_dependencies.copy().items(): - _logger.debug("Checking %s", package_name) + logger.debug("Checking %s", package_name) if dependency_info.dependents and not all( package in package_dependencies for package in dependency_info.dependents ): - _logger.info( + logger.info( "Cannot uninstall %s, required by: %s", package_name, ", ".join(dependency_info.dependents.difference(package_dependencies)), @@ -277,27 +276,27 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915 # are also reconsidered. packages_to_uninstall: list[str] = [] for package_name, dependency_info in package_dependencies.items(): - _logger.debug("Checking %s again", package_name) + logger.debug("Checking %s again", package_name) if not dependency_info.dependents or all( package in package_dependencies for package in dependency_info.dependents ): packages_to_uninstall.append(package_name) - _logger.debug("%s will be uninstalled", package_name) + logger.debug("%s will be uninstalled", package_name) else: - _logger.info( + logger.info( "Cannot uninstall %s, required by: %s", package_name, ", ".join(dependency_info.dependents.difference(package_dependencies)), ) - _logger.debug("Finished checking packages") + logger.debug("Finished checking packages") if not packages_to_uninstall: - _logger.info("No packages to purge") + logger.info("No packages to purge") return 0 packages_to_uninstall.sort() - _logger.info( + logger.info( "The following packages will be uninstalled: %s", ", ".join(packages_to_uninstall), ) @@ -306,9 +305,9 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915 try: _freeze_packages(args.freeze_file, packages_to_uninstall) except OSError as err: - _logger.error("Could not open requirements file: %s", err) + logger.error("Could not open requirements file: %s", err) return 1 - _logger.debug("Wrote packages to %s", args.freeze_file) + logger.debug("Wrote packages to %s", args.freeze_file) joined_pip_cmd: str = " ".join(PIP_CMD) joined_uninstall_args: str = " ".join(uninstall_args) @@ -322,7 +321,7 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915 f"{running}: '{joined_pip_cmd} uninstall {joined_uninstall_args} " f"{joined_packages_to_uninstall}'" ) - _logger.info(msg) + logger.info(msg) if not args.dry_run: uninstall_packages( diff --git a/pip_manage/pip_review.py b/pip_manage/pip_review.py index c31084a6..10d04759 100755 --- a/pip_manage/pip_review.py +++ b/pip_manage/pip_review.py @@ -34,8 +34,6 @@ """ ) -_logger: logging.Logger = logging.getLogger(__title__) - def _parse_args( args: Sequence[str] | None = None, @@ -253,67 +251,68 @@ def main( # pylint: disable=R0915 # noqa: PLR0915 exclude=LIST_ONLY, include=INSTALL_ONLY, ) - setup_logging(verbose=args.verbose) + setup_logging(__title__, verbose=args.verbose) + logger: logging.Logger = logging.getLogger(__title__) - _logger.debug("Forwarded arguments: %s", forwarded) - _logger.debug("Arguments forwarded to 'pip list --outdated': %s", list_args) - _logger.debug("Arguments forwarded to 'pip install': %s", install_args) + logger.debug("Forwarded arguments: %s", forwarded) + logger.debug("Arguments forwarded to 'pip list --outdated': %s", list_args) + logger.debug("Arguments forwarded to 'pip install': %s", install_args) if unrecognized_args := set(forwarded).difference(list_args, install_args): formatted_unrecognized_arg: list[str] = [ f"'{unrecognized_arg}'" for unrecognized_arg in sorted(unrecognized_args) ] - _logger.warning( + logger.warning( "Unrecognized arguments: %s", ", ".join(formatted_unrecognized_arg), ) if args.raw and args.auto: - _logger.error("'--raw' and '--auto' cannot be used together") + logger.error("'--raw' and '--auto' cannot be used together") return 1 if args.raw and args.interactive: - _logger.error("'--raw' and '--interactive' cannot be used together") + logger.error("'--raw' and '--interactive' cannot be used together") return 1 if args.auto and args.interactive: - _logger.error("'--auto' and '--interactive' cannot be used together") + logger.error("'--auto' and '--interactive' cannot be used together") return 1 outdated: list[_OutdatedPackage] = get_outdated_packages(list_args) - _logger.debug("Outdated packages: %s", outdated) + logger.debug("Outdated packages: %s", outdated) if not outdated and not args.raw: - _logger.info("Everything up-to-date") + logger.info("Everything up-to-date") return 0 if args.freeze_outdated_packages: try: _freeze_outdated_packages(args.freeze_file, outdated) except OSError as err: - _logger.error("Could not open requirements file: %s", err) + logger.error("Could not open requirements file: %s", err) return 1 - _logger.debug("Wrote outdated packages to %s", args.freeze_file) + logger.debug("Wrote outdated packages to %s", args.freeze_file) if args.raw: for pkg in outdated: - _logger.info("%s==%s", pkg.name, pkg.latest_version) + logger.info("%s==%s", pkg.name, pkg.latest_version) return 0 constraints_files: list[Path] = _get_constraints_files(install_args) - _logger.debug("Constraints files: %s", constraints_files) + logger.debug("Constraints files: %s", constraints_files) try: _set_constraints_of_outdated_pkgs(constraints_files, outdated) except OSError as err: - _logger.error("Could not open requirements file: %s", err) + logger.error("Could not open requirements file: %s", err) return 1 - _logger.debug( + logger.debug( "Outdated packages with new set constraints: %s", outdated, ) if args.preview and (args.auto or args.interactive): - _logger.info(_format_table(_extract_table(outdated))) + logger.info(_format_table(_extract_table(outdated))) if args.auto: update_packages( @@ -326,7 +325,7 @@ def main( # pylint: disable=R0915 # noqa: PLR0915 selected: list[_OutdatedPackage] = [] for pkg in outdated: if pkg.constraints: - _logger.info( + logger.info( "%s==%s is available (you have %s) [Constraint to %s]", pkg.name, pkg.latest_version, @@ -334,7 +333,7 @@ def main( # pylint: disable=R0915 # noqa: PLR0915 pkg.constraints_display, ) else: - _logger.info( + logger.info( "%s==%s is available (you have %s)", pkg.name, pkg.latest_version, @@ -346,7 +345,7 @@ def main( # pylint: disable=R0915 # noqa: PLR0915 if answer in {"y", "a"}: selected.append(pkg) - _logger.debug("Selected packages: %s", selected) + logger.debug("Selected packages: %s", selected) if selected: update_packages( selected,