-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set field values on the import command line #1881 #2581
Conversation
…lds functionality in importer
@bartkl, thanks for your PR! By analyzing the history of the files in this pull request, we identified @mattmurch, @geigerzaehler and @sampsyo to be potential reviewers. |
@@ -25,7 +25,8 @@ import: | |||
pretend: false | |||
search_ids: [] | |||
duplicate_action: ask | |||
bell: no | |||
bell: no |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed a redundant space after 'bell: no'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your patience while I found the time to do a full review! This looks fantastic already; thank you for the careful and complete implementation. ✨ I've left a few suggestions scattered throughout the code.
@@ -530,6 +533,17 @@ def remove_duplicates(self, lib): | |||
util.prune_dirs(os.path.dirname(item.path), | |||
lib.directory) | |||
|
|||
def set_fields(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A docstring here might be nice to have! (Perhaps even nicer than the summary in the overall "step sequence" in the overall class docstring.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added!
beets/importer.py
Outdated
@@ -530,6 +533,17 @@ def remove_duplicates(self, lib): | |||
util.prune_dirs(os.path.dirname(item.path), | |||
lib.directory) | |||
|
|||
def set_fields(self): | |||
set_fields_dict = config['import']['set_fields'] | |||
for field in set_fields_dict.keys(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A simpler way to iterate over Confit dicts:
for key, view in config['import']['set_fields'].items():
value = view.get()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the tip: done.
beets/importer.py
Outdated
field, | ||
value) | ||
self.album[field] = value | ||
self.album.store() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend not including a store
call here. Instead, we can just modify the values before they ever hit the database at all! Another comment below will elaborate…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scratch my previous comment in light of the ordering constraints, but I still recommend "un-indenting" this line so the album get stored only once to update all of its fields. (And the same below for items.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah of course, way better indeed :), will do.
beets/importer.py
Outdated
# If ``set_fields`` is set, set those fields to the | ||
# configured values. | ||
if config['import']['set_fields']: | ||
task.set_fields() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend moving this stanza above the call to task.add
. This way, we'll modify the values on the Album before ever putting them in the database. This will be marginally more efficient and, more importantly, will be a little more predictable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually used to have it structured that way, but it doesn't work. Without the call to task.add
first, there's no album
attribute defined on the task: AttributeError: 'ImportTask' object has no attribute 'album'
.
Please let me know it you have another idea, because I do agree with you it would be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha; got it! That makes sense. Let's leave it where it is—perhaps with a comment to clarify why it's there?—for this version at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a note.
beets/importer.py
Outdated
field, | ||
value) | ||
self.item[field] = value | ||
self.item.store() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(As above.)
beets/ui/commands.py
Outdated
@@ -1017,6 +1018,12 @@ def import_func(lib, opts, args): | |||
metavar='ID', | |||
help=u'restrict matching to a specific metadata backend ID' | |||
) | |||
import_cmd.parser.add_option( | |||
u'--set-field', dest='set_fields', action='callback', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little bit of bikeshedding, but what do you think about the slightly simpler option name --set
? In beets, the only thing you can really "set" is fields, so having "field" in the name feels a teensy bit redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, and there's the metavar
value which makes it sufficiently explicit. I'll change this.
beets/ui/__init__.py
Outdated
@@ -1060,6 +1060,32 @@ def parse_subcommand(self, args): | |||
suboptions, subargs = subcommand.parse_args(args) | |||
return subcommand, suboptions, subargs | |||
|
|||
@staticmethod | |||
def _store_dict(option, opt_str, value, parser): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nice way to parse a series of foo=bar
options! Cool!
But I don't think this needs to be a static method of the SubcommandsOptionParser
class, which is intended for a pretty specific purpose. Can we make it a plain, top-level function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had my doubts on where to place this. I'll follow your advice :).
docs/reference/cli.rst
Outdated
those fields the specified values on import, in addition to such field/value | ||
pairs defined in the ``importer.set_fields`` dictionary in the configuration | ||
file. Make sure to use an option per field/value pair, like so: | ||
:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In ReST, if you just use :: at the end of your paragraph, you'll get a literal : there and mark the following indented block as code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the tip, I improved it.
Thanks for your feedback and kind words :). |
I hope I'm not too much of a burden, but I don't get what goes wrong with the And the merge conflict is probably not something I can or should resolve, right? Thanks! |
Sure. Here are the results of the flake8 run (which you can get by typing
Those are some fairly banal style complaints: just about whitespace. In particular, you'll want to do this: print() # Foo. instead of: print() # Foo. Tiny detail, I know! I'm not seeing any Python 3 test failures on my end—is there a specific message you're looking at? About merge conflicts: it's actually fairly straightforward for you to resolve this on your end. You can just type |
It seems to be fine :). |
Awesome!! Thank you for your hard work on this; I look forward to using this feature myself. Merging now… |
Set field values on the import command line #1881
My first contribution, so be gentle ;).
test_set_fields
functions in theSingletonImportTest
andImportTest
classes.cli.rst
andconfig.rst
, and updated the changelog.tox
seems to approve of my style and the tests (including mine) passI can imagine the
_store_dict
custom callback action I created should be moved elsewhere, but I do think this generic approach is better than a more helper function for theimporter_cmd
specifically.I'd love to hear your comments!