Skip to content

Commit 61a4c73

Browse files
authored
Refactor ui/commands.py monolith into modular structure (#6119)
## Description This one’s a big one 🎣 Proceed with care and a bit of time ;) The `ui/commands.py` file had grown into an unwieldy monolith (2000+ lines) over time, so this PR breaks it apart into a modular structure i.e. **one file per command**, plus some cleanup and reorganization along the way. --- ### What changed * **Commands modularized:** Every command (`help`, `list`, `move`, `update`, `remove`, etc.) now lives in its own file under `ui/commands/`. * **Support code reorganized:** * Utility functions moved into a separate helper module. * `commands.py` converted into `commands/__init__.py` for better import handling. * The `import` command (and related helpers) moved into its own folder: * `importer/session.py` for import session logic * `importer/display.py` for display-related functions * **Tests cleaned up:** * Each command’s tests now live in their own file. * All UI-related tests were moved into a dedicated folder for clarity.
2 parents beda6fc + f495a9e commit 61a4c73

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+4324
-4191
lines changed

.git-blame-ignore-revs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,9 @@ d93ddf8dd43e4f9ed072a03829e287c78d2570a2
7373
33f1a5d0bef8ca08be79ee7a0d02a018d502680d
7474
# Moved art.py utility module from beets into beetsplug
7575
28aee0fde463f1e18dfdba1994e2bdb80833722f
76+
# Refactor `ui/commands.py` into multiple modules
77+
59c93e70139f70e9fd1c6f3c1bceb005945bec33
78+
# Moved ui.commands._utils into ui.commands.utils
79+
25ae330044abf04045e3f378f72bbaed739fb30d
80+
# Refactor test_ui_command.py into multiple modules
81+
a59e41a88365e414db3282658d2aa456e0b3468a

beets/test/_common.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ def item(lib=None, **kwargs):
107107

108108
# Dummy import session.
109109
def import_session(lib=None, loghandler=None, paths=[], query=[], cli=False):
110-
cls = commands.TerminalImportSession if cli else importer.ImportSession
110+
cls = (
111+
commands.import_.session.TerminalImportSession
112+
if cli
113+
else importer.ImportSession
114+
)
111115
return cls(lib, loghandler, paths, query)
112116

113117

beets/test/helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
from beets.importer import ImportSession
5555
from beets.library import Item, Library
5656
from beets.test import _common
57-
from beets.ui.commands import TerminalImportSession
57+
from beets.ui.commands.import_.session import TerminalImportSession
5858
from beets.util import (
5959
MoveOperation,
6060
bytestring_path,

beets/ui/__init__.py

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,76 +1111,9 @@ def show_model_changes(
11111111
return bool(changes)
11121112

11131113

1114-
def show_path_changes(path_changes):
1115-
"""Given a list of tuples (source, destination) that indicate the
1116-
path changes, log the changes as INFO-level output to the beets log.
1117-
The output is guaranteed to be unicode.
1118-
1119-
Every pair is shown on a single line if the terminal width permits it,
1120-
else it is split over two lines. E.g.,
1121-
1122-
Source -> Destination
1123-
1124-
vs.
1125-
1126-
Source
1127-
-> Destination
1128-
"""
1129-
sources, destinations = zip(*path_changes)
1130-
1131-
# Ensure unicode output
1132-
sources = list(map(util.displayable_path, sources))
1133-
destinations = list(map(util.displayable_path, destinations))
1134-
1135-
# Calculate widths for terminal split
1136-
col_width = (term_width() - len(" -> ")) // 2
1137-
max_width = len(max(sources + destinations, key=len))
1138-
1139-
if max_width > col_width:
1140-
# Print every change over two lines
1141-
for source, dest in zip(sources, destinations):
1142-
color_source, color_dest = colordiff(source, dest)
1143-
print_(f"{color_source} \n -> {color_dest}")
1144-
else:
1145-
# Print every change on a single line, and add a header
1146-
title_pad = max_width - len("Source ") + len(" -> ")
1147-
1148-
print_(f"Source {' ' * title_pad} Destination")
1149-
for source, dest in zip(sources, destinations):
1150-
pad = max_width - len(source)
1151-
color_source, color_dest = colordiff(source, dest)
1152-
print_(f"{color_source} {' ' * pad} -> {color_dest}")
1153-
1154-
11551114
# Helper functions for option parsing.
11561115

11571116

1158-
def _store_dict(option, opt_str, value, parser):
1159-
"""Custom action callback to parse options which have ``key=value``
1160-
pairs as values. All such pairs passed for this option are
1161-
aggregated into a dictionary.
1162-
"""
1163-
dest = option.dest
1164-
option_values = getattr(parser.values, dest, None)
1165-
1166-
if option_values is None:
1167-
# This is the first supplied ``key=value`` pair of option.
1168-
# Initialize empty dictionary and get a reference to it.
1169-
setattr(parser.values, dest, {})
1170-
option_values = getattr(parser.values, dest)
1171-
1172-
try:
1173-
key, value = value.split("=", 1)
1174-
if not (key and value):
1175-
raise ValueError
1176-
except ValueError:
1177-
raise UserError(
1178-
f"supplied argument `{value}' is not of the form `key=value'"
1179-
)
1180-
1181-
option_values[key] = value
1182-
1183-
11841117
class CommonOptionsParser(optparse.OptionParser):
11851118
"""Offers a simple way to add common formatting options.
11861119
@@ -1666,7 +1599,7 @@ def parse_csl_callback(
16661599
and subargs[0] == "config"
16671600
and ("-e" in subargs or "--edit" in subargs)
16681601
):
1669-
from beets.ui.commands import config_edit
1602+
from beets.ui.commands.config import config_edit
16701603

16711604
return config_edit()
16721605

0 commit comments

Comments
 (0)