Skip to content

Commit

Permalink
Improve logging
Browse files Browse the repository at this point in the history
- Use logging.config.dictConfi
- Make error message more similar to pip
  • Loading branch information
realshouzy committed Jun 10, 2024
1 parent 7373979 commit 4a57dbb
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 36 deletions.
80 changes: 60 additions & 20 deletions pip_manage/_logging.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import annotations

__all__: list[str] = ["setup_logging", "set_logging_level"]
__all__: list[str] = ["setup_logging"]

import logging
import logging.config
import sys
from typing import TextIO
from typing import ClassVar, Literal

if sys.version_info >= (3, 12): # pragma: >=3.12 cover
from typing import override
Expand All @@ -18,24 +19,63 @@ def filter(self, record: logging.LogRecord) -> bool:
return record.levelno <= logging.INFO


def setup_logging(logger_name: str) -> logging.Logger:
logger: logging.Logger = logging.getLogger(logger_name)
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",
}
RESET: ClassVar[Literal["\033[0m"]] = "\033[0m"

stdout_handler: logging.StreamHandler[TextIO] = logging.StreamHandler(sys.stdout)
stdout_handler.set_name("stdout")
stdout_handler.addFilter(_StdOutFilter())
stdout_handler.setFormatter(logging.Formatter("%(message)s"))
stdout_handler.setLevel(logging.DEBUG)

stderr_handler: logging.StreamHandler[TextIO] = logging.StreamHandler(sys.stderr)
stderr_handler.set_name("stderr")
stderr_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
stderr_handler.setLevel(logging.WARNING)

logger.addHandler(stderr_handler)
logger.addHandler(stdout_handler)
return logger
@override
def format(self, record: logging.LogRecord) -> str:
log_color: str = self.COLORS.get(record.levelname, self.RESET)
record.msg = f"{log_color}{record.levelname}: {record.msg}{self.RESET}"
return super().format(record)


def set_logging_level(logger: logging.Logger, *, verbose: bool) -> None:
logger.setLevel(logging.DEBUG if verbose else logging.INFO)
def setup_logging(*, verbose: bool) -> None:
level: Literal["DEBUG", "INFO"] = "DEBUG" if verbose else "INFO"
logging.config.dictConfig(
{
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"simple": {
"format": "%(message)s",
},
"colored": {
"()": _ColoredFormatter,
},
},
"filters": {
"StdOutFilter": {
"()": _StdOutFilter,
},
},
"handlers": {
"stdout": {
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
"formatter": "simple",
"filters": ["StdOutFilter"],
"level": "DEBUG",
},
"stderr": {
"class": "logging.StreamHandler",
"stream": "ext://sys.stderr",
"formatter": "colored",
"level": "WARNING",
},
},
"loggers": {
"root": {
"level": level,
"handlers": ["stdout", "stderr"],
"propagate": True,
},
},
},
)
27 changes: 19 additions & 8 deletions pip_manage/pip_purge.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

import argparse
import importlib.metadata
import logging
from pathlib import Path
from typing import TYPE_CHECKING, Final, NamedTuple

from pip_manage._logging import set_logging_level, setup_logging
from pip_manage._logging import setup_logging
from pip_manage._pip_interface import (
PIP_CMD,
UNINSTALL_ONLY,
Expand All @@ -18,7 +19,6 @@
)

if TYPE_CHECKING:
import logging
from collections.abc import Sequence

