try to reset log-level after setting it (#10800)

This commit is contained in:
skshetry
2025-07-11 20:17:29 +05:45
committed by GitHub
parent be1b529bdf
commit 1b9b1f870a
8 changed files with 55 additions and 35 deletions
+6 -5
View File
@@ -157,6 +157,8 @@ def main(argv=None): # noqa: C901, PLR0912, PLR0915
Returns: Returns:
int: command's return code. int: command's return code.
""" """
from contextlib import ExitStack
from dvc._debug import debugtools from dvc._debug import debugtools
from dvc.config import ConfigError from dvc.config import ConfigError
from dvc.exceptions import DvcException, NotDvcRepoError from dvc.exceptions import DvcException, NotDvcRepoError
@@ -173,12 +175,11 @@ def main(argv=None): # noqa: C901, PLR0912, PLR0915
logging.disable(logging.INFO) logging.disable(logging.INFO)
args = None args = None
stack = ExitStack()
outer_log_level = logger.level
level = None
try: try:
args = parse_args(argv) args = parse_args(argv)
level = None
if args.quiet: if args.quiet:
level = logging.CRITICAL level = logging.CRITICAL
elif args.verbose == 1: elif args.verbose == 1:
@@ -187,7 +188,7 @@ def main(argv=None): # noqa: C901, PLR0912, PLR0915
level = logging.TRACE # type: ignore[attr-defined] level = logging.TRACE # type: ignore[attr-defined]
if level is not None: if level is not None:
set_loggers_level(level) stack.enter_context(set_loggers_level(level))
if level and level <= logging.DEBUG: if level and level <= logging.DEBUG:
from platform import platform, python_implementation, python_version from platform import platform, python_implementation, python_version
@@ -247,7 +248,7 @@ def main(argv=None): # noqa: C901, PLR0912, PLR0915
return ret return ret
finally: finally:
logger.setLevel(outer_log_level) stack.close()
from dvc.repo.open_repo import clean_repos from dvc.repo.open_repo import clean_repos
+14 -2
View File
@@ -5,6 +5,8 @@ import logging.config
import logging.handlers import logging.handlers
import os import os
import sys import sys
from collections.abc import Iterator
from contextlib import contextmanager
from typing import ClassVar from typing import ClassVar
import colorama import colorama
@@ -174,9 +176,19 @@ def _iter_causes(exc):
exc = exc.__cause__ exc = exc.__cause__
def set_loggers_level(level: int = logging.INFO) -> None: @contextmanager
def set_loggers_level(level: int = logging.INFO) -> Iterator[None]:
ret: dict[logging.Logger, int] = {}
for name in ["dvc", "dvc_objects", "dvc_data"]: for name in ["dvc", "dvc_objects", "dvc_data"]:
logging.getLogger(name).setLevel(level) _logger = logging.getLogger(name)
ret[_logger] = _logger.getEffectiveLevel()
_logger.setLevel(level)
try:
yield
finally:
for _logger, old_lvl in ret.items():
_logger.setLevel(old_lvl)
def setup(level: int = logging.INFO, log_colors: bool = True) -> None: def setup(level: int = logging.INFO, log_colors: bool = True) -> None:
+19 -18
View File
@@ -1,20 +1,21 @@
import logging
import os import os
import pickle import pickle
import shutil import shutil
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from collections.abc import Iterable, Iterator from collections.abc import Iterable, Iterator
from contextlib import contextmanager from contextlib import AbstractContextManager, contextmanager
from dataclasses import asdict, dataclass from dataclasses import asdict, dataclass
from enum import IntEnum from enum import IntEnum
from itertools import chain from itertools import chain
from typing import TYPE_CHECKING, Any, Callable, NamedTuple, Optional, Union from typing import TYPE_CHECKING, Any, Callable, NamedTuple, Optional, Union
from funcy import nullcontext
from scmrepo.exceptions import SCMError from scmrepo.exceptions import SCMError
from dvc.env import DVC_EXP_AUTO_PUSH, DVC_EXP_GIT_REMOTE from dvc.env import DVC_EXP_AUTO_PUSH, DVC_EXP_GIT_REMOTE
from dvc.exceptions import DvcException from dvc.exceptions import DvcException
from dvc.log import logger from dvc.log import logger
from dvc.logger import set_loggers_level
from dvc.repo.experiments.exceptions import ExperimentExistsError from dvc.repo.experiments.exceptions import ExperimentExistsError
from dvc.repo.experiments.refs import EXEC_BASELINE, EXEC_BRANCH, ExpRefInfo from dvc.repo.experiments.refs import EXEC_BASELINE, EXEC_BRANCH, ExpRefInfo
from dvc.repo.experiments.utils import to_studio_params from dvc.repo.experiments.utils import to_studio_params
@@ -466,8 +467,8 @@ class BaseExecutor(ABC):
if queue is not None: if queue is not None:
queue.put((rev, os.getpid())) queue.put((rev, os.getpid()))
if log_errors and log_level is not None:
cls._set_log_level(log_level) log_ctx = cls._set_log_level(log_level) if log_errors else nullcontext()
exp_hash: Optional[str] = None exp_hash: Optional[str] = None
exp_ref: Optional[ExpRefInfo] = None exp_ref: Optional[ExpRefInfo] = None
@@ -476,14 +477,17 @@ class BaseExecutor(ABC):
if info.name: if info.name:
ui.write(f"Reproducing experiment '{info.name}'") ui.write(f"Reproducing experiment '{info.name}'")
with cls._repro_dvc( with (
info, log_ctx,
infofile, cls._repro_dvc(
log_errors=log_errors, info,
copy_paths=copy_paths, infofile,
message=message, log_errors=log_errors,
**kwargs, copy_paths=copy_paths,
) as dvc: message=message,
**kwargs,
) as dvc,
):
args, kwargs = cls._repro_args(dvc) args, kwargs = cls._repro_args(dvc)
if args: if args:
targets: Optional[Union[list, str]] = args[0] targets: Optional[Union[list, str]] = args[0]
@@ -786,13 +790,10 @@ class BaseExecutor(ABC):
return orig_rev return orig_rev
@staticmethod @staticmethod
def _set_log_level(level): def _set_log_level(level: Optional[int]) -> AbstractContextManager[None]:
# When executor.reproduce is run in a multiprocessing child process,
# dvc.cli.main will not be called for that child process so we need to
# setup logging ourselves
dvc_logger = logging.getLogger("dvc")
if level is not None: if level is not None:
dvc_logger.setLevel(level) return set_loggers_level(level)
return nullcontext()
@staticmethod @staticmethod
def _copy_path(src, dst): def _copy_path(src, dst):
-1
View File
@@ -175,7 +175,6 @@ filterwarnings = [
"ignore:unclosed database.*sqlite3.Connection:ResourceWarning", "ignore:unclosed database.*sqlite3.Connection:ResourceWarning",
"ignore:unclosed.*<socket.socket:ResourceWarning", "ignore:unclosed.*<socket.socket:ResourceWarning",
] ]
log_level = "debug"
markers = [ markers = [
"needs_internet: Might need network access for the tests", "needs_internet: Might need network access for the tests",
"studio: Tests verifying contract between DVC and Studio", "studio: Tests verifying contract between DVC and Studio",
+5 -5
View File
@@ -1,7 +1,7 @@
import json import json
import os import os
import sys import sys
from contextlib import suppress from contextlib import ExitStack, suppress
import pytest import pytest
@@ -46,10 +46,10 @@ def reset_loglevel(request, caplog):
ini_opt = request.config.getini("log_level") ini_opt = request.config.getini("log_level")
level = request.config.getoption("--log-level") or ini_opt level = request.config.getoption("--log-level") or ini_opt
if level: with ExitStack() as stack:
with caplog.at_level(level.upper(), logger="dvc"): if level:
yield for name in ["dvc", "dvc_data", "dvc_objects"]:
else: stack.enter_context(caplog.at_level(level.upper(), logger=name))
yield yield
+8 -1
View File
@@ -4,6 +4,7 @@ from copy import deepcopy
import pytest import pytest
from dvc import env
from dvc.annotations import Artifact from dvc.annotations import Artifact
from dvc.exceptions import ArtifactNotFoundError, InvalidArgumentError from dvc.exceptions import ArtifactNotFoundError, InvalidArgumentError
from dvc.repo.artifacts import Artifacts, check_name_format from dvc.repo.artifacts import Artifacts, check_name_format
@@ -283,7 +284,13 @@ def test_artifacts_download_subrepo(tmp_dir, scm, sub):
assert Artifacts.get(".", name, force=True) == result assert Artifacts.get(".", name, force=True) == result
def test_artifacts_download_studio(tmp_dir, dvc, mocker): def test_artifacts_download_studio(monkeypatch, tmp_dir, dvc, mocker, tmp_path_factory):
global_config_dir = tmp_path_factory.mktemp("global_config")
monkeypatch.setenv(env.DVC_GLOBAL_CONFIG_DIR, str(global_config_dir))
# reset config to ensure it picks up the new global config
dvc.__dict__.pop("config")
assert dvc.config.files["global"] == os.fspath(global_config_dir / "config")
with dvc.config.edit("global") as conf: with dvc.config.edit("global") as conf:
conf["studio"]["token"] = "mytoken" conf["studio"]["token"] = "mytoken"
+2 -2
View File
@@ -238,9 +238,9 @@ def test_push_pull_unsupported(tmp_dir, dvc, mocker, run_copy, local_remote, cap
mocker.patch.object( mocker.patch.object(
dvc.cloud, "get_remote_odb", side_effect=RunCacheNotSupported("foo") dvc.cloud, "get_remote_odb", side_effect=RunCacheNotSupported("foo")
) )
with caplog.at_level(logging.DEBUG): with caplog.at_level(logging.DEBUG, logger="dvc"):
dvc.push(run_cache=True) dvc.push(run_cache=True)
assert "failed to push run cache" in caplog.text assert "failed to push run cache" in caplog.text
with caplog.at_level(logging.DEBUG): with caplog.at_level(logging.DEBUG, logger="dvc"):
dvc.pull(run_cache=True) dvc.pull(run_cache=True)
assert "failed to pull run cache" in caplog.text assert "failed to pull run cache" in caplog.text
@@ -29,7 +29,7 @@ def test_post_to_studio(
monkeypatch.setenv(DVC_STUDIO_REPO_URL, "STUDIO_REPO_URL") monkeypatch.setenv(DVC_STUDIO_REPO_URL, "STUDIO_REPO_URL")
monkeypatch.setenv(DVC_STUDIO_TOKEN, "STUDIO_TOKEN") monkeypatch.setenv(DVC_STUDIO_TOKEN, "STUDIO_TOKEN")
monkeypatch.setenv(DVC_STUDIO_URL, "https://0.0.0.0") monkeypatch.setenv(DVC_STUDIO_URL, "https://0.0.0.0")
monkeypatch.setenv(DVC_STUDIO_OFFLINE, offline) monkeypatch.setenv(DVC_STUDIO_OFFLINE, str(offline))
if dvc_exp_git_remote: if dvc_exp_git_remote:
monkeypatch.setenv(DVC_EXP_GIT_REMOTE, dvc_exp_git_remote) monkeypatch.setenv(DVC_EXP_GIT_REMOTE, dvc_exp_git_remote)