Skip to content
Merged
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
20 changes: 12 additions & 8 deletions beets/test/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from pathlib import Path
from tempfile import gettempdir, mkdtemp, mkstemp
from typing import Any, ClassVar
from unittest.mock import patch
from unittest.mock import Mock, patch

import pytest
import responses
Expand Down Expand Up @@ -126,17 +126,21 @@ def config(self) -> beets.IncludeLazyConfig:


class RunMixin:
def run_command(self, *args, **kwargs):
lib: Library

def run_command(self, *args, lib: Library | None = None):
"""Run a beets command with an arbitrary amount of arguments. The
Library` defaults to `self.lib`, but can be overridden with
the keyword argument `lib`.
"""
sys.argv = ["beet"] # avoid leakage from test suite args
lib = None
if hasattr(self, "lib"):
lib = self.lib
lib = kwargs.get("lib", lib)
beets.ui._raw_main(list(args), lib)
sys.argv = ["beet", *args] # avoid leakage from test suite args
lib = lib or self.lib
Comment thread
snejus marked this conversation as resolved.

Comment thread
semohr marked this conversation as resolved.
with (
patch.object(lib, "_close", Mock()),
patch("beets.ui._open_library", return_value=lib),
):
beets.ui._raw_main(list(args))


@pytest.mark.usefixtures("io")
Expand Down
18 changes: 7 additions & 11 deletions beets/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ def parse_subcommand(self, args):


