Switch back to using JSON for import / export scripts

This commit is contained in:
Bob Swift
2021-05-07 20:54:28 -06:00
parent ffadc6ea55
commit 33a2dc9a31
7 changed files with 48 additions and 46 deletions

View File

@@ -44,8 +44,6 @@ from enum import (
import json
import uuid
import yaml
from picard.config import get_config
from picard.const import (
DEFAULT_FILE_NAMING_FORMAT,
@@ -128,7 +126,7 @@ class PicardScriptType(IntEnum):
FILENAMING = 2
class ScriptYamlImportError(Exception):
class ScriptImportError(Exception):
def __init__(self, *args):
super().__init__(*args)
@@ -244,15 +242,17 @@ class PicardScript():
new_object._set_new_id()
return new_object
def to_yaml(self):
"""Converts the properties of the script object to a YAML formatted string. Note that only property
names listed in `OUTPUT_FIELDS` will be included in the output.
# TODO: Enable once PyYAML requirement resolved with Python 3.8
#
# def to_yaml(self):
# """Converts the properties of the script object to a YAML formatted string. Note that only property
# names listed in `OUTPUT_FIELDS` will be included in the output.
Returns:
str: The properties of the script object formatted as a YAML string.
"""
items = {key: getattr(self, key) for key in dir(self) if key in self.OUTPUT_FIELDS}
return yaml.dump(items)
# Returns:
# str: The properties of the script object formatted as a YAML string.
# """
# items = {key: getattr(self, key) for key in dir(self) if key in self.OUTPUT_FIELDS}
# return yaml.dump(items)
def to_json(self, indent=None):
"""Converts the properties of the script object to a JSON formatted string. Note that only property
@@ -267,25 +267,27 @@ class PicardScript():
items = {key: getattr(self, key) for key in dir(self) if key in self.OUTPUT_FIELDS}
return json.dumps(items, indent=indent, sort_keys=True)
@classmethod
def create_from_yaml(cls, yaml_string):
"""Creates an instance based on the contents of the YAML string provided.
Properties in the YAML string that are not found in the script object are ignored.
# TODO: Enable once PyYAML requirement resolved with Python 3.8
#
# @classmethod
# def create_from_yaml(cls, yaml_string):
# """Creates an instance based on the contents of the YAML string provided.
# Properties in the YAML string that are not found in the script object are ignored.
Args:
yaml_string (str): YAML string containing the property settings.
# Args:
# yaml_string (str): YAML string containing the property settings.
Returns:
object: An instance of the class, populated from the property settings in the YAML string.
"""
new_object = cls()
yaml_dict = yaml.safe_load(yaml_string)
if not isinstance(yaml_dict, dict):
raise ScriptYamlImportError(N_("File content not a dictionary"))
if 'title' not in yaml_dict or 'script' not in yaml_dict:
raise ScriptYamlImportError(N_('Invalid script package'))
new_object._update_from_dict(yaml_dict)
return new_object
# Returns:
# object: An instance of the class, populated from the property settings in the YAML string.
# """
# new_object = cls()
# yaml_dict = yaml.safe_load(yaml_string)
# if not isinstance(yaml_dict, dict):
# raise ScriptImportError(N_("File content not a dictionary"))
# if 'title' not in yaml_dict or 'script' not in yaml_dict:
# raise ScriptImportError(N_('Invalid script package'))
# new_object._update_from_dict(yaml_dict)
# return new_object
@classmethod
def create_from_json(cls, json_string):
@@ -299,7 +301,10 @@ class PicardScript():
object: An instance of the class, populated from the property settings in the JSON string.
"""
new_object = cls()
new_object.title = ''
new_object.update_from_json(json_string)
if not (new_object['title'] and new_object['script']):
raise ScriptImportError(N_('Invalid script package'))
return new_object
def update_from_json(self, json_string):
@@ -309,7 +314,11 @@ class PicardScript():
Args:
json_string (str): JSON string containing the property settings.
"""
self._update_from_dict(json.loads(json_string))
try:
decoded_string = json.loads(json_string)
except json.decoder.JSONDecodeError:
raise ScriptImportError(N_("Unable to decode JSON string"))
self._update_from_dict(decoded_string)
class FileNamingScript(PicardScript):

View File

@@ -41,8 +41,8 @@ from picard.file import File
from picard.script import (
FileNamingScript,
ScriptError,
ScriptImportError,
ScriptParser,
ScriptYamlImportError,
get_file_naming_script_presets,
)
from picard.util.settingsoverride import SettingsOverride
@@ -58,11 +58,7 @@ from picard.ui.ui_scripteditor_details import Ui_ScriptDetails
from picard.ui.widgets.scriptdocumentation import ScriptingDocumentationWidget
class ScriptImportError(OptionsCheckError):
pass
class ScriptExportError(OptionsCheckError):
class ScriptFileError(OptionsCheckError):
pass
@@ -271,7 +267,7 @@ class ScriptEditorPage(PicardDialog):
self.FILE_TYPE_ALL = _("All Files") + " (*)"
self.FILE_TYPE_SCRIPT = _("Picard Script Files") + " (*.pts *.txt)"
self.FILE_TYPE_PACKAGE = _("Picard Naming Script Package") + " (*.pnsp *.yaml)"
self.FILE_TYPE_PACKAGE = _("Picard Naming Script Package") + " (*.pnsp *.json)"
self.SCRIPT_TITLE_SYSTEM = _("System: %s")
self.SCRIPT_TITLE_USER = _("User: %s")
@@ -619,7 +615,7 @@ class ScriptEditorPage(PicardDialog):
"""
log.error(fmt, filename, msg)
error_message = _(fmt) % (filename, _(msg))
self.display_error(ScriptImportError(_(title), error_message))
self.display_error(ScriptFileError(_(title), error_message))
def output_file_error(self, fmt, filename, msg):
"""Log file error and display error message dialog.
@@ -656,8 +652,8 @@ class ScriptEditorPage(PicardDialog):
return
if file_type == self.FILE_TYPE_PACKAGE:
try:
script_item = FileNamingScript().create_from_yaml(file_content)
except ScriptYamlImportError as error:
script_item = FileNamingScript().create_from_json(file_content)
except ScriptImportError as error:
self.output_file_error(FILE_ERROR_DECODE, filename, error)
return
else:
@@ -690,7 +686,7 @@ class ScriptEditorPage(PicardDialog):
filename = name
log.debug('Exporting naming script file: %s' % filename)
if file_type == self.FILE_TYPE_PACKAGE:
script_text = script_item.to_yaml()
script_text = script_item.to_json(indent=4)
try:
with open(filename, 'w', encoding='utf8') as o_file:
o_file.write(script_text)

View File

@@ -6,4 +6,3 @@ mutagen==1.45.1
pyobjc-core==6.2.2
pyobjc-framework-Cocoa==6.2.2
PyQt5==5.13.1
PyYAML==5.4.1

View File

@@ -6,4 +6,3 @@ mutagen==1.45.1
pyobjc-core==6.2.2
pyobjc-framework-Cocoa==6.2.2
PyQt5==5.15.4
PyYAML==5.4.1

View File

@@ -5,4 +5,3 @@ markdown==3.3.4
mutagen==1.45.1
PyQt5==5.15.4
pywin32==300
PyYAML==5.4.1

View File

@@ -7,4 +7,3 @@ pyobjc-core<7.0; sys_platform == 'darwin'
pyobjc-framework-Cocoa<7.0; sys_platform == 'darwin'
PyQt5>=5.10
pywin32; sys_platform == 'win32'
PyYAML==5.4.1

View File

@@ -27,6 +27,7 @@ from test.picardtestcase import PicardTestCase
from picard.script import (
FileNamingScript,
PicardScript,
ScriptImportError,
)
@@ -125,10 +126,10 @@ class ScriptClassesTest(PicardTestCase):
def test_script_object_9(self):
# Test that an exception is raised when creating or updating using an invalid JSON string
with self.assertRaises(JSONDecodeError):
with self.assertRaises(ScriptImportError):
test_script = PicardScript().create_from_json('Not a JSON string')
test_script = PicardScript(title='Script 1', script='Script text', id='12345', last_updated='2021-04-26', script_language_version='1.0')
with self.assertRaises(JSONDecodeError):
with self.assertRaises(ScriptImportError):
test_script.update_from_json('Not a JSON string')
def test_naming_script_object_1(self):