mirror of
https://github.com/beetbox/beets.git
synced 2026-02-27 17:53:12 +01:00
robust difference display for modify
This new alternative to _showdiff takes care of formatting and is better at highlighting differences for non-string fields. This takes care of the issue where "True -> False" would have everything but the "e" highlighted.
This commit is contained in:
parent
8ddf04e711
commit
8303c71b38
1 changed files with 58 additions and 14 deletions
|
|
@ -22,7 +22,6 @@ import os
|
|||
import time
|
||||
import itertools
|
||||
import codecs
|
||||
from datetime import datetime
|
||||
|
||||
import beets
|
||||
from beets import ui
|
||||
|
|
@ -46,8 +45,10 @@ log = logging.getLogger('beets')
|
|||
default_commands = []
|
||||
|
||||
|
||||
|
||||
# Utilities.
|
||||
|
||||
|
||||
def _do_query(lib, query, album, also_items=True):
|
||||
"""For commands that operate on matched items, performs a query
|
||||
and returns a list of matching items and a list of matching
|
||||
|
|
@ -73,6 +74,7 @@ def _do_query(lib, query, album, also_items=True):
|
|||
|
||||
return items, albums
|
||||
|
||||
|
||||
FLOAT_EPSILON = 0.01
|
||||
def _showdiff(field, oldval, newval):
|
||||
"""Print out a human-readable field difference line if `oldval` and
|
||||
|
|
@ -93,6 +95,54 @@ def _showdiff(field, oldval, newval):
|
|||
return False
|
||||
|
||||
|
||||
def _field_diff(field, old, new):
|
||||
"""Given two Model objects, format their values for `field` and
|
||||
highlight changes among them. Return a human-readable string. If the
|
||||
value has not changed, return None instead.
|
||||
"""
|
||||
oldval = old.get(field)
|
||||
newval = new.get(field)
|
||||
|
||||
# If no change, abort.
|
||||
if isinstance(oldval, float) and isinstance(newval, float) and \
|
||||
abs(oldval - newval) < FLOAT_EPSILON:
|
||||
return None
|
||||
elif oldval == newval:
|
||||
return None
|
||||
|
||||
# Get formatted values for output.
|
||||
oldstr = old._get_formatted(field)
|
||||
newstr = new._get_formatted(field)
|
||||
|
||||
# For strings, highlight changes. For others, colorize the whole
|
||||
# thing.
|
||||
if isinstance(oldval, basestring):
|
||||
oldstr, newstr = ui.colordiff(oldval, newval)
|
||||
else:
|
||||
oldstr, newstr = ui.colorize('red', oldstr), ui.colorize('red', newstr)
|
||||
|
||||
return u'{0} -> {1}'.format(oldstr, newstr)
|
||||
|
||||
|
||||
def _show_model_changes(new, old=None):
|
||||
"""Given a Model object, print a list of changes from its pristine
|
||||
version stored in the database. Return a boolean indicating whether
|
||||
any changes were found.
|
||||
"""
|
||||
old = old or new._db._get(type(new), new.id)
|
||||
ui.print_obj(old, old._db)
|
||||
|
||||
changed = False
|
||||
for field in old:
|
||||
line = _field_diff(field, old, new)
|
||||
if line:
|
||||
print_(u' ' + line)
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
# fields: Shows a list of available fields for queries and format strings.
|
||||
|
||||
fields_cmd = ui.Subcommand('fields',
|
||||
|
|
@ -472,8 +522,8 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None,
|
|||
.format(itemcount))
|
||||
print_('For help, see: '
|
||||
'http://beets.readthedocs.org/en/latest/faq.html#nomatch')
|
||||
opts = ('Use as-is', 'as Tracks', 'Group albums', 'Skip', 'Enter search',
|
||||
'enter Id', 'aBort')
|
||||
opts = ('Use as-is', 'as Tracks', 'Group albums', 'Skip',
|
||||
'Enter search', 'enter Id', 'aBort')
|
||||
sel = ui.input_options(opts)
|
||||
if sel == 'u':
|
||||
return importer.action.ASIS
|
||||
|
|
@ -1119,18 +1169,15 @@ def modify_items(lib, mods, query, write, move, album, confirm):
|
|||
items, albums = _do_query(lib, query, album, False)
|
||||
objs = albums if album else items
|
||||
|
||||
# Preview change and collect modified objects.
|
||||
# Apply changes *temporarily*, preview them, and collect modified
|
||||
# objects.
|
||||
print_('Modifying %i %ss.' % (len(objs), 'album' if album else 'item'))
|
||||
changed = set()
|
||||
for obj in objs:
|
||||
# Identify the changed object.
|
||||
ui.print_obj(obj, lib)
|
||||
|
||||
# Show each change.
|
||||
for field, value in fsets.iteritems():
|
||||
if _showdiff(field, obj._get_formatted(field),
|
||||
obj._format(field, value)):
|
||||
changed.add(obj)
|
||||
obj[field] = value
|
||||
if _show_model_changes(obj):
|
||||
changed.add(obj)
|
||||
|
||||
# Still something to do?
|
||||
if not changed:
|
||||
|
|
@ -1146,9 +1193,6 @@ def modify_items(lib, mods, query, write, move, album, confirm):
|
|||
# Apply changes to database.
|
||||
with lib.transaction():
|
||||
for obj in changed:
|
||||
for field, value in fsets.iteritems():
|
||||
obj[field] = value
|
||||
|
||||
if move:
|
||||
cur_path = obj.path
|
||||
if lib.directory in ancestry(cur_path): # In library?
|
||||
|
|
|
|||
Loading…
Reference in a new issue