_EPILOG: Final[str] = (
Expand All @@ -29,7 +29,7 @@
"""
)

_logger: logging.Logger = setup_logging(__title__)
_logger: logging.Logger = logging.getLogger(__title__)


def _parse_args(
Expand Down Expand Up @@ -189,7 +189,8 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915
) -> int:
args, forwarded = _parse_args(argv)
uninstall_args: list[str] = filter_forwards_include(forwarded, UNINSTALL_ONLY)
set_logging_level(_logger, verbose=args.verbose)
setup_logging(verbose=args.verbose)

_logger.debug("Forwarded arguments: %s", forwarded)
_logger.debug("Arguments forwarded to 'pip uninstall': %s", uninstall_args)

Expand All @@ -201,18 +202,24 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915
"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)
return 1

if not (packages := [*args.packages, *_read_from_requirements(args.requirements)]):
_logger.error("No packages provided")
if not (packages := [*args.packages, *requirements]):
_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("%s 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)
continue

package_dependencies[package] = dependency_info = _get_dependencies_of_package(
Expand Down Expand Up @@ -296,7 +303,11 @@ def main( # pylint: disable=R0914, R0915 # noqa: PLR0915
)

if args.freeze_purged_packages:
_freeze_packages(args.freeze_file, packages_to_uninstall)
try:
_freeze_packages(args.freeze_file, packages_to_uninstall)
except OSError as err:
_logger.error("Could not open requirements file: %s", err)
return 1
_logger.debug("Wrote packages to %s", args.freeze_file)

joined_pip_cmd: str = " ".join(PIP_CMD)
Expand Down
25 changes: 17 additions & 8 deletions pip_manage/pip_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
__title__: Final[str] = "pip-review"

import argparse
import logging
import os
from pathlib import Path
from typing import TYPE_CHECKING, Final, NamedTuple

from pip_manage._logging import set_logging_level, setup_logging
from pip_manage._logging import setup_logging
from pip_manage._pip_interface import (
INSTALL_ONLY,
LIST_ONLY,
Expand All @@ -19,7 +20,6 @@
)

if TYPE_CHECKING:
import logging
from collections.abc import Callable, Sequence

from pip_manage._pip_interface import _OutdatedPackage
Expand All @@ -34,7 +34,7 @@
"""
)

_logger: logging.Logger = setup_logging(__title__)
_logger: logging.Logger = logging.getLogger(__title__)


def _parse_args(
Expand Down Expand Up @@ -239,7 +239,9 @@ def _format_table(columns: list[list[str]]) -> str:
return "\n".join([head, ruler, *body, ruler])


def main(argv: Sequence[str] | None = None) -> int:
def main( # pylint: disable=R0915 # noqa: PLR0915
argv: Sequence[str] | None = None,
) -> int:
args, forwarded = _parse_args(argv)
list_args: list[str] = filter_forwards(
forwarded,
Expand All @@ -251,7 +253,7 @@ def main(argv: Sequence[str] | None = None) -> int:
exclude=LIST_ONLY,
include=INSTALL_ONLY,
)
set_logging_level(_logger, verbose=args.verbose)
setup_logging(verbose=args.verbose)

_logger.debug("Forwarded arguments: %s", forwarded)
_logger.debug("Arguments forwarded to 'pip list --outdated': %s", list_args)
Expand Down Expand Up @@ -286,7 +288,11 @@ def main(argv: Sequence[str] | None = None) -> int:
return 0

if args.freeze_outdated_packages:
_freeze_outdated_packages(args.freeze_file, outdated)
try:
_freeze_outdated_packages(args.freeze_file, outdated)
except OSError as err:
_logger.error("Could not open requirements file: %s", err)
return 1
_logger.debug("Wrote outdated packages to %s", args.freeze_file)

if args.raw:
Expand All @@ -296,8 +302,11 @@ def main(argv: Sequence[str] | None = None) -> int:

constraints_files: list[Path] = _get_constraints_files(install_args)
_logger.debug("Constraints files: %s", constraints_files)

_set_constraints_of_outdated_pkgs(constraints_files, outdated)
try:
_set_constraints_of_outdated_pkgs(constraints_files, outdated)
except OSError as err:
_logger.error("Could not open requirements file: %s", err)
return 1
_logger.debug(
"Outdated packages with new set constraints: %s",
outdated,
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ lint.ignore = [
"B905",
"TD002",
"TD003",
"TRY400",
]
lint.fixable = ["ALL"]
lint.unfixable = []
Expand Down

0 comments on commit 4a57dbb

Please sign in to comment.