From e801f83da4d209315a688ee1c3707a064fdbddd4 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sat, 25 May 2024 17:29:50 +0200 Subject: [PATCH 01/17] Introduce TaggingScriptSetting and few helper methods --- picard/script/__init__.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/picard/script/__init__.py b/picard/script/__init__.py index 8d9ec9ccf..84ee4f469 100644 --- a/picard/script/__init__.py +++ b/picard/script/__init__.py @@ -66,6 +66,31 @@ from picard.script.parser import ( # noqa: F401 # pylint: disable=unused-import from picard.script.serializer import FileNamingScript +class TaggingScriptSetting: + def __init__(self, pos=0, name="", enabled=False, content=""): + self.pos = pos + self.name = name + self.enabled = enabled + self.content = content + + +def iter_tagging_scripts_from_config(config=None): + if config is None: + config = get_config() + yield from iter_tagging_scripts_from_tuples(config.setting['list_of_scripts']) + + +def iter_tagging_scripts_from_tuples(tuples): + for pos, name, enabled, content in tuples: + yield TaggingScriptSetting(pos=pos, name=name, enabled=enabled, content=content) + + +def save_tagging_scripts_to_config(scripts, config=None): + if config is None: + config = get_config() + config.setting['list_of_scripts'] = [(s.pos, s.name, s.enabled, s.content) for s in scripts] + + class ScriptFunctionDocError(Exception): pass From fe88e79665b02b10bb733dbc61c24569ea558690 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 16:11:32 +0200 Subject: [PATCH 02/17] Use iter_tagging_scripts_from_*() --- picard/script/__init__.py | 2 +- picard/ui/options/profiles.py | 7 +++++-- picard/ui/scripteditor.py | 7 ++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/picard/script/__init__.py b/picard/script/__init__.py index 84ee4f469..918c7180f 100644 --- a/picard/script/__init__.py +++ b/picard/script/__init__.py @@ -142,7 +142,7 @@ def enabled_tagger_scripts_texts(): config = get_config() if not config.setting['enable_tagger_scripts']: return [] - return [(s_name, s_text) for _s_pos, s_name, s_enabled, s_text in config.setting['list_of_scripts'] if s_enabled and s_text] + return [(s.name, s.content) for s in iter_tagging_scripts_from_config(config=config) if s.enabled and s.content] def get_file_naming_script(settings): diff --git a/picard/ui/options/profiles.py b/picard/ui/options/profiles.py index 221349e46..07dba374f 100644 --- a/picard/ui/options/profiles.py +++ b/picard/ui/options/profiles.py @@ -44,7 +44,10 @@ from picard.i18n import ( gettext_constants, ) from picard.profile import profile_groups_values -from picard.script import get_file_naming_script_presets +from picard.script import ( + get_file_naming_script_presets, + iter_tagging_scripts_from_tuples, +) from picard.util import get_base_title from picard.ui.forms.ui_options_profiles import Ui_ProfileEditorDialog @@ -249,7 +252,7 @@ class ProfilesOptionsPage(OptionsPage): return _("Unknown script") def _get_scripts_list(self, scripts): - enabled_scripts = ['
  • %s
  • ' % name for (pos, name, enabled, script) in scripts if enabled] + enabled_scripts = ['
  • %s
  • ' % s.name for s in iter_tagging_scripts_from_tuples(scripts) if s.enabled] if not enabled_scripts: return _("No enabled scripts") return _("Enabled scripts:") + '' diff --git a/picard/ui/scripteditor.py b/picard/ui/scripteditor.py index 867ccc4bd..ae9fb43fe 100644 --- a/picard/ui/scripteditor.py +++ b/picard/ui/scripteditor.py @@ -57,6 +57,7 @@ from picard.script import ( ScriptParser, get_file_naming_script, get_file_naming_script_presets, + iter_tagging_scripts_from_tuples, ) from picard.script.serializer import ( FileNamingScript, @@ -162,10 +163,10 @@ class ScriptEditorExamples(): try: # Only apply scripts if the original file metadata has not been changed. if self.settings['enable_tagger_scripts'] and not c_metadata.diff(file.orig_metadata): - for s_pos, s_name, s_enabled, s_text in self.settings['list_of_scripts']: - if s_enabled and s_text: + for s in iter_tagging_scripts_from_tuples(self.settings['list_of_scripts']): + if s.enabled and s.content: parser = ScriptParser() - parser.eval(s_text, c_metadata) + parser.eval(s.content, c_metadata) filename_before = file.filename filename_after = file.make_filename(filename_before, c_metadata, self.settings, self.script_text) if not self.settings['move_files']: From 2207e9f034b9486345baa51926794e9c60ddda24 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 16:13:14 +0200 Subject: [PATCH 03/17] Pass TaggingScriptSetting instance if possible --- picard/ui/itemviews/basetreeview.py | 6 +++--- picard/ui/options/scripting.py | 29 +++++++++++++++----------- picard/ui/scriptsmenu.py | 10 ++++----- picard/ui/widgets/scriptlistwidget.py | 30 +++++++++++++++++---------- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/picard/ui/itemviews/basetreeview.py b/picard/ui/itemviews/basetreeview.py index d223d5cbc..82003dab5 100644 --- a/picard/ui/itemviews/basetreeview.py +++ b/picard/ui/itemviews/basetreeview.py @@ -75,6 +75,7 @@ from picard.extension_points.item_actions import ( ) from picard.file import File from picard.i18n import gettext as _ +from picard.script import iter_tagging_scripts_from_tuples from picard.track import ( NonAlbumTrack, Track, @@ -403,8 +404,6 @@ class BaseTreeView(QtWidgets.QTreeWidget): CollectionMenu(selected_albums, _("Collections"), menu), ) - scripts = config.setting['list_of_scripts'] - if plugin_actions: plugin_menu = QtWidgets.QMenu(_("P&lugins"), menu) plugin_menu.setIcon(self.icon_plugins) @@ -424,8 +423,9 @@ class BaseTreeView(QtWidgets.QTreeWidget): action_menu = plugin_menus[key] = action_menu.addMenu(key[-1]) action_menu.addAction(action) + scripts = config.setting['list_of_scripts'] if scripts: - scripts_menu = ScriptsMenu(scripts, _("&Run scripts"), menu) + scripts_menu = ScriptsMenu(iter_tagging_scripts_from_tuples(scripts), _("&Run scripts"), menu) scripts_menu.setIcon(self.icon_plugins) add_actions( '-', diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index b75158112..063bc9f41 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -40,7 +40,12 @@ from picard.i18n import ( N_, gettext as _, ) -from picard.script import ScriptParser +from picard.script import ( + ScriptParser, + TaggingScriptSetting, + iter_tagging_scripts_from_config, + save_tagging_scripts_to_config, +) from picard.script.serializer import ( ScriptImportExportError, TaggingScript, @@ -170,7 +175,8 @@ class ScriptingOptionsPage(OptionsPage): return if script_item: title = _("%s (imported)") % script_item['title'] - list_item = ScriptListWidgetItem(title, False, script_item['script']) + script = TaggingScriptSetting(name=title, enabled=False, content=script_item['script']) + list_item = ScriptListWidgetItem(script) self.ui.script_list.addItem(list_item) self.ui.script_list.setCurrentRow(self.ui.script_list.count() - 1) @@ -183,11 +189,10 @@ class ScriptingOptionsPage(OptionsPage): return item = items[0] - script_text = item.script - script_title = item.name if item.name.strip() else _("Unnamed Script") + script_title = item.script.name if item.script.name.strip() else _("Unnamed Script") - if script_text: - script_item = TaggingScript(title=script_title, script=script_text) + if item.script.content: + script_item = TaggingScript(title=script_title, script=item.script.content) try: script_item.export_script(parent=self) except ScriptImportExportError as error: @@ -202,7 +207,7 @@ class ScriptingOptionsPage(OptionsPage): if items: item = items[0] self.ui.tagger_script.setEnabled(True) - self.ui.tagger_script.setText(item.script) + self.ui.tagger_script.setText(item.script.content) self.ui.tagger_script.setFocus(QtCore.Qt.FocusReason.OtherFocusReason) self.ui.export_button.setEnabled(True) else: @@ -215,7 +220,7 @@ class ScriptingOptionsPage(OptionsPage): if not items: return script = items[0] - script.script = self.ui.tagger_script.toPlainText() + script.script.content = self.ui.tagger_script.toPlainText() self.ui.script_error.setStyleSheet("") self.ui.script_error.setText("") try: @@ -248,8 +253,8 @@ class ScriptingOptionsPage(OptionsPage): config = get_config() self.ui.enable_tagger_scripts.setChecked(config.setting['enable_tagger_scripts']) self.ui.script_list.clear() - for pos, name, enabled, text in config.setting['list_of_scripts']: - list_item = ScriptListWidgetItem(name, enabled, text) + for script in iter_tagging_scripts_from_config(config=config): + list_item = ScriptListWidgetItem(script) self.ui.script_list.addItem(list_item) # Select the last selected script item @@ -261,12 +266,12 @@ class ScriptingOptionsPage(OptionsPage): def _all_scripts(self): for item in qlistwidget_items(self.ui.script_list): - yield item.get_all() + yield item.get_script() def save(self): config = get_config() config.setting['enable_tagger_scripts'] = self.ui.enable_tagger_scripts.isChecked() - config.setting['list_of_scripts'] = list(self._all_scripts()) + save_tagging_scripts_to_config(self._all_scripts()) config.persist['last_selected_script_pos'] = self.ui.script_list.currentRow() def display_error(self, error): diff --git a/picard/ui/scriptsmenu.py b/picard/ui/scriptsmenu.py index 00f55b08b..11b991e39 100644 --- a/picard/ui/scriptsmenu.py +++ b/picard/ui/scriptsmenu.py @@ -46,23 +46,21 @@ class ScriptsMenu(QtWidgets.QMenu): super().__init__(*args) for script in scripts: - action = self.addAction(script[1]) + action = self.addAction(script.name) action.triggered.connect(partial(self._run_script, script)) def _run_script(self, script): - s_name = script[1] - s_text = script[3] parser = ScriptParser() for obj in self._iter_unique_metadata_objects(): try: - parser.eval(s_text, obj.metadata) + parser.eval(script.content, obj.metadata) obj.update() except ScriptError as e: - log.exception('Error running tagger script "%s" on object %r', s_name, obj) + log.exception('Error running tagger script "%s" on object %r', script.name, obj) msg = N_('Script error in "%(script)s": %(message)s') mparms = { - 'script': s_name, + 'script': script.name, 'message': str(e), } self.tagger.window.set_statusbar_message(msg, mparms) diff --git a/picard/ui/widgets/scriptlistwidget.py b/picard/ui/widgets/scriptlistwidget.py index 1b7706308..a39f184cc 100644 --- a/picard/ui/widgets/scriptlistwidget.py +++ b/picard/ui/widgets/scriptlistwidget.py @@ -35,6 +35,7 @@ from picard.i18n import ( gettext as _, gettext_constants, ) +from picard.script import TaggingScriptSetting from picard.util import unique_numbered_title from picard.ui import HashableListWidgetItem @@ -77,7 +78,7 @@ class ScriptListWidget(QtWidgets.QListWidget): def add_script(self): numbered_name = self.unique_script_name() - list_item = ScriptListWidgetItem(name=numbered_name) + list_item = ScriptListWidgetItem(TaggingScriptSetting(name=numbered_name, enabled=True)) list_item.setCheckState(QtCore.Qt.CheckState.Checked) self.addItem(list_item) self.setCurrentItem(list_item, QtCore.QItemSelectionModel.SelectionFlag.Clear @@ -114,14 +115,15 @@ class ScriptListWidget(QtWidgets.QListWidget): class ScriptListWidgetItem(HashableListWidgetItem): """Holds a script's list and text widget properties""" - def __init__(self, name=None, enabled=True, script=""): - super().__init__(name) + def __init__(self, script): + assert isinstance(script, TaggingScriptSetting) + super().__init__(script.name) self.setFlags(self.flags() | QtCore.Qt.ItemFlag.ItemIsUserCheckable | QtCore.Qt.ItemFlag.ItemIsEditable) - if name is None: - name = gettext_constants(DEFAULT_SCRIPT_NAME) - self.setText(name) - self.setCheckState(QtCore.Qt.CheckState.Checked if enabled else QtCore.Qt.CheckState.Unchecked) - self.script = script + if not script.name: + script.name = gettext_constants(DEFAULT_SCRIPT_NAME) + self.setText(script.name) + self.setCheckState(QtCore.Qt.CheckState.Checked if script.enabled else QtCore.Qt.CheckState.Unchecked) + self._script = script self.has_error = False @property @@ -136,6 +138,12 @@ class ScriptListWidgetItem(HashableListWidgetItem): def enabled(self): return self.checkState() == QtCore.Qt.CheckState.Checked - def get_all(self): - # tuples used to get pickle dump of settings to work - return (self.pos, self.name, self.enabled, self.script) + @property + def script(self): + return self._script + + def get_script(self): + self._script.pos = self.pos + self._script.name = self.name + self._script.enabled = self.enabled + return self._script From 1f49e7809f9072a39b5984ee23bafe4b0282a8fb Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 16:25:47 +0200 Subject: [PATCH 04/17] Replace enabled_tagger_scripts_texts() with iter_active_tagging_scripts() - it iterates over enabled and non-empty tagger scripts - it yields TaggingScriptSetting objects --- picard/album.py | 12 ++++++------ picard/script/__init__.py | 14 ++++++++------ picard/track.py | 8 ++++---- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/picard/album.py b/picard/album.py index 95a9c3f38..cbaf7febb 100644 --- a/picard/album.py +++ b/picard/album.py @@ -82,7 +82,7 @@ from picard.plugin import ( from picard.script import ( ScriptError, ScriptParser, - enabled_tagger_scripts_texts, + iter_active_tagging_scripts, ) from picard.track import Track from picard.util import ( @@ -474,21 +474,21 @@ class Album(DataObject, MetadataItem): track.metadata_images_changed.connect(self.update_metadata_images) # Prepare parser for user's script - for s_name, s_text in enabled_tagger_scripts_texts(): + for script in iter_active_tagging_scripts(): parser = ScriptParser() for track in self._new_tracks: # Run tagger script for each track try: - parser.eval(s_text, track.metadata) + parser.eval(script.content, track.metadata) except ScriptError: - log.exception("Failed to run tagger script %s on track", s_name) + log.exception("Failed to run tagger script %s on track", script.name) track.metadata.strip_whitespace() track.scripted_metadata.update(track.metadata) # Run tagger script for the album itself try: - parser.eval(s_text, self._new_metadata) + parser.eval(script.content, self._new_metadata) except ScriptError: - log.exception("Failed to run tagger script %s on album", s_name) + log.exception("Failed to run tagger script %s on album", script.name) self._new_metadata.strip_whitespace() unmatched_files = [file for track in self.tracks for file in track.files] diff --git a/picard/script/__init__.py b/picard/script/__init__.py index 918c7180f..10d34c31a 100644 --- a/picard/script/__init__.py +++ b/picard/script/__init__.py @@ -136,13 +136,15 @@ def script_function_documentation_all(fmt='markdown', pre='', return "\n".join(doc_elements) -def enabled_tagger_scripts_texts(): - """Returns an iterator over the enabled tagger scripts. - For each script, you'll get a tuple consisting of the script name and text""" - config = get_config() +def iter_active_tagging_scripts(config=None): + """Returns an iterator over the enabled and not empty tagging scripts.""" + if config is None: + config = get_config() if not config.setting['enable_tagger_scripts']: - return [] - return [(s.name, s.content) for s in iter_tagging_scripts_from_config(config=config) if s.enabled and s.content] + return + for script in iter_tagging_scripts_from_config(config=config): + if script.enabled and script.content: + yield script def get_file_naming_script(settings): diff --git a/picard/track.py b/picard/track.py index d3c35cd77..7d42fd3ff 100644 --- a/picard/track.py +++ b/picard/track.py @@ -71,7 +71,7 @@ from picard.metadata import ( from picard.script import ( ScriptError, ScriptParser, - enabled_tagger_scripts_texts, + iter_active_tagging_scripts, ) from picard.util import pattern_as_regex from picard.util.imagelist import ImageList @@ -201,12 +201,12 @@ class Track(DataObject, FileListItem): @staticmethod def run_scripts(metadata, strip_whitespace=False): - for s_name, s_text in enabled_tagger_scripts_texts(): + for script in iter_active_tagging_scripts(): parser = ScriptParser() try: - parser.eval(s_text, metadata) + parser.eval(script.content, metadata) except ScriptError: - log.exception("Failed to run tagger script %s on track", s_name) + log.exception("Failed to run tagger script %s on track", script.name) if strip_whitespace: metadata.strip_whitespace() From 9bf130dc06cb7f7ff3bde3f3233f74d83b6eda2f Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:03:04 +0200 Subject: [PATCH 05/17] export_script(): rename variables and simplify code --- picard/ui/options/scripting.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index 063bc9f41..de2e05ffd 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -184,17 +184,18 @@ class ScriptingOptionsPage(OptionsPage): """Export the current script to an external file. Export can be either as a plain text script or a naming script package. """ - items = self.ui.script_list.selectedItems() - if not items: + list_items = self.ui.script_list.selectedItems() + if not list_items: return - item = items[0] - script_title = item.script.name if item.script.name.strip() else _("Unnamed Script") - - if item.script.content: - script_item = TaggingScript(title=script_title, script=item.script.content) + list_item = list_items[0] + content = list_item.script.content + if content: + name = list_item.script.name.strip() + title = name or _("Unnamed Script") + tagging_script = TaggingScript(title=title, script=content) try: - script_item.export_script(parent=self) + tagging_script.export_script(parent=self) except ScriptImportExportError as error: self.output_file_error(error) From e70d1fbda04270797b824550da232d091aff9768 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:05:38 +0200 Subject: [PATCH 06/17] script_item -> tagging_script --- picard/ui/options/scripting.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index de2e05ffd..422cb79d7 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -169,13 +169,13 @@ class ScriptingOptionsPage(OptionsPage): a Picard script package. """ try: - script_item = TaggingScript().import_script(self) + tagging_script = TaggingScript().import_script(self) except ScriptImportExportError as error: self.output_file_error(error) return - if script_item: - title = _("%s (imported)") % script_item['title'] - script = TaggingScriptSetting(name=title, enabled=False, content=script_item['script']) + if tagging_script: + title = _("%s (imported)") % tagging_script['title'] + script = TaggingScriptSetting(name=title, enabled=False, content=tagging_script['script']) list_item = ScriptListWidgetItem(script) self.ui.script_list.addItem(list_item) self.ui.script_list.setCurrentRow(self.ui.script_list.count() - 1) From dec700e9ed2c7937e521ff79261938359ba6b6ab Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:08:43 +0200 Subject: [PATCH 07/17] Consistently name list items list_item(s) --- picard/ui/options/scripting.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index 422cb79d7..37dd86050 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -204,11 +204,11 @@ class ScriptingOptionsPage(OptionsPage): self.ui.script_list.add_script() def script_selected(self): - items = self.ui.script_list.selectedItems() - if items: - item = items[0] + list_items = self.ui.script_list.selectedItems() + if list_items: + list_item = list_items[0] self.ui.tagger_script.setEnabled(True) - self.ui.tagger_script.setText(item.script.content) + self.ui.tagger_script.setText(list_item.script.content) self.ui.tagger_script.setFocus(QtCore.Qt.FocusReason.OtherFocusReason) self.ui.export_button.setEnabled(True) else: @@ -217,21 +217,21 @@ class ScriptingOptionsPage(OptionsPage): self.ui.export_button.setEnabled(False) def live_update_and_check(self): - items = self.ui.script_list.selectedItems() - if not items: + list_items = self.ui.script_list.selectedItems() + if not list_items: return - script = items[0] - script.script.content = self.ui.tagger_script.toPlainText() + list_item = list_items[0] + list_item.script.content = self.ui.tagger_script.toPlainText() self.ui.script_error.setStyleSheet("") self.ui.script_error.setText("") try: self.check() except OptionsCheckError as e: - script.has_error = True + list_item.has_error = True self.ui.script_error.setStyleSheet(self.STYLESHEET_ERROR) self.ui.script_error.setText(e.info) return - script.has_error = False + list_item.has_error = False def reset_selected_item(self): widget = self.ui.script_list From 3761c7e4921b78dbda3b113a3d4ce86456b1c582 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:26:03 +0200 Subject: [PATCH 08/17] TaggingScript -> PicardTaggingScript - it's less ambiguous vs TaggingScriptSetting - it's a subclass of PicardScript --- picard/script/serializer.py | 2 +- picard/ui/options/scripting.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/picard/script/serializer.py b/picard/script/serializer.py index 65763bfb9..435c71c1d 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -367,7 +367,7 @@ class PicardScript(): )) -class TaggingScript(PicardScript): +class PicardTaggingScript(PicardScript): """Picard tagging script class """ TYPE = PicardScriptType.TAGGER diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index 37dd86050..83f84c89e 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -47,8 +47,8 @@ from picard.script import ( save_tagging_scripts_to_config, ) from picard.script.serializer import ( + PicardTaggingScript, ScriptImportExportError, - TaggingScript, ) from picard.ui import ( @@ -169,7 +169,7 @@ class ScriptingOptionsPage(OptionsPage): a Picard script package. """ try: - tagging_script = TaggingScript().import_script(self) + tagging_script = PicardTaggingScript().import_script(self) except ScriptImportExportError as error: self.output_file_error(error) return @@ -193,7 +193,7 @@ class ScriptingOptionsPage(OptionsPage): if content: name = list_item.script.name.strip() title = name or _("Unnamed Script") - tagging_script = TaggingScript(title=title, script=content) + tagging_script = PicardTaggingScript(title=title, script=content) try: tagging_script.export_script(parent=self) except ScriptImportExportError as error: From 4fc43af380ebd826d9f9868bd5c5e8a81a0c8035 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:32:27 +0200 Subject: [PATCH 09/17] ScriptImportError -> PicardScriptFromFileError --- picard/config_upgrade.py | 4 ++-- picard/script/serializer.py | 12 ++++++------ test/test_script_serializer.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py index 0b34f0743..e6aaed13a 100644 --- a/picard/config_upgrade.py +++ b/picard/config_upgrade.py @@ -430,14 +430,14 @@ def upgrade_to_v2_7_0dev3(config): from picard.script import get_file_naming_script_presets from picard.script.serializer import ( FileNamingScript, - ScriptImportError, + PicardScriptFromFileError, ) scripts = {} for item in config.setting.raw_value('file_naming_scripts') or []: try: script_item = FileNamingScript().create_from_yaml(item, create_new_id=False) scripts[script_item['id']] = script_item.to_dict() - except ScriptImportError: + except PicardScriptFromFileError: log.error("Error converting file naming script") script_list = set(scripts.keys()) | set(map(lambda item: item['id'], get_file_naming_script_presets())) if config.setting['selected_file_naming_script_id'] not in script_list: diff --git a/picard/script/serializer.py b/picard/script/serializer.py index 435c71c1d..99e5c3a19 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -64,7 +64,7 @@ class ScriptImportExportError(Exception): self.error_msg = error_msg -class ScriptImportError(Exception): +class PicardScriptFromFileError(Exception): def __init__(self, *args): super().__init__(*args) @@ -261,7 +261,7 @@ class PicardScript(): if file_type == cls._file_types()['package']: try: return cls().create_from_yaml(file_content) - except ScriptImportError as error: + except PicardScriptFromFileError as error: raise ScriptImportExportError(format=FILE_ERROR_DECODE, filename=filename, error_msg=error) else: return cls( @@ -283,9 +283,9 @@ class PicardScript(): """ new_object = cls() if not isinstance(script_dict, Mapping): - raise ScriptImportError(N_("Argument is not a dictionary")) + raise PicardScriptFromFileError(N_("Argument is not a dictionary")) if 'title' not in script_dict or 'script' not in script_dict: - raise ScriptImportError(N_("Invalid script package")) + raise PicardScriptFromFileError(N_("Invalid script package")) new_object.update_from_dict(script_dict) if create_new_id or not new_object['id']: new_object._set_new_id() @@ -327,9 +327,9 @@ class PicardScript(): new_object = cls() yaml_dict = yaml.safe_load(yaml_string) if not isinstance(yaml_dict, dict): - raise ScriptImportError(N_("File content not a dictionary")) + raise PicardScriptFromFileError(N_("File content not a dictionary")) if 'title' not in yaml_dict or 'script' not in yaml_dict: - raise ScriptImportError(N_("Invalid script package")) + raise PicardScriptFromFileError(N_("Invalid script package")) new_object.update_from_dict(yaml_dict) if create_new_id or not new_object['id']: new_object._set_new_id() diff --git a/test/test_script_serializer.py b/test/test_script_serializer.py index 943c06bf3..422b26c9e 100644 --- a/test/test_script_serializer.py +++ b/test/test_script_serializer.py @@ -30,7 +30,7 @@ from test.picardtestcase import PicardTestCase from picard.script.serializer import ( FileNamingScript, PicardScript, - ScriptImportError, + PicardScriptFromFileError, ) @@ -125,7 +125,7 @@ class PicardScriptTest(PicardTestCase): def test_script_object_9(self): # Test that an exception is raised when creating or updating using an invalid YAML string - with self.assertRaises(ScriptImportError): + with self.assertRaises(PicardScriptFromFileError): PicardScript().create_from_yaml('Not a YAML string') PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') From e46428c3a455262d85bdce6744a89117d93d2ddf Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:34:42 +0200 Subject: [PATCH 10/17] ScriptImportExportError -> PicardScriptImportExportError --- picard/script/serializer.py | 10 +++++----- picard/ui/options/scripting.py | 10 +++++----- picard/ui/scripteditor.py | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/picard/script/serializer.py b/picard/script/serializer.py index 99e5c3a19..16ae20d27 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -57,7 +57,7 @@ class PicardScriptType(IntEnum): FILENAMING = 2 -class ScriptImportExportError(Exception): +class PicardScriptImportExportError(Exception): def __init__(self, *args, format=None, filename=None, error_msg=None): self.format = format self.filename = filename @@ -226,7 +226,7 @@ class PicardScript(): with open(filename, 'w', encoding='utf-8') as o_file: o_file.write(script_text) except OSError as error: - raise ScriptImportExportError(format=FILE_ERROR_EXPORT, filename=filename, error_msg=error.strerror) + raise PicardScriptImportExportError(format=FILE_ERROR_EXPORT, filename=filename, error_msg=error.strerror) dialog = QtWidgets.QMessageBox( QtWidgets.QMessageBox.Icon.Information, _("Export Script"), @@ -255,14 +255,14 @@ class PicardScript(): with open(filename, 'r', encoding='utf-8') as i_file: file_content = i_file.read() except OSError as error: - raise ScriptImportExportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=error.strerror) + raise PicardScriptImportExportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=error.strerror) if not file_content.strip(): - raise ScriptImportExportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=N_("The file was empty")) + raise PicardScriptImportExportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=N_("The file was empty")) if file_type == cls._file_types()['package']: try: return cls().create_from_yaml(file_content) except PicardScriptFromFileError as error: - raise ScriptImportExportError(format=FILE_ERROR_DECODE, filename=filename, error_msg=error) + raise PicardScriptImportExportError(format=FILE_ERROR_DECODE, filename=filename, error_msg=error) else: return cls( title=_("Imported from %s") % filename, diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index 83f84c89e..714f74bfb 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -47,8 +47,8 @@ from picard.script import ( save_tagging_scripts_to_config, ) from picard.script.serializer import ( + PicardScriptImportExportError, PicardTaggingScript, - ScriptImportExportError, ) from picard.ui import ( @@ -151,12 +151,12 @@ class ScriptingOptionsPage(OptionsPage): error_message = _(fmt) % params self.display_error(ScriptFileError(_(title), error_message)) - def output_file_error(self, error: ScriptImportExportError): + def output_file_error(self, error: PicardScriptImportExportError): """Log file error and display error message dialog. Args: fmt (str): Format for the error type being displayed - error (ScriptImportExportError): The error as a ScriptImportExportError instance + error (PicardScriptImportExportError): The error as a PicardScriptImportExportError instance """ params = { 'filename': error.filename, @@ -170,7 +170,7 @@ class ScriptingOptionsPage(OptionsPage): """ try: tagging_script = PicardTaggingScript().import_script(self) - except ScriptImportExportError as error: + except PicardScriptImportExportError as error: self.output_file_error(error) return if tagging_script: @@ -196,7 +196,7 @@ class ScriptingOptionsPage(OptionsPage): tagging_script = PicardTaggingScript(title=title, script=content) try: tagging_script.export_script(parent=self) - except ScriptImportExportError as error: + except PicardScriptImportExportError as error: self.output_file_error(error) def enable_tagger_scripts_toggled(self, on): diff --git a/picard/ui/scripteditor.py b/picard/ui/scripteditor.py index ae9fb43fe..cefa33375 100644 --- a/picard/ui/scripteditor.py +++ b/picard/ui/scripteditor.py @@ -61,7 +61,7 @@ from picard.script import ( ) from picard.script.serializer import ( FileNamingScript, - ScriptImportExportError, + PicardScriptImportExportError, ) from picard.util import ( get_base_title, @@ -1234,7 +1234,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """ try: script_item = FileNamingScript().import_script(self) - except ScriptImportExportError as error: + except PicardScriptImportExportError as error: self.output_file_error(error.format, error.filename, error.error_msg) return if script_item: @@ -1281,7 +1281,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): script_item.title = get_base_title(script_item.title) try: script_item.export_script(parent=self) - except ScriptImportExportError as error: + except PicardScriptImportExportError as error: self.output_file_error(error.format, error.filename, error.error_msg) def check_formats(self): From f1c5bb4e488d8a9b82be98f225519a9e5bf50da7 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:37:55 +0200 Subject: [PATCH 11/17] Introduce a base exception class PicardScriptError --- picard/script/serializer.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/picard/script/serializer.py b/picard/script/serializer.py index 16ae20d27..3c23eb049 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -57,16 +57,20 @@ class PicardScriptType(IntEnum): FILENAMING = 2 -class PicardScriptImportExportError(Exception): +class PicardScriptError(Exception): + """Base exception class for PicardScript errors""" + + +class PicardScriptImportExportError(PicardScriptError): def __init__(self, *args, format=None, filename=None, error_msg=None): + super().__init__(*args) self.format = format self.filename = filename self.error_msg = error_msg -class PicardScriptFromFileError(Exception): - def __init__(self, *args): - super().__init__(*args) +class PicardScriptFromFileError(PicardScriptError): + """Exception raised when converting a file to a PicardScript""" class MultilineLiteral(str): From e95665d7047eee8324660de11f41b34a7eccf891 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:46:54 +0200 Subject: [PATCH 12/17] Introduce PicardScriptImportError/PicardScriptExportError They are subclassing PicardScriptImportExportError --- picard/script/serializer.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/picard/script/serializer.py b/picard/script/serializer.py index 3c23eb049..dd1a6f675 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -69,6 +69,14 @@ class PicardScriptImportExportError(PicardScriptError): self.error_msg = error_msg +class PicardScriptImportError(PicardScriptImportExportError): + """Exception raised during script import""" + + +class PicardScriptExportError(PicardScriptImportExportError): + """Exception raised during script export""" + + class PicardScriptFromFileError(PicardScriptError): """Exception raised when converting a file to a PicardScript""" @@ -230,7 +238,7 @@ class PicardScript(): with open(filename, 'w', encoding='utf-8') as o_file: o_file.write(script_text) except OSError as error: - raise PicardScriptImportExportError(format=FILE_ERROR_EXPORT, filename=filename, error_msg=error.strerror) + raise PicardScriptExportError(format=FILE_ERROR_EXPORT, filename=filename, error_msg=error.strerror) dialog = QtWidgets.QMessageBox( QtWidgets.QMessageBox.Icon.Information, _("Export Script"), @@ -259,14 +267,14 @@ class PicardScript(): with open(filename, 'r', encoding='utf-8') as i_file: file_content = i_file.read() except OSError as error: - raise PicardScriptImportExportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=error.strerror) + raise PicardScriptImportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=error.strerror) if not file_content.strip(): - raise PicardScriptImportExportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=N_("The file was empty")) + raise PicardScriptImportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=N_("The file was empty")) if file_type == cls._file_types()['package']: try: return cls().create_from_yaml(file_content) except PicardScriptFromFileError as error: - raise PicardScriptImportExportError(format=FILE_ERROR_DECODE, filename=filename, error_msg=error) + raise PicardScriptImportError(format=FILE_ERROR_DECODE, filename=filename, error_msg=error) else: return cls( title=_("Imported from %s") % filename, From 929214b3f7e603977fba1064aae73ebb2665cf76 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Sun, 26 May 2024 18:49:34 +0200 Subject: [PATCH 13/17] FileNamingScript -> PicardFileNamingScript --- picard/config_upgrade.py | 6 +++--- picard/script/__init__.py | 10 +++++----- picard/script/serializer.py | 2 +- picard/ui/scripteditor.py | 20 ++++++++++---------- test/test_script_serializer.py | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py index e6aaed13a..8e212e90a 100644 --- a/picard/config_upgrade.py +++ b/picard/config_upgrade.py @@ -429,19 +429,19 @@ def upgrade_to_v2_7_0dev3(config): """ from picard.script import get_file_naming_script_presets from picard.script.serializer import ( - FileNamingScript, + PicardFileNamingScript, PicardScriptFromFileError, ) scripts = {} for item in config.setting.raw_value('file_naming_scripts') or []: try: - script_item = FileNamingScript().create_from_yaml(item, create_new_id=False) + script_item = PicardFileNamingScript().create_from_yaml(item, create_new_id=False) scripts[script_item['id']] = script_item.to_dict() except PicardScriptFromFileError: log.error("Error converting file naming script") script_list = set(scripts.keys()) | set(map(lambda item: item['id'], get_file_naming_script_presets())) if config.setting['selected_file_naming_script_id'] not in script_list: - script_item = FileNamingScript( + script_item = PicardFileNamingScript( script=config.setting.value('file_naming_format', TextOption), title=_("Primary file naming script"), readonly=False, diff --git a/picard/script/__init__.py b/picard/script/__init__.py index 10d34c31a..28f96f711 100644 --- a/picard/script/__init__.py +++ b/picard/script/__init__.py @@ -63,7 +63,7 @@ from picard.script.parser import ( # noqa: F401 # pylint: disable=unused-import ScriptUnknownFunction, ScriptVariable, ) -from picard.script.serializer import FileNamingScript +from picard.script.serializer import PicardFileNamingScript class TaggingScriptSetting: @@ -173,7 +173,7 @@ def get_file_naming_script_presets(): """Generator of preset example file naming script objects. Yields: - FileNamingScript: the next example FileNamingScript object + PicardFileNamingScript: the next example PicardFileNamingScript object """ AUTHOR = "MusicBrainz Picard Development Team" DESCRIPTION = _("This preset example file naming script does not require any special settings, tagging scripts or plugins.") @@ -185,7 +185,7 @@ def get_file_naming_script_presets(): 'title': _(title), } - yield FileNamingScript( + yield PicardFileNamingScript( id=DEFAULT_NAMING_PRESET_ID, title=preset_title(1, N_("Default file naming script")), script=DEFAULT_FILE_NAMING_FORMAT, @@ -197,7 +197,7 @@ def get_file_naming_script_presets(): script_language_version="1.0", ) - yield FileNamingScript( + yield PicardFileNamingScript( id="Preset 2", title=preset_title(2, N_("[album artist]/[album]/[track #]. [title]")), script="%albumartist%/\n" @@ -211,7 +211,7 @@ def get_file_naming_script_presets(): script_language_version="1.0", ) - yield FileNamingScript( + yield PicardFileNamingScript( id="Preset 3", title=preset_title(3, N_("[album artist]/[album]/[disc and track #] [artist] - [title]")), script="$if2(%albumartist%,%artist%)/\n" diff --git a/picard/script/serializer.py b/picard/script/serializer.py index dd1a6f675..817a28558 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -397,7 +397,7 @@ class PicardTaggingScript(PicardScript): super().__init__(script=script, title=title, id=id, last_updated=last_updated, script_language_version=script_language_version) -class FileNamingScript(PicardScript): +class PicardFileNamingScript(PicardScript): """Picard file naming script class """ TYPE = PicardScriptType.FILENAMING diff --git a/picard/ui/scripteditor.py b/picard/ui/scripteditor.py index cefa33375..671d27b3c 100644 --- a/picard/ui/scripteditor.py +++ b/picard/ui/scripteditor.py @@ -60,7 +60,7 @@ from picard.script import ( iter_tagging_scripts_from_tuples, ) from picard.script.serializer import ( - FileNamingScript, + PicardFileNamingScript, PicardScriptImportExportError, ) from picard.util import ( @@ -386,7 +386,7 @@ def populate_script_selection_combo_box(naming_scripts, selected_script_id, comb """Populate the specified script selection combo box and identify the selected script. Args: - naming_scripts (dict): Dictionary of available user-defined naming scripts as script dictionaries as produced by FileNamingScript().to_dict() + naming_scripts (dict): Dictionary of available user-defined naming scripts as script dictionaries as produced by PicardFileNamingScript().to_dict() selected_script_id (str): ID code for the currently selected script combo_box (QComboBox): Combo box object to populate @@ -936,7 +936,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """Insert a new item into the script selection combo box and update the script list in the settings. Args: - script_item (dict): File naming script to insert as produced by FileNamingScript().to_dict() + script_item (dict): File naming script to insert as produced by PicardFileNamingScript().to_dict() """ self.selected_script_id = script_item['id'] self.naming_scripts[self.selected_script_id] = script_item @@ -960,7 +960,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): def new_script(self, script): """Add a new script to the script selection combo box and script list. """ - script_item = FileNamingScript(script=script) + script_item = PicardFileNamingScript(script=script) script_item.title = self.new_script_name() self._insert_item(script_item.to_dict()) @@ -968,7 +968,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """Add a copy of the script as a new editable script to the script selection combo box. """ selected, script_item = self.get_selected_index_and_item() - new_item = FileNamingScript.create_from_dict(script_dict=script_item).copy() + new_item = PicardFileNamingScript.create_from_dict(script_dict=script_item).copy() base_title = "%s %s" % (get_base_title(script_item['title']), gettext_constants(DEFAULT_COPY_TEXT)) new_item.title = self.new_script_name(base_title) @@ -1009,7 +1009,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """Get the specified item from the script selection combo box. Returns: - dict: File naming script dictionary as produced by FileNamingScript().to_dict() + dict: File naming script dictionary as produced by PicardFileNamingScript().to_dict() """ return self.get_script_item(self.ui.preset_naming_scripts.currentIndex()) @@ -1058,7 +1058,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): Args: idx (int): Index of the item to update - script_item (dict): Updated file naming script information as produced by FileNamingScript().to_dict() + script_item (dict): Updated file naming script information as produced by PicardFileNamingScript().to_dict() """ self.ui.preset_naming_scripts.setItemData(idx, script_item) title = script_item['title'] @@ -1233,7 +1233,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): a naming script package. """ try: - script_item = FileNamingScript().import_script(self) + script_item = PicardFileNamingScript().import_script(self) except PicardScriptImportExportError as error: self.output_file_error(error.format, error.filename, error.error_msg) return @@ -1277,7 +1277,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): script or a naming script package. """ selected = self.get_selected_item() - script_item = FileNamingScript.create_from_dict(script_dict=selected, create_new_id=False) + script_item = PicardFileNamingScript.create_from_dict(script_dict=selected, create_new_id=False) script_item.title = get_base_title(script_item.title) try: script_item.export_script(parent=self) @@ -1402,7 +1402,7 @@ class ScriptDetailsEditor(PicardDialog): def set_last_updated(self): """Set the last updated value to the current timestamp. """ - self.ui.script_last_updated.setText(FileNamingScript.make_last_updated()) + self.ui.script_last_updated.setText(PicardFileNamingScript.make_last_updated()) self.ui.script_last_updated.setModified(True) def save_changes(self): diff --git a/test/test_script_serializer.py b/test/test_script_serializer.py index 422b26c9e..9f4366110 100644 --- a/test/test_script_serializer.py +++ b/test/test_script_serializer.py @@ -28,7 +28,7 @@ import yaml from test.picardtestcase import PicardTestCase from picard.script.serializer import ( - FileNamingScript, + PicardFileNamingScript, PicardScript, PicardScriptFromFileError, ) @@ -131,7 +131,7 @@ class PicardScriptTest(PicardTestCase): def test_naming_script_object_1(self): # Check initial loaded values. - test_script = FileNamingScript( + test_script = PicardFileNamingScript( title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', description='Script description', author='Script author', script_language_version='1.0' ) From d9e89bf5a96958f9dc335827372d4e1baf0c74e7 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 27 May 2024 12:03:04 +0200 Subject: [PATCH 14/17] PicardScript -> ScriptSerializer --- picard/config_upgrade.py | 4 +-- picard/script/serializer.py | 46 +++++++++++++++++----------------- picard/ui/options/scripting.py | 10 ++++---- picard/ui/scripteditor.py | 6 ++--- test/test_script_serializer.py | 28 ++++++++++----------- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py index 8e212e90a..ddada669a 100644 --- a/picard/config_upgrade.py +++ b/picard/config_upgrade.py @@ -430,14 +430,14 @@ def upgrade_to_v2_7_0dev3(config): from picard.script import get_file_naming_script_presets from picard.script.serializer import ( PicardFileNamingScript, - PicardScriptFromFileError, + ScriptSerializerFromFileError, ) scripts = {} for item in config.setting.raw_value('file_naming_scripts') or []: try: script_item = PicardFileNamingScript().create_from_yaml(item, create_new_id=False) scripts[script_item['id']] = script_item.to_dict() - except PicardScriptFromFileError: + except ScriptSerializerFromFileError: log.error("Error converting file naming script") script_list = set(scripts.keys()) | set(map(lambda item: item['id'], get_file_naming_script_presets())) if config.setting['selected_file_naming_script_id'] not in script_list: diff --git a/picard/script/serializer.py b/picard/script/serializer.py index 817a28558..f7b9391d4 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -49,7 +49,7 @@ from picard.util import make_filename_from_title @unique -class PicardScriptType(IntEnum): +class ScriptSerializerType(IntEnum): """Picard Script object types """ BASE = 0 @@ -57,11 +57,11 @@ class PicardScriptType(IntEnum): FILENAMING = 2 -class PicardScriptError(Exception): - """Base exception class for PicardScript errors""" +class ScriptSerializerError(Exception): + """Base exception class for ScriptSerializer errors""" -class PicardScriptImportExportError(PicardScriptError): +class ScriptSerializerImportExportError(ScriptSerializerError): def __init__(self, *args, format=None, filename=None, error_msg=None): super().__init__(*args) self.format = format @@ -69,16 +69,16 @@ class PicardScriptImportExportError(PicardScriptError): self.error_msg = error_msg -class PicardScriptImportError(PicardScriptImportExportError): +class ScriptSerializerImportError(ScriptSerializerImportExportError): """Exception raised during script import""" -class PicardScriptExportError(PicardScriptImportExportError): +class ScriptSerializerExportError(ScriptSerializerImportExportError): """Exception raised during script export""" -class PicardScriptFromFileError(PicardScriptError): - """Exception raised when converting a file to a PicardScript""" +class ScriptSerializerFromFileError(ScriptSerializerError): + """Exception raised when converting a file to a ScriptSerializer""" class MultilineLiteral(str): @@ -92,12 +92,12 @@ class MultilineLiteral(str): yaml.add_representer(MultilineLiteral, MultilineLiteral.yaml_presenter) -class PicardScript(): +class ScriptSerializer(): """Base class for Picard script objects. """ # Base class developed to support future tagging script class as possible replacement for currently used tuples in config.setting["list_of_scripts"]. - TYPE = PicardScriptType.BASE + TYPE = ScriptSerializerType.BASE OUTPUT_FIELDS = ('title', 'script_language_version', 'script', 'id') # Don't automatically trigger changing the `script_last_updated` property when updating these properties. @@ -238,7 +238,7 @@ class PicardScript(): with open(filename, 'w', encoding='utf-8') as o_file: o_file.write(script_text) except OSError as error: - raise PicardScriptExportError(format=FILE_ERROR_EXPORT, filename=filename, error_msg=error.strerror) + raise ScriptSerializerExportError(format=FILE_ERROR_EXPORT, filename=filename, error_msg=error.strerror) dialog = QtWidgets.QMessageBox( QtWidgets.QMessageBox.Icon.Information, _("Export Script"), @@ -267,14 +267,14 @@ class PicardScript(): with open(filename, 'r', encoding='utf-8') as i_file: file_content = i_file.read() except OSError as error: - raise PicardScriptImportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=error.strerror) + raise ScriptSerializerImportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=error.strerror) if not file_content.strip(): - raise PicardScriptImportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=N_("The file was empty")) + raise ScriptSerializerImportError(format=FILE_ERROR_IMPORT, filename=filename, error_msg=N_("The file was empty")) if file_type == cls._file_types()['package']: try: return cls().create_from_yaml(file_content) - except PicardScriptFromFileError as error: - raise PicardScriptImportError(format=FILE_ERROR_DECODE, filename=filename, error_msg=error) + except ScriptSerializerFromFileError as error: + raise ScriptSerializerImportError(format=FILE_ERROR_DECODE, filename=filename, error_msg=error) else: return cls( title=_("Imported from %s") % filename, @@ -295,9 +295,9 @@ class PicardScript(): """ new_object = cls() if not isinstance(script_dict, Mapping): - raise PicardScriptFromFileError(N_("Argument is not a dictionary")) + raise ScriptSerializerFromFileError(N_("Argument is not a dictionary")) if 'title' not in script_dict or 'script' not in script_dict: - raise PicardScriptFromFileError(N_("Invalid script package")) + raise ScriptSerializerFromFileError(N_("Invalid script package")) new_object.update_from_dict(script_dict) if create_new_id or not new_object['id']: new_object._set_new_id() @@ -339,9 +339,9 @@ class PicardScript(): new_object = cls() yaml_dict = yaml.safe_load(yaml_string) if not isinstance(yaml_dict, dict): - raise PicardScriptFromFileError(N_("File content not a dictionary")) + raise ScriptSerializerFromFileError(N_("File content not a dictionary")) if 'title' not in yaml_dict or 'script' not in yaml_dict: - raise PicardScriptFromFileError(N_("Invalid script package")) + raise ScriptSerializerFromFileError(N_("Invalid script package")) new_object.update_from_dict(yaml_dict) if create_new_id or not new_object['id']: new_object._set_new_id() @@ -379,10 +379,10 @@ class PicardScript(): )) -class PicardTaggingScript(PicardScript): +class PicardTaggingScript(ScriptSerializer): """Picard tagging script class """ - TYPE = PicardScriptType.TAGGER + TYPE = ScriptSerializerType.TAGGER OUTPUT_FIELDS = ('title', 'script_language_version', 'script', 'id') def __init__(self, script='', title='', id=None, last_updated=None, script_language_version=None): @@ -397,10 +397,10 @@ class PicardTaggingScript(PicardScript): super().__init__(script=script, title=title, id=id, last_updated=last_updated, script_language_version=script_language_version) -class PicardFileNamingScript(PicardScript): +class PicardFileNamingScript(ScriptSerializer): """Picard file naming script class """ - TYPE = PicardScriptType.FILENAMING + TYPE = ScriptSerializerType.FILENAMING OUTPUT_FIELDS = ('title', 'description', 'author', 'license', 'version', 'last_updated', 'script_language_version', 'script', 'id') def __init__( diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index 714f74bfb..497cdd001 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -47,8 +47,8 @@ from picard.script import ( save_tagging_scripts_to_config, ) from picard.script.serializer import ( - PicardScriptImportExportError, PicardTaggingScript, + ScriptSerializerImportExportError, ) from picard.ui import ( @@ -151,12 +151,12 @@ class ScriptingOptionsPage(OptionsPage): error_message = _(fmt) % params self.display_error(ScriptFileError(_(title), error_message)) - def output_file_error(self, error: PicardScriptImportExportError): + def output_file_error(self, error: ScriptSerializerImportExportError): """Log file error and display error message dialog. Args: fmt (str): Format for the error type being displayed - error (PicardScriptImportExportError): The error as a PicardScriptImportExportError instance + error (ScriptSerializerImportExportError): The error as a ScriptSerializerImportExportError instance """ params = { 'filename': error.filename, @@ -170,7 +170,7 @@ class ScriptingOptionsPage(OptionsPage): """ try: tagging_script = PicardTaggingScript().import_script(self) - except PicardScriptImportExportError as error: + except ScriptSerializerImportExportError as error: self.output_file_error(error) return if tagging_script: @@ -196,7 +196,7 @@ class ScriptingOptionsPage(OptionsPage): tagging_script = PicardTaggingScript(title=title, script=content) try: tagging_script.export_script(parent=self) - except PicardScriptImportExportError as error: + except ScriptSerializerImportExportError as error: self.output_file_error(error) def enable_tagger_scripts_toggled(self, on): diff --git a/picard/ui/scripteditor.py b/picard/ui/scripteditor.py index 671d27b3c..5aa89c2df 100644 --- a/picard/ui/scripteditor.py +++ b/picard/ui/scripteditor.py @@ -61,7 +61,7 @@ from picard.script import ( ) from picard.script.serializer import ( PicardFileNamingScript, - PicardScriptImportExportError, + ScriptSerializerImportExportError, ) from picard.util import ( get_base_title, @@ -1234,7 +1234,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """ try: script_item = PicardFileNamingScript().import_script(self) - except PicardScriptImportExportError as error: + except ScriptSerializerImportExportError as error: self.output_file_error(error.format, error.filename, error.error_msg) return if script_item: @@ -1281,7 +1281,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): script_item.title = get_base_title(script_item.title) try: script_item.export_script(parent=self) - except PicardScriptImportExportError as error: + except ScriptSerializerImportExportError as error: self.output_file_error(error.format, error.filename, error.error_msg) def check_formats(self): diff --git a/test/test_script_serializer.py b/test/test_script_serializer.py index 9f4366110..f23f59aa1 100644 --- a/test/test_script_serializer.py +++ b/test/test_script_serializer.py @@ -29,8 +29,8 @@ from test.picardtestcase import PicardTestCase from picard.script.serializer import ( PicardFileNamingScript, - PicardScript, - PicardScriptFromFileError, + ScriptSerializer, + ScriptSerializerFromFileError, ) @@ -43,14 +43,14 @@ class MockDateTime(datetime.datetime): raise Exception("Unexpected parameter tz=%r" % tz) -class PicardScriptTest(PicardTestCase): +class ScriptSerializerTest(PicardTestCase): def assertYamlEquals(self, yaml_str, obj, msg=None): self.assertEqual(obj, yaml.safe_load(yaml_str), msg) def test_script_object_1(self): # Check initial loaded values. - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') self.assertEqual(test_script.id, '12345') self.assertEqual(test_script['id'], '12345') self.assertEqual(test_script.last_updated, '2021-04-26') @@ -59,7 +59,7 @@ class PicardScriptTest(PicardTestCase): def test_script_object_2(self): # Check updating values directly so as not to modify `last_updated`. - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') test_script.id = '54321' self.assertEqual(test_script.id, '54321') self.assertEqual(test_script['id'], '54321') @@ -73,7 +73,7 @@ class PicardScriptTest(PicardTestCase): def test_script_object_3(self): # Check updating values that are ignored from modifying `last_updated`. - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') test_script.update_script_setting(id='54321') self.assertEqual(test_script.id, '54321') self.assertEqual(test_script['id'], '54321') @@ -83,7 +83,7 @@ class PicardScriptTest(PicardTestCase): @patch('datetime.datetime', MockDateTime) def test_script_object_4(self): # Check updating values that modify `last_updated`. - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') test_script.update_script_setting(title='Updated Script 1') self.assertEqual(test_script.title, 'Updated Script 1') self.assertEqual(test_script['title'], 'Updated Script 1') @@ -93,7 +93,7 @@ class PicardScriptTest(PicardTestCase): @patch('datetime.datetime', MockDateTime) def test_script_object_5(self): # Check updating values from dict that modify `last_updated`. - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') test_script.update_from_dict({"script": "Updated script"}) self.assertEqual(test_script.script, 'Updated script') self.assertEqual(test_script['script'], 'Updated script') @@ -102,7 +102,7 @@ class PicardScriptTest(PicardTestCase): def test_script_object_6(self): # Test that extra (unknown) settings are ignored during updating - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') test_script.update_script_setting(description='Updated description') self.assertEqual(test_script['last_updated'], '2021-04-26') self.assertYamlEquals(test_script.to_yaml(), {"id": "12345", "script": "Script text\n", "script_language_version": "1.0", "title": "Script 1"}) @@ -111,7 +111,7 @@ class PicardScriptTest(PicardTestCase): def test_script_object_7(self): # Test that extra (unknown) settings are ignored during updating from dict - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') test_script.update_from_dict({"description": "Updated description"}) self.assertEqual(test_script['last_updated'], '2021-04-26') self.assertYamlEquals(test_script.to_yaml(), {"id": "12345", "script": "Script text\n", "script_language_version": "1.0", "title": "Script 1"}) @@ -120,14 +120,14 @@ class PicardScriptTest(PicardTestCase): def test_script_object_8(self): # Test that requested unknown settings return None - test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') + test_script = ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26') self.assertEqual(test_script['unknown_setting'], None) def test_script_object_9(self): # Test that an exception is raised when creating or updating using an invalid YAML string - with self.assertRaises(PicardScriptFromFileError): - PicardScript().create_from_yaml('Not a YAML string') - PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') + with self.assertRaises(ScriptSerializerFromFileError): + ScriptSerializer().create_from_yaml('Not a YAML string') + ScriptSerializer(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0') def test_naming_script_object_1(self): # Check initial loaded values. From 10160b584872f1bad18ba42c7703b12e7ae6e461 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 27 May 2024 12:04:35 +0200 Subject: [PATCH 15/17] PicardTaggingScript -> TaggingScriptInfo --- picard/script/serializer.py | 2 +- picard/ui/options/scripting.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/picard/script/serializer.py b/picard/script/serializer.py index f7b9391d4..c3dd71722 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -379,7 +379,7 @@ class ScriptSerializer(): )) -class PicardTaggingScript(ScriptSerializer): +class TaggingScriptInfo(ScriptSerializer): """Picard tagging script class """ TYPE = ScriptSerializerType.TAGGER diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py index 497cdd001..d3508c0b1 100644 --- a/picard/ui/options/scripting.py +++ b/picard/ui/options/scripting.py @@ -47,8 +47,8 @@ from picard.script import ( save_tagging_scripts_to_config, ) from picard.script.serializer import ( - PicardTaggingScript, ScriptSerializerImportExportError, + TaggingScriptInfo, ) from picard.ui import ( @@ -169,7 +169,7 @@ class ScriptingOptionsPage(OptionsPage): a Picard script package. """ try: - tagging_script = PicardTaggingScript().import_script(self) + tagging_script = TaggingScriptInfo().import_script(self) except ScriptSerializerImportExportError as error: self.output_file_error(error) return @@ -193,7 +193,7 @@ class ScriptingOptionsPage(OptionsPage): if content: name = list_item.script.name.strip() title = name or _("Unnamed Script") - tagging_script = PicardTaggingScript(title=title, script=content) + tagging_script = TaggingScriptInfo(title=title, script=content) try: tagging_script.export_script(parent=self) except ScriptSerializerImportExportError as error: From 9548b752939a008a74ea34a2842d7da954bcb530 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 27 May 2024 12:06:17 +0200 Subject: [PATCH 16/17] PicardFileNamingScript -> FileNamingScriptInfo --- picard/config_upgrade.py | 6 +++--- picard/script/__init__.py | 10 +++++----- picard/script/serializer.py | 2 +- picard/ui/scripteditor.py | 20 ++++++++++---------- test/test_script_serializer.py | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py index ddada669a..ee0b7685c 100644 --- a/picard/config_upgrade.py +++ b/picard/config_upgrade.py @@ -429,19 +429,19 @@ def upgrade_to_v2_7_0dev3(config): """ from picard.script import get_file_naming_script_presets from picard.script.serializer import ( - PicardFileNamingScript, + FileNamingScriptInfo, ScriptSerializerFromFileError, ) scripts = {} for item in config.setting.raw_value('file_naming_scripts') or []: try: - script_item = PicardFileNamingScript().create_from_yaml(item, create_new_id=False) + script_item = FileNamingScriptInfo().create_from_yaml(item, create_new_id=False) scripts[script_item['id']] = script_item.to_dict() except ScriptSerializerFromFileError: log.error("Error converting file naming script") script_list = set(scripts.keys()) | set(map(lambda item: item['id'], get_file_naming_script_presets())) if config.setting['selected_file_naming_script_id'] not in script_list: - script_item = PicardFileNamingScript( + script_item = FileNamingScriptInfo( script=config.setting.value('file_naming_format', TextOption), title=_("Primary file naming script"), readonly=False, diff --git a/picard/script/__init__.py b/picard/script/__init__.py index 28f96f711..bb5782d43 100644 --- a/picard/script/__init__.py +++ b/picard/script/__init__.py @@ -63,7 +63,7 @@ from picard.script.parser import ( # noqa: F401 # pylint: disable=unused-import ScriptUnknownFunction, ScriptVariable, ) -from picard.script.serializer import PicardFileNamingScript +from picard.script.serializer import FileNamingScriptInfo class TaggingScriptSetting: @@ -173,7 +173,7 @@ def get_file_naming_script_presets(): """Generator of preset example file naming script objects. Yields: - PicardFileNamingScript: the next example PicardFileNamingScript object + FileNamingScriptInfo: the next example FileNamingScriptInfo object """ AUTHOR = "MusicBrainz Picard Development Team" DESCRIPTION = _("This preset example file naming script does not require any special settings, tagging scripts or plugins.") @@ -185,7 +185,7 @@ def get_file_naming_script_presets(): 'title': _(title), } - yield PicardFileNamingScript( + yield FileNamingScriptInfo( id=DEFAULT_NAMING_PRESET_ID, title=preset_title(1, N_("Default file naming script")), script=DEFAULT_FILE_NAMING_FORMAT, @@ -197,7 +197,7 @@ def get_file_naming_script_presets(): script_language_version="1.0", ) - yield PicardFileNamingScript( + yield FileNamingScriptInfo( id="Preset 2", title=preset_title(2, N_("[album artist]/[album]/[track #]. [title]")), script="%albumartist%/\n" @@ -211,7 +211,7 @@ def get_file_naming_script_presets(): script_language_version="1.0", ) - yield PicardFileNamingScript( + yield FileNamingScriptInfo( id="Preset 3", title=preset_title(3, N_("[album artist]/[album]/[disc and track #] [artist] - [title]")), script="$if2(%albumartist%,%artist%)/\n" diff --git a/picard/script/serializer.py b/picard/script/serializer.py index c3dd71722..cc5a53dd0 100644 --- a/picard/script/serializer.py +++ b/picard/script/serializer.py @@ -397,7 +397,7 @@ class TaggingScriptInfo(ScriptSerializer): super().__init__(script=script, title=title, id=id, last_updated=last_updated, script_language_version=script_language_version) -class PicardFileNamingScript(ScriptSerializer): +class FileNamingScriptInfo(ScriptSerializer): """Picard file naming script class """ TYPE = ScriptSerializerType.FILENAMING diff --git a/picard/ui/scripteditor.py b/picard/ui/scripteditor.py index 5aa89c2df..ade1697de 100644 --- a/picard/ui/scripteditor.py +++ b/picard/ui/scripteditor.py @@ -60,7 +60,7 @@ from picard.script import ( iter_tagging_scripts_from_tuples, ) from picard.script.serializer import ( - PicardFileNamingScript, + FileNamingScriptInfo, ScriptSerializerImportExportError, ) from picard.util import ( @@ -386,7 +386,7 @@ def populate_script_selection_combo_box(naming_scripts, selected_script_id, comb """Populate the specified script selection combo box and identify the selected script. Args: - naming_scripts (dict): Dictionary of available user-defined naming scripts as script dictionaries as produced by PicardFileNamingScript().to_dict() + naming_scripts (dict): Dictionary of available user-defined naming scripts as script dictionaries as produced by FileNamingScriptInfo().to_dict() selected_script_id (str): ID code for the currently selected script combo_box (QComboBox): Combo box object to populate @@ -936,7 +936,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """Insert a new item into the script selection combo box and update the script list in the settings. Args: - script_item (dict): File naming script to insert as produced by PicardFileNamingScript().to_dict() + script_item (dict): File naming script to insert as produced by FileNamingScriptInfo().to_dict() """ self.selected_script_id = script_item['id'] self.naming_scripts[self.selected_script_id] = script_item @@ -960,7 +960,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): def new_script(self, script): """Add a new script to the script selection combo box and script list. """ - script_item = PicardFileNamingScript(script=script) + script_item = FileNamingScriptInfo(script=script) script_item.title = self.new_script_name() self._insert_item(script_item.to_dict()) @@ -968,7 +968,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """Add a copy of the script as a new editable script to the script selection combo box. """ selected, script_item = self.get_selected_index_and_item() - new_item = PicardFileNamingScript.create_from_dict(script_dict=script_item).copy() + new_item = FileNamingScriptInfo.create_from_dict(script_dict=script_item).copy() base_title = "%s %s" % (get_base_title(script_item['title']), gettext_constants(DEFAULT_COPY_TEXT)) new_item.title = self.new_script_name(base_title) @@ -1009,7 +1009,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): """Get the specified item from the script selection combo box. Returns: - dict: File naming script dictionary as produced by PicardFileNamingScript().to_dict() + dict: File naming script dictionary as produced by FileNamingScriptInfo().to_dict() """ return self.get_script_item(self.ui.preset_naming_scripts.currentIndex()) @@ -1058,7 +1058,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): Args: idx (int): Index of the item to update - script_item (dict): Updated file naming script information as produced by PicardFileNamingScript().to_dict() + script_item (dict): Updated file naming script information as produced by FileNamingScriptInfo().to_dict() """ self.ui.preset_naming_scripts.setItemData(idx, script_item) title = script_item['title'] @@ -1233,7 +1233,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): a naming script package. """ try: - script_item = PicardFileNamingScript().import_script(self) + script_item = FileNamingScriptInfo().import_script(self) except ScriptSerializerImportExportError as error: self.output_file_error(error.format, error.filename, error.error_msg) return @@ -1277,7 +1277,7 @@ class ScriptEditorDialog(PicardDialog, SingletonDialog): script or a naming script package. """ selected = self.get_selected_item() - script_item = PicardFileNamingScript.create_from_dict(script_dict=selected, create_new_id=False) + script_item = FileNamingScriptInfo.create_from_dict(script_dict=selected, create_new_id=False) script_item.title = get_base_title(script_item.title) try: script_item.export_script(parent=self) @@ -1402,7 +1402,7 @@ class ScriptDetailsEditor(PicardDialog): def set_last_updated(self): """Set the last updated value to the current timestamp. """ - self.ui.script_last_updated.setText(PicardFileNamingScript.make_last_updated()) + self.ui.script_last_updated.setText(FileNamingScriptInfo.make_last_updated()) self.ui.script_last_updated.setModified(True) def save_changes(self): diff --git a/test/test_script_serializer.py b/test/test_script_serializer.py index f23f59aa1..40f74f733 100644 --- a/test/test_script_serializer.py +++ b/test/test_script_serializer.py @@ -28,7 +28,7 @@ import yaml from test.picardtestcase import PicardTestCase from picard.script.serializer import ( - PicardFileNamingScript, + FileNamingScriptInfo, ScriptSerializer, ScriptSerializerFromFileError, ) @@ -131,7 +131,7 @@ class ScriptSerializerTest(PicardTestCase): def test_naming_script_object_1(self): # Check initial loaded values. - test_script = PicardFileNamingScript( + test_script = FileNamingScriptInfo( title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', description='Script description', author='Script author', script_language_version='1.0' ) From b1f327252d6f71f30272427c28c084a26c101efc Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 27 May 2024 12:17:03 +0200 Subject: [PATCH 17/17] Move iter_active_tagging_scripts() generator near over iter_*() methods --- picard/script/__init__.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/picard/script/__init__.py b/picard/script/__init__.py index bb5782d43..594eb6445 100644 --- a/picard/script/__init__.py +++ b/picard/script/__init__.py @@ -91,6 +91,17 @@ def save_tagging_scripts_to_config(scripts, config=None): config.setting['list_of_scripts'] = [(s.pos, s.name, s.enabled, s.content) for s in scripts] +def iter_active_tagging_scripts(config=None): + """Returns an iterator over the enabled and not empty tagging scripts.""" + if config is None: + config = get_config() + if not config.setting['enable_tagger_scripts']: + return + for script in iter_tagging_scripts_from_config(config=config): + if script.enabled and script.content: + yield script + + class ScriptFunctionDocError(Exception): pass @@ -136,17 +147,6 @@ def script_function_documentation_all(fmt='markdown', pre='', return "\n".join(doc_elements) -def iter_active_tagging_scripts(config=None): - """Returns an iterator over the enabled and not empty tagging scripts.""" - if config is None: - config = get_config() - if not config.setting['enable_tagger_scripts']: - return - for script in iter_tagging_scripts_from_config(config=config): - if script.enabled and script.content: - yield script - - def get_file_naming_script(settings): """Retrieve the file naming script.