From e681449785ea4ee2a111c361743f35cee22252ef Mon Sep 17 00:00:00 2001 From: Malte Ried Date: Sun, 1 Feb 2015 17:01:06 +0100 Subject: [PATCH] Added documentation FileFilterPlugin uses the new return value feature Some tweaks to get the code more readable --- beets/importer.py | 44 ++++++++++++++++------------------------- beetsplug/filefilter.py | 7 ++++--- docs/changelog.rst | 3 ++- docs/dev/plugins.rst | 8 +++++--- test/test_plugins.py | 20 +++++++++++++++++++ 5 files changed, 48 insertions(+), 34 deletions(-) diff --git a/beets/importer.py b/beets/importer.py index 9de68d2f1..c15b6b3f3 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -546,9 +546,11 @@ class ImportTask(object): return plugins.send('album_imported', lib=lib, album=self.album) - def emit_created(self, session): - """Send the `import_task_created` event for this task and return a list - of tasks which might be returned by plugins. + def handle_created(self, session): + """Send the `import_task_created` event for this task. Return a list of + tasks that should continue through the pipeline. By default, this is a + list containing only the task itself, but plugins can replace the task + with new ones. """ tasks = plugins.send('import_task_created', session=session, task=self) if not tasks: @@ -557,10 +559,7 @@ class ImportTask(object): # The plugins gave us a list of lists of task. Flatten it. flat_tasks = [] for inner in tasks: - if isinstance(inner, list): - flat_tasks += inner - else: - flat_tasks.append(inner) + flat_tasks += inner tasks = [t for t in flat_tasks if t] return tasks @@ -1020,16 +1019,14 @@ class ImportTaskFactory(object): if self.session.config['singletons']: for path in paths: tasks = self._create(self.singleton(path)) - if tasks: - for task in tasks: - yield task + for task in tasks: + yield task yield self.sentinel(dirs) else: tasks = self._create(self.album(paths, dirs)) - if tasks: - for task in tasks: - yield task + for task in tasks: + yield task # Produce the final sentinel for this toppath to indicate that # it is finished. This is usually just a SentinelImportTask, but @@ -1048,11 +1045,10 @@ class ImportTaskFactory(object): task. If `task` is None, do nothing. """ if task: - tasks = task.emit_created(self.session) - for task in tasks: - if not task.skip: - self.imported += 1 + tasks = task.handle_created(self.session) + self.imported += len(tasks) return tasks + return [] def paths(self): """Walk `self.toppath` and yield `(dirs, files)` pairs where @@ -1205,8 +1201,7 @@ def query_tasks(session): # Search for items. for item in session.lib.items(session.query): task = SingletonImportTask(None, item) - tasks = task.emit_created(session) - for task in tasks: + for task in task.handle_created(session): yield task else: @@ -1223,8 +1218,7 @@ def query_tasks(session): item.album_id = None task = ImportTask(None, [album.item_dir()], items) - tasks = task.emit_created(session) - for task in tasks: + for task in task.handle_created(session): yield task @@ -1272,8 +1266,7 @@ def user_query(session, task): def emitter(task): for item in task.items: task = SingletonImportTask(task.toppath, item) - tasks = task.emit_created(session) - for new_task in tasks: + for new_task in task.handle_created(session): yield new_task yield SentinelImportTask(task.toppath, task.paths) @@ -1384,9 +1377,6 @@ def manipulate_files(session, task): def log_files(session, task): """A coroutine (pipeline stage) to log each file to be imported. """ - if task.skip: - return - if isinstance(task, SingletonImportTask): log.info(u'Singleton: {0}', displayable_path(task.item['path'])) elif task.items: @@ -1413,7 +1403,7 @@ def group_albums(session): tasks = [] for _, items in itertools.groupby(task.items, group): task = ImportTask(items=list(items)) - tasks += task.emit_created(session) + tasks += task.handle_created(session) tasks.append(SentinelImportTask(task.toppath, task.paths)) task = pipeline.multiple(tasks) diff --git a/beetsplug/filefilter.py b/beetsplug/filefilter.py index 1a19d46cc..fbb23aae7 100644 --- a/beetsplug/filefilter.py +++ b/beetsplug/filefilter.py @@ -18,7 +18,7 @@ import re from beets import config from beets.plugins import BeetsPlugin -from beets.importer import action, SingletonImportTask +from beets.importer import SingletonImportTask class FileFilterPlugin(BeetsPlugin): @@ -50,10 +50,11 @@ class FileFilterPlugin(BeetsPlugin): if len(items_to_import) > 0: task.items = items_to_import else: - task.choice_flag = action.SKIP + return [] elif isinstance(task, SingletonImportTask): if not self.file_filter(task.item['path']): - task.choice_flag = action.SKIP + return [] + return [task] def file_filter(self, full_path): """Checks if the configured regular expressions allow the import diff --git a/docs/changelog.rst b/docs/changelog.rst index b8fc19dac..8494c4823 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -96,7 +96,8 @@ For developers: should!) use modern ``{}``-style string formatting lazily. See :ref:`plugin-logging` in the plugin API docs. * A new ``import_task_created`` event lets you manipulate import tasks - immediately after they are initialized. + immediately after they are initialized. It's also possible to replace the + originally created tasks by returning new ones using this event. 1.3.10 (January 5, 2015) diff --git a/docs/dev/plugins.rst b/docs/dev/plugins.rst index e8f32d25f..97da193f0 100644 --- a/docs/dev/plugins.rst +++ b/docs/dev/plugins.rst @@ -175,9 +175,11 @@ The events currently available are: written to disk (i.e., just after the file on disk is closed). * *import_task_created*: called immediately after an import task is - initialized. Plugins can use this to, for example, cancel processing of a - task before anything else happens. ``task`` (an `ImportTask`) and - ``session`` (an `ImportSession`). + initialized. Plugins can use this to, for example, change imported files of a + task before anything else happens. It's also possible to replace the task + with another task by returning a list of tasks. This list can contain zero + or more `ImportTask`s. Returning an empty list will stop the task. + Parameters: ``task`` (an `ImportTask`) and ``session`` (an `ImportSession`). * *import_task_start*: called when before an import task begins processing. Parameters: ``task`` and ``session``. diff --git a/test/test_plugins.py b/test/test_plugins.py index 056be14e4..d46c5bd5d 100644 --- a/test/test_plugins.py +++ b/test/test_plugins.py @@ -207,6 +207,26 @@ class EventsTest(unittest.TestCase, ImportHelper, TestHelper): self.file_paths.append(dest_path) def test_import_task_created(self): + import_files = [self.import_dir] + self._setup_import_session(singletons=False) + self.importer.paths = import_files + + with helper.capture_log() as logs: + self.importer.run() + self.unload_plugins() + + # Exactly one event should have been imported (for the album). + # Sentinels do not get emitted. + self.assertEqual(logs.count('Sending event: import_task_created'), 1) + + logs = [line for line in logs if not line.startswith('Sending event:')] + self.assertEqual(logs, [ + 'Album: {0}'.format(os.path.join(self.import_dir, 'album')), + ' {0}'.format(self.file_paths[0]), + ' {0}'.format(self.file_paths[1]), + ]) + + def test_import_task_created_with_plugin(self): class ToSingletonPlugin(plugins.BeetsPlugin): def __init__(self): super(ToSingletonPlugin, self).__init__()