Skip to content

Commit

Permalink
Futher improve logging
Browse files Browse the repository at this point in the history
- Move logger instance inside main
- Rename _StdOutFilter to _NonErrorFilter
- Improve dictConfig
- Use hexadecimal escape sequences
  • Loading branch information
realshouzy committed Jun 10, 2024
1 parent 4a57dbb commit d0bce10
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 59 deletions.
24 changes: 12 additions & 12 deletions pip_manage/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@
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


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:
Expand All @@ -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(
{
Expand All @@ -52,7 +52,7 @@ def setup_logging(*, verbose: bool) -> None:
},
"filters": {
"StdOutFilter": {
"()": _StdOutFilter,
"()": _NonErrorFilter,
},
},
"handlers": {
Expand All @@ -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},
},
},
)
49 changes: 24 additions & 25 deletions pip_manage/pip_purge.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
"""
)

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


def _parse_args(
args: Sequence[str] | None = None,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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)),
Expand All @@ -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),
)
Expand All @@ -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)
Expand All @@ -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(
Expand Down
43 changes: 21 additions & 22 deletions pip_manage/pip_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
"""
)

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


def _parse_args(
args: Sequence[str] | None = None,
Expand Down Expand Up @@ -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(
Expand All @@ -326,15 +325,15 @@ 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,
pkg.version,
pkg.constraints_display,
)
else:
_logger.info(
logger.info(
"%s==%s is available (you have %s)",
pkg.name,
pkg.latest_version,
Expand All @@ -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,
Expand Down

0 comments on commit d0bce10

Please sign in to comment.