Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move CLI's logging initialization into a dedicated module #5275

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 5 additions & 16 deletions conda_build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import time
import warnings
from collections import OrderedDict, deque
from logging import getLogger
kenodegard marked this conversation as resolved.
Show resolved Hide resolved
from os.path import dirname, isdir, isfile, islink, join
from pathlib import Path

Expand Down Expand Up @@ -89,6 +90,8 @@
if on_win:
from . import windows

log = getLogger(__name__)
kenodegard marked this conversation as resolved.
Show resolved Hide resolved

if "bsd" in sys.platform:
shell_path = "/bin/sh"
elif utils.on_win:
Expand Down Expand Up @@ -265,7 +268,6 @@ def have_prefix_files(files, prefix):
try:
fi = open(path, "rb+")
except OSError:
log = utils.get_logger(__name__)
log.warn("failed to open %s for detecting prefix. Skipping it." % f)
continue
try:
Expand Down Expand Up @@ -1034,7 +1036,6 @@ def copy_test_source_files(m, destination):
clobber=True,
)
except OSError as e:
log = utils.get_logger(__name__)
log.warn(
f"Failed to copy {f} into test files. Error was: {str(e)}"
)
Expand Down Expand Up @@ -1414,7 +1415,6 @@ def write_about_json(m):
extra = m.get_section("extra")
# Add burn-in information to extra
if m.config.extra_meta:
log = utils.get_logger(__name__)
log.info(
"Adding the following extra-meta data to about.json: %s",
m.config.extra_meta,
Expand Down Expand Up @@ -1721,7 +1721,6 @@ def post_process_files(m: MetaData, initial_prefix_files):
if not os.path.exists(os.path.join(host_prefix, f)):
missing.append(f)
if len(missing):
log = utils.get_logger(__name__)
log.warning(
f"The install/build script(s) for {package_name} deleted the following "
f"files (from dependencies) from the prefix:\n{missing}\n"
Expand Down Expand Up @@ -1804,7 +1803,6 @@ def post_process_files(m: MetaData, initial_prefix_files):


def bundle_conda(output, metadata: MetaData, env, stats, **kw):
log = utils.get_logger(__name__)
log.info("Packaging %s", metadata.dist())
get_all_replacements(metadata.config)
files = output.get("files", [])
Expand Down Expand Up @@ -2265,7 +2263,6 @@ def _write_activation_text(script_path, m):
elif os.path.splitext(script_path)[1].lower() == ".sh":
_write_sh_activation_text(fh, m)
else:
log = utils.get_logger(__name__)
log.warn(
f"not adding activation to {script_path} - I don't know how to do so for "
"this file type"
Expand Down Expand Up @@ -2408,7 +2405,6 @@ def build(
print(utils.get_skip_message(m))
return default_return

log = utils.get_logger(__name__)
host_precs = []
build_precs = []
output_metas = []
Expand Down Expand Up @@ -2943,7 +2939,6 @@ def _construct_metadata_for_test_from_recipe(recipe_dir, config):
metadata = expand_outputs(
render_recipe(recipe_dir, config=config, reset_build_id=False)
)[0][1]
log = utils.get_logger(__name__)
log.warn(
"Testing based on recipes is deprecated as of conda-build 3.16.0. Please adjust "
"your code to pass your desired conda package to test instead."
Expand Down Expand Up @@ -2981,8 +2976,6 @@ def _construct_metadata_for_test_from_package(package, config):
# This is still necessary for computing the hash correctly though
config.variant = hash_input

log = utils.get_logger(__name__)

# get absolute file location
local_pkg_location = os.path.normpath(os.path.abspath(os.path.dirname(package)))

Expand Down Expand Up @@ -3183,7 +3176,6 @@ def _write_test_run_script(
shell_files,
trace,
):
log = utils.get_logger(__name__)
with open(test_run_script, "w") as tf:
tf.write(
'{source} "{test_env_script}"\n'.format(
Expand Down Expand Up @@ -3342,7 +3334,6 @@ def test(
:param m: Package's metadata.
:type m: Metadata
"""
log = utils.get_logger(__name__)
# we want to know if we're dealing with package input. If so, we can move the input on success.
hash_input = {}

Expand Down Expand Up @@ -3625,7 +3616,6 @@ def tests_failed(package_or_metadata, move_broken, broken_dir, config):
dest = join(broken_dir, os.path.basename(pkg))

if move_broken:
log = utils.get_logger(__name__)
try:
shutil.move(pkg, dest)
log.warn(
Expand Down Expand Up @@ -3784,7 +3774,6 @@ def build_tree(
)
]
)
log = utils.get_logger(__name__)
# downstreams can be a dict, for adding capability for worker labels
if hasattr(downstreams, "keys"):
downstreams = list(downstreams.keys())
Expand Down Expand Up @@ -4121,11 +4110,11 @@ def handle_pypi_upload(wheels, config):
try:
utils.check_call_env(args + [f])
except:
utils.get_logger(__name__).warn(
log.warn(
"wheel upload failed - is twine installed?"
" Is this package registered?"
)
utils.get_logger(__name__).warn(f"Wheel file left in {f}")
log.warn(f"Wheel file left in {f}")

else:
print(f"anaconda_upload is not set. Not uploading wheels: {wheels}")
Expand Down
76 changes: 76 additions & 0 deletions conda_build/cli/logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (C) 2014 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import os
import os.path
import sys
from logging import INFO, WARNING, Filter, Formatter, StreamHandler, getLogger
kenodegard marked this conversation as resolved.
Show resolved Hide resolved
from logging.config import dictConfig
from pathlib import Path
from typing import TYPE_CHECKING

from conda.base.context import context
from yaml import safe_load

if TYPE_CHECKING:
from logging import LogRecord


# https://stackoverflow.com/a/31459386/1170370
class LessThanFilter(Filter):
def __init__(self, exclusive_maximum: int, name: str = "") -> None:
super().__init__(name)
self.max_level = exclusive_maximum

def filter(self, record: LogRecord) -> bool:
return record.levelno < self.max_level


class GreaterThanFilter(Filter):
def __init__(self, exclusive_minimum: int, name: str = "") -> None:
super().__init__(name)
self.min_level = exclusive_minimum

def filter(self, record: LogRecord) -> bool:
return record.levelno > self.min_level


class DuplicateFilter(Filter):
msgs: set[str] = set()

def filter(self, record: LogRecord) -> bool:
try:
return record.msg not in self.msgs
finally:
self.msgs.add(record.msg)


def init_logging() -> None:
"""
Default initialization of logging for conda-build CLI.

When using conda-build as a CLI tool (not as a library) we wish to limit logging to
avoid duplication and to otherwise offer some default behavior.
"""
config_file = context.conda_build.get("log_config_file")
if config_file:
config_file = os.path.expandvars(config_file)
dictConfig(safe_load(Path(config_file).expanduser().resolve().read_text()))

log = getLogger("conda_build")

# we don't want propagation in CLI, but we do want it in tests
# this is a pytest limitation: https://github.com/pytest-dev/pytest/issues/3697
log.propagate = "PYTEST_CURRENT_TEST" in os.environ

if not log.handlers:
log.addHandler(stdout := StreamHandler(sys.stdout))
stdout.addFilter(LessThanFilter(WARNING))
stdout.addFilter(DuplicateFilter())
stdout.setFormatter(Formatter("%(levelname)s: %(message)s"))

log.addHandler(stderr := StreamHandler(sys.stderr))
stderr.addFilter(GreaterThanFilter(INFO))
stderr.addFilter(DuplicateFilter())
stderr.setFormatter(Formatter("%(levelname)s: %(message)s"))
10 changes: 8 additions & 2 deletions conda_build/cli/main_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from __future__ import annotations

import argparse
import logging
import sys
import warnings
from glob import glob
from itertools import chain
from logging import CRITICAL, getLogger
from os.path import abspath, expanduser, expandvars
from pathlib import Path
from typing import TYPE_CHECKING
Expand All @@ -33,6 +33,8 @@

from ..conda_interface import ArgumentParser

log = getLogger(__name__)


def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:
parser = get_render_parser()
Expand Down Expand Up @@ -502,7 +504,7 @@ def check_recipe(path_list):


def output_action(recipe, config):
with LoggingContext(logging.CRITICAL + 1):
with LoggingContext(CRITICAL + 1):
config.verbose = False
config.debug = False
paths = api.get_output_file_paths(recipe, config=config)
Expand All @@ -524,6 +526,10 @@ def check_action(recipe, config):


def execute(args: Sequence[str] | None = None) -> int:
from .logging import init_logging

init_logging()

_, parsed = parse_args(args)
config = get_or_merge_config(None, **parsed.__dict__)
build.check_external()
Expand Down
8 changes: 6 additions & 2 deletions conda_build/cli/main_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import logging
from logging import getLogger
from os.path import abspath, expanduser
from typing import TYPE_CHECKING

Expand All @@ -13,7 +13,7 @@
from argparse import Namespace
from typing import Sequence

logging.basicConfig(level=logging.INFO)
log = getLogger(__name__)

epilog = """

Expand Down Expand Up @@ -124,6 +124,10 @@ def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:


def execute(args: Sequence[str] | None = None) -> int:
from .logging import init_logging
kenodegard marked this conversation as resolved.
Show resolved Hide resolved

init_logging()

_, parsed = parse_args(args)
files = parsed.files
del parsed.__dict__["files"]
Expand Down
8 changes: 6 additions & 2 deletions conda_build/cli/main_debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import logging
import sys
from logging import getLogger
from typing import TYPE_CHECKING

from .. import api
Expand All @@ -15,7 +15,7 @@
from argparse import ArgumentParser
from typing import Sequence

logging.basicConfig(level=logging.INFO)
log = getLogger(__name__)


def get_parser() -> ArgumentParser:
Expand Down Expand Up @@ -92,6 +92,10 @@ def get_parser() -> ArgumentParser:


def execute(args: Sequence[str] | None = None) -> int:
from .logging import init_logging

init_logging()

parser = get_parser()
parsed = parser.parse_args(args)

Expand Down
8 changes: 6 additions & 2 deletions conda_build/cli/main_develop.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import logging
from logging import getLogger
from typing import TYPE_CHECKING

from conda.base.context import context, determine_target_prefix
Expand All @@ -14,7 +14,7 @@
from argparse import Namespace
from typing import Sequence

logging.basicConfig(level=logging.INFO)
log = getLogger(__name__)


def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:
Expand Down Expand Up @@ -80,6 +80,10 @@ def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:


def execute(args: Sequence[str] | None = None) -> int:
from .logging import init_logging

init_logging()

_, parsed = parse_args(args)
prefix = determine_target_prefix(context, parsed)
api.develop(
Expand Down
8 changes: 6 additions & 2 deletions conda_build/cli/main_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import logging
import sys
from logging import getLogger
from os.path import expanduser
from pprint import pprint
from typing import TYPE_CHECKING
Expand All @@ -17,7 +17,7 @@
from argparse import Namespace
from typing import Sequence

logging.basicConfig(level=logging.INFO)
log = getLogger(__name__)


def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:
Expand Down Expand Up @@ -188,6 +188,10 @@ def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:


def execute(args: Sequence[str] | None = None) -> int:
from .logging import init_logging

init_logging()

parser, parsed = parse_args(args)

if not parsed.subcommand:
Expand Down