Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion beets/autotag/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def __getattr__(name: str):
]

# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)

# Metadata fields that are already hardcoded, or where the tag name changes.
SPECIAL_FIELDS = {
Expand Down
2 changes: 1 addition & 1 deletion beets/autotag/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

from .distance import Distance

log = logging.getLogger("beets")
log = logging.getLogger(__name__)

V = TypeVar("V")

Expand Down
2 changes: 1 addition & 1 deletion beets/autotag/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from beets.library import Item

# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)


# Recommendation enumeration.
Expand Down
2 changes: 1 addition & 1 deletion beets/importer/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
QUEUE_SIZE = 128

# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)


class ImportAbortError(Exception):
Expand Down
5 changes: 2 additions & 3 deletions beets/importer/stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
from __future__ import annotations

import itertools
import logging
from typing import TYPE_CHECKING, Callable

from beets import config, plugins
from beets import config, logging, plugins
from beets.util import MoveOperation, displayable_path, pipeline

from .tasks import (
Expand All @@ -35,7 +34,7 @@
from .session import ImportSession

# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)

# ---------------------------- Producer functions ---------------------------- #
# Functions that are called first i.e. they generate import tasks
Expand Down
5 changes: 2 additions & 3 deletions beets/importer/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,20 @@

from __future__ import annotations

import logging
import os
import pickle
from bisect import bisect_left, insort
from dataclasses import dataclass
from typing import TYPE_CHECKING

from beets import config
from beets import config, logging

if TYPE_CHECKING:
from beets.util import PathBytes


# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)


@dataclass
Expand Down
8 changes: 2 additions & 6 deletions beets/importer/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from __future__ import annotations

import logging
import os
import re
import shutil
Expand All @@ -26,7 +25,7 @@

import mediafile

from beets import autotag, config, library, plugins, util
from beets import autotag, config, library, logging, plugins, util
from beets.dbcore.query import PathQuery

from .state import ImportState
Expand All @@ -36,9 +35,6 @@

from .session import ImportSession

# Global logger.
log = logging.getLogger("beets")


SINGLE_ARTIST_THRESH = 0.25

Expand All @@ -62,7 +58,7 @@
REIMPORT_FRESH_FIELDS_ITEM = list(REIMPORT_FRESH_FIELDS_ALBUM)

# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)


class ImportAbortError(Exception):
Expand Down
2 changes: 1 addition & 1 deletion beets/library/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from ..dbcore.query import FieldQuery, FieldQueryType
from .library import Library # noqa: F401

log = logging.getLogger("beets")
log = logging.getLogger(__name__)


class LibModel(dbcore.Model["Library"]):
Expand Down
2 changes: 1 addition & 1 deletion beets/library/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import beets
from beets import dbcore, logging, plugins

log = logging.getLogger("beets")
log = logging.getLogger(__name__)


# Special path format key.
Expand Down
16 changes: 16 additions & 0 deletions beets/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@
WARNING,
FileHandler,
Filter,
Formatter,
Handler,
Logger,
NullHandler,
StreamHandler,
_levelToName,
)

__all__ = [
Expand All @@ -42,14 +44,28 @@
"WARNING",
"FileHandler",
"Filter",
"Formatter",
"Handler",
"Logger",
"NullHandler",
"StreamHandler",
"getLogger",
"getLevelNamesMapping",
]


def getLevelNamesMapping() -> dict[str, int]: # noqa: N802 # Hey, I didn't name it!
"""Returns a mapping from level names to their corresponding logging
levels. For example, the string “CRITICAL” maps to CRITICAL. The returned
mapping is copied from an internal mapping on each call to this function.

Polyfill for `logging.getLevelNamesMapping`, which was only added in Python
3.11.
"""

return {name: level for (level, name) in _levelToName.items()}


def logsafe(val):
"""Coerce `bytes` to `str` to avoid crashes solely due to logging.

Expand Down
2 changes: 1 addition & 1 deletion beets/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
LASTFM_KEY = "2dc3914abf35f0d9c92d97d8f8e42b43"

# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)


class PluginConflictError(Exception):
Expand Down
74 changes: 68 additions & 6 deletions beets/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import traceback
import warnings
from difflib import SequenceMatcher
from typing import TYPE_CHECKING, Any, Callable
from typing import TYPE_CHECKING, Any, Callable, OrderedDict, cast

import confuse

Expand Down Expand Up @@ -1653,11 +1653,7 @@ def _configure(options):
overlay_path = None
config.set_args(options)

# Configure the logger.
if config["verbose"].get(int):
log.set_global_level(logging.DEBUG)
else:
log.set_global_level(logging.INFO)
_configure_logging()

if overlay_path:
log.debug(
Expand All @@ -1677,6 +1673,72 @@ def _configure(options):
return config


def _configure_logging():
"""Configure logging levels and handlers."""

if config["verbose"].get(int):
level = logging.DEBUG
else:
level = logging.INFO

root_logger = logging.getLogger()
beet_logger = logging.getLogger("beets")

root_logger.setLevel(level)
beet_logger.set_global_level(level)

log_format = config["logging"]["format"].get(
confuse.String(default="{message}")
)
date_format = config["logging"]["date_format"].get(
confuse.String(default="%Y-%m-%d %H:%M:%S")
)

# Remove the `StreamHandler` we added earlier so we can make a new one with
# the user's format.
for logger in [log, beet_logger, root_logger]:
stream_handlers = [
handler
for handler in logger.handlers
if isinstance(handler, logging.StreamHandler)
]
for handler in stream_handlers:
logger.removeHandler(handler)

handler = logging.StreamHandler()
handler.setFormatter(
logging.Formatter(
fmt=cast(str, log_format),
datefmt=cast(str, date_format),
style="{",
validate=True,
)
)
logger.addHandler(handler)

level_names_mapping = logging.getLevelNamesMapping()
log_levels = config["logging"]["levels"].get(
confuse.MappingValues(
confuse.OneOf(
allowed=[
confuse.Integer(),
confuse.OneOf(allowed=level_names_mapping.keys()),
]
)
)
)

if log_levels:
for name, level in cast(OrderedDict, log_levels).items():
name = None if name == "root" else name
logger = logging.getLogger(name)
if isinstance(level, str):
level = level_names_mapping[level]
logger.setLevel(level)
if hasattr(logger, "set_global_level"):
logger.set_global_level(level)


def _ensure_db_directory_exists(path):
if path == b":memory:": # in memory db
return
Expand Down
2 changes: 1 addition & 1 deletion beets/ui/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
VARIOUS_ARTISTS = "Various Artists"

# Global logger.
log = logging.getLogger("beets")
log = logging.getLogger(__name__)

# The list of default subcommands. This is populated with Subcommand
# objects that can be fed to a SubcommandsOptionParser.
Expand Down
2 changes: 1 addition & 1 deletion beets/util/artresizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

PROXY_URL = "https://images.weserv.nl/"

log = logging.getLogger("beets")
log = logging.getLogger(__name__)


def resize_url(url: str, maxwidth: int, quality: int = 0) -> str:
Expand Down
2 changes: 1 addition & 1 deletion beets/util/id_extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from beets import logging

log = logging.getLogger("beets")
log = logging.getLogger(__name__)


PATTERN_BY_SOURCE = {
Expand Down
3 changes: 1 addition & 2 deletions beetsplug/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

"""Converts tracks or albums to external directory"""

import logging
import os
import shlex
import subprocess
Expand All @@ -25,7 +24,7 @@
import mediafile
from confuse import ConfigTypeError, Optional

from beets import art, config, plugins, ui, util
from beets import art, config, logging, plugins, ui, util
from beets.library import Item, parse_query_string
from beets.plugins import BeetsPlugin
from beets.util import par_map
Expand Down
5 changes: 4 additions & 1 deletion beetsplug/discogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

import beets
import beets.ui
from beets import config
from beets import config, logging
from beets.autotag.distance import string_dist
from beets.autotag.hooks import AlbumInfo, TrackInfo
from beets.metadata_plugins import MetadataSourcePlugin
Expand All @@ -47,6 +47,9 @@

from beets.library import Item

# Global logger.
log = logging.getLogger(__name__)

USER_AGENT = f"beets/{beets.__version__} +https://beets.io/"
API_KEY = "rAzVUQYRaoFjeBjyWuWZ"
API_SECRET = "plxtUTqoCzwxZpqdPysCwGuBSmZNdZVy"
Expand Down
2 changes: 1 addition & 1 deletion test/plugins/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def test_pretend(self):
assert not self.converted_mp3.exists()

def test_empty_query(self):
with capture_log("beets.convert") as logs:
with capture_log("beets.plugins.convert") as logs:
self.run_convert("An impossible query")
assert logs[0] == "convert: Empty query result."

Expand Down
5 changes: 4 additions & 1 deletion test/plugins/test_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ class HookLogsTest(HookTestCase):
def _configure_logs(self, command: str) -> Iterator[list[str]]:
config = {"hooks": [self._get_hook("test_event", command)]}

with self.configure_plugin(config), capture_log("beets.hook") as logs:
with (
self.configure_plugin(config),
capture_log("beets.plugins.hook") as logs,
):
plugins.send("test_event")
yield logs

Expand Down
2 changes: 1 addition & 1 deletion test/plugins/test_mbsync.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_custom_format(self):
]:
self.lib.add(item)

with capture_log("beets.mbsync") as logs:
with capture_log("beets.plugins.mbsync") as logs:
self.run_command("mbsync", "-f", "'%if{$album,$album,$title}'")

assert "mbsync: Skipping album with no mb_albumid: 'no id'" in logs
Expand Down
Loading