def _setup(
options: optparse.Values, lib: library.Library | None
options: optparse.Values,
) -> tuple[list[Subcommand], library.Library]:
"""Prepare and global state and updates it with command line options.

Expand All @@ -821,9 +821,8 @@ def _setup(
subcommands = list(default_commands)
subcommands.extend(plugins.commands())

if lib is None:
lib = _open_library(config)
plugins.send("library_opened", lib=lib)
lib = _open_library(config)
plugins.send("library_opened", lib=lib)

return subcommands, lib

Expand Down Expand Up @@ -903,7 +902,7 @@ def _open_library(config: confuse.LazyConfig) -> library.Library:
return lib


def _raw_main(args: list[str], lib=None) -> None:
def _raw_main(args: list[str]) -> None:
"""A helper function for `main` without top-level exception
handling.
"""
Expand Down Expand Up @@ -984,20 +983,17 @@ def parse_csl_callback(

return config_edit(options)

test_lib = bool(lib)
subcommands, lib = _setup(options, lib)
subcommands, lib = _setup(options)
parser.add_subcommand(*subcommands)

subcommand, suboptions, subargs = parser.parse_subcommand(subargs)
subcommand.func(lib, suboptions, subargs)

plugins.send("cli_exit", lib=lib)
if not test_lib:
# Clean up the library unless it came from the test harness.
lib._close()
lib._close()


def main(args=None):
def main(args: list[str]) -> None:
"""Run the main command-line interface for beets. Includes top-level
exception handlers that print friendly error messages.
"""
Expand Down
2 changes: 1 addition & 1 deletion test/ui/commands/test_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def test_completion(self):
self.skipTest("could not read bash-completion script")

# Load completion script.
self.run_command("completion", lib=None)
self.run_command("completion")
completion_script = self.io.getoutput().encode("utf-8")
tester.stdin.writelines(completion_script.splitlines(True))

Expand Down
38 changes: 22 additions & 16 deletions test/ui/test_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from beets import config, plugins, ui
from beets.test import _common
from beets.test.helper import BeetsTestCase, IOMixin, PluginTestCase
from beets.ui import commands
from beets.ui import _open_library, commands
from beets.util import syspath


Expand Down Expand Up @@ -126,6 +126,12 @@ def setUp(self):

self._reset_config()

def run_command(self, *args, **kwargs):
# We need to reload the lib based on the
# current config
self.lib = _open_library(self.config)
super().run_command(*args, **kwargs)

def tearDown(self):
self.env_patcher.stop()
commands.default_commands.pop()
Expand Down Expand Up @@ -155,7 +161,7 @@ def test_paths_section_respected(self):
with self.write_config_file() as config:
config.write("paths: {x: y}")

self.run_command("test", lib=None)
self.run_command("test")
key, template = self.test_cmd.lib.path_formats[0]
assert key == "x"
assert template.original == "y"
Expand All @@ -166,7 +172,7 @@ def test_default_paths_preserved(self):
self._reset_config()
with self.write_config_file() as config:
config.write("paths: {x: y}")
self.run_command("test", lib=None)
self.run_command("test")
key, template = self.test_cmd.lib.path_formats[0]
assert key == "x"
assert template.original == "y"
Expand All @@ -178,36 +184,36 @@ def test_nonexistant_db(self):

self.io.addinput("n")
with pytest.raises(ui.UserError):
self.run_command("test", lib=None)
self.run_command("test")

def test_user_config_file(self):
with self.write_config_file() as file:
file.write("anoption: value")

self.run_command("test", lib=None)
self.run_command("test")
assert config["anoption"].get() == "value"

def test_replacements_parsed(self):
with self.write_config_file() as config:
config.write("replace: {'[xy]': z}")

self.run_command("test", lib=None)
self.run_command("test")
replacements = self.test_cmd.lib.replacements
repls = [(p.pattern, s) for p, s in replacements] # Compare patterns.
assert repls == [("[xy]", "z")]

def test_multiple_replacements_parsed(self):
with self.write_config_file() as config:
config.write("replace: {'[xy]': z, foo: bar}")
self.run_command("test", lib=None)
self.run_command("test")
replacements = self.test_cmd.lib.replacements
repls = [(p.pattern, s) for p, s in replacements]
assert repls == [("[xy]", "z"), ("foo", "bar")]

def test_cli_config_option(self):
with open(self.cli_config_path, "w") as file:
file.write("anoption: value")
self.run_command("--config", self.cli_config_path, "test", lib=None)
self.run_command("--config", self.cli_config_path, "test")
assert config["anoption"].get() == "value"

def test_cli_config_file_overwrites_user_defaults(self):
Expand All @@ -216,7 +222,7 @@ def test_cli_config_file_overwrites_user_defaults(self):

with open(self.cli_config_path, "w") as file:
file.write("anoption: cli overwrite")
self.run_command("--config", self.cli_config_path, "test", lib=None)
self.run_command("--config", self.cli_config_path, "test")
assert config["anoption"].get() == "cli overwrite"

def test_cli_config_file_overwrites_beetsdir_defaults(self):
Expand All @@ -226,7 +232,7 @@ def test_cli_config_file_overwrites_beetsdir_defaults(self):

with open(self.cli_config_path, "w") as file:
file.write("anoption: cli overwrite")
self.run_command("--config", self.cli_config_path, "test", lib=None)
self.run_command("--config", self.cli_config_path, "test")
assert config["anoption"].get() == "cli overwrite"

# @unittest.skip('Difficult to implement with optparse')
Expand All @@ -241,7 +247,7 @@ def test_cli_config_file_overwrites_beetsdir_defaults(self):
# file.write('second: value')
#
# self.run_command('--config', cli_config_path_1,
# '--config', cli_config_path_2, 'test', lib=None)
# '--config', cli_config_path_2, 'test')
# assert config['first'].get() == 'value'
# assert config['second'].get() == 'value'
#
Expand All @@ -267,7 +273,7 @@ def test_cli_config_paths_resolve_relative_to_user_dir(self):
file.write("library: beets.db\n")
file.write("statefile: state")

self.run_command("--config", self.cli_config_path, "test", lib=None)
self.run_command("--config", self.cli_config_path, "test")
assert config["library"].as_path() == self.user_config_dir / "beets.db"
assert config["statefile"].as_path() == self.user_config_dir / "state"

Expand All @@ -278,22 +284,22 @@ def test_cli_config_paths_resolve_relative_to_beetsdir(self):
file.write("library: beets.db\n")
file.write("statefile: state")

self.run_command("--config", self.cli_config_path, "test", lib=None)
self.run_command("--config", self.cli_config_path, "test")
assert config["library"].as_path() == self.beetsdir / "beets.db"
assert config["statefile"].as_path() == self.beetsdir / "state"

def test_command_line_option_relative_to_working_dir(self):
config.read()
os.chdir(syspath(self.temp_dir))
self.run_command("--library", "foo.db", "test", lib=None)
self.run_command("--library", "foo.db", "test")
assert config["library"].as_path() == Path.cwd() / "foo.db"

def test_cli_config_file_loads_plugin_commands(self):
with open(self.cli_config_path, "w") as file:
file.write(f"pluginpath: {_common.PLUGINPATH}\n")
file.write("plugins: test")

self.run_command("--config", self.cli_config_path, "plugin", lib=None)
self.run_command("--config", self.cli_config_path, "plugin")
plugs = plugins.find_plugins()
assert len(plugs) == 1
assert plugs[0].is_test_plugin
Expand Down Expand Up @@ -358,7 +364,7 @@ def test_custom_paths_prepend(self):
@_common.slow_test()
class PluginTest(TestPluginTestCase):
def test_plugin_command_from_pluginpath(self):
self.run_command("test", lib=None)
self.run_command("test")


class CommonOptionsParserCliTest(IOMixin, BeetsTestCase):
Expand Down
Loading