Skip to content

Commit 68550e0

Browse files
committed
PICARD-2213: Use YAML for script package export/import
1 parent ddef0f5 commit 68550e0

6 files changed

+57
-36
lines changed

picard/script/__init__.py

+50-33
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import json
4545
import uuid
4646

47+
import yaml
48+
4749
from picard.config import get_config
4850
from picard.const import (
4951
DEFAULT_FILE_NAMING_FORMAT,
@@ -131,6 +133,17 @@ def __init__(self, *args):
131133
super().__init__(*args)
132134

133135

136+
class ScriptLiteral(str):
137+
@staticmethod
138+
def yaml_presenter(dumper, data):
139+
if data:
140+
data = data.rstrip() + '\n'
141+
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
142+
143+
144+
yaml.add_representer(ScriptLiteral, ScriptLiteral.yaml_presenter)
145+
146+
134147
class PicardScript():
135148
"""Base class for Picard script objects.
136149
"""
@@ -188,6 +201,14 @@ def __getitem__(self, setting):
188201
return value
189202
return None
190203

204+
@property
205+
def script(self):
206+
return self._script
207+
208+
@script.setter
209+
def script(self, value):
210+
self._script = ScriptLiteral(value)
211+
191212
@staticmethod
192213
def make_last_updated():
193214
"""Provide consistently formatted last updated string.
@@ -242,17 +263,15 @@ def copy(self):
242263
new_object._set_new_id()
243264
return new_object
244265

245-
# TODO: Enable once PyYAML requirement resolved with Python 3.8
246-
#
247-
# def to_yaml(self):
248-
# """Converts the properties of the script object to a YAML formatted string. Note that only property
249-
# names listed in `OUTPUT_FIELDS` will be included in the output.
266+
def to_yaml(self):
267+
"""Converts the properties of the script object to a YAML formatted string. Note that only property
268+
names listed in `OUTPUT_FIELDS` will be included in the output.
250269
251-
# Returns:
252-
# str: The properties of the script object formatted as a YAML string.
253-
# """
254-
# items = {key: getattr(self, key) for key in dir(self) if key in self.OUTPUT_FIELDS}
255-
# return yaml.dump(items)
270+
Returns:
271+
str: The properties of the script object formatted as a YAML string.
272+
"""
273+
items = {key: getattr(self, key) for key in dir(self) if key in self.OUTPUT_FIELDS}
274+
return yaml.dump(items)
256275

257276
def to_json(self, indent=None):
258277
"""Converts the properties of the script object to a JSON formatted string. Note that only property
@@ -267,29 +286,27 @@ def to_json(self, indent=None):
267286
items = {key: getattr(self, key) for key in dir(self) if key in self.OUTPUT_FIELDS}
268287
return json.dumps(items, indent=indent, sort_keys=True)
269288

270-
# TODO: Enable once PyYAML requirement resolved with Python 3.8
271-
#
272-
# @classmethod
273-
# def create_from_yaml(cls, yaml_string, create_new_id=True):
274-
# """Creates an instance based on the contents of the YAML string provided.
275-
# Properties in the YAML string that are not found in the script object are ignored.
276-
277-
# Args:
278-
# yaml_string (str): YAML string containing the property settings.
279-
280-
# Returns:
281-
# object: An instance of the class, populated from the property settings in the YAML string.
282-
# """
283-
# new_object = cls()
284-
# yaml_dict = yaml.safe_load(yaml_string)
285-
# if not isinstance(yaml_dict, dict):
286-
# raise ScriptImportError(N_("File content not a dictionary"))
287-
# if 'title' not in yaml_dict or 'script' not in yaml_dict:
288-
# raise ScriptImportError(N_('Invalid script package'))
289-
# new_object._update_from_dict(yaml_dict)
290-
# if create_new_id or not new_object['id']:
291-
# new_object._set_new_id()
292-
# return new_object
289+
@classmethod
290+
def create_from_yaml(cls, yaml_string, create_new_id=True):
291+
"""Creates an instance based on the contents of the YAML string provided.
292+
Properties in the YAML string that are not found in the script object are ignored.
293+
294+
Args:
295+
yaml_string (str): YAML string containing the property settings.
296+
297+
Returns:
298+
object: An instance of the class, populated from the property settings in the YAML string.
299+
"""
300+
new_object = cls()
301+
yaml_dict = yaml.safe_load(yaml_string)
302+
if not isinstance(yaml_dict, dict):
303+
raise ScriptImportError(N_("File content not a dictionary"))
304+
if 'title' not in yaml_dict or 'script' not in yaml_dict:
305+
raise ScriptImportError(N_('Invalid script package'))
306+
new_object._update_from_dict(yaml_dict)
307+
if create_new_id or not new_object['id']:
308+
new_object._set_new_id()
309+
return new_object
293310

294311
@classmethod
295312
def create_from_json(cls, json_string, create_new_id=True):

picard/ui/scripteditor.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def __init__(self, parent=None, examples=None):
284284

285285
self.FILE_TYPE_ALL = _("All Files") + " (*)"
286286
self.FILE_TYPE_SCRIPT = _("Picard Script Files") + " (*.pts *.txt)"
287-
self.FILE_TYPE_PACKAGE = _("Picard Naming Script Package") + " (*.pnsp *.json)"
287+
self.FILE_TYPE_PACKAGE = _("Picard Naming Script Package") + " (*.pnsp *.yaml)"
288288

289289
self.SCRIPT_TITLE_SYSTEM = _("System: %s")
290290
self.SCRIPT_TITLE_USER = _("User: %s")
@@ -873,7 +873,7 @@ def import_script(self):
873873
return
874874
if file_type == self.FILE_TYPE_PACKAGE:
875875
try:
876-
script_item = FileNamingScript().create_from_json(file_content)
876+
script_item = FileNamingScript().create_from_yaml(file_content)
877877
except ScriptImportError as error:
878878
self.output_file_error(FILE_ERROR_DECODE, filename, error)
879879
return
@@ -907,7 +907,7 @@ def export_script(self):
907907
filename = name
908908
log.debug('Exporting naming script file: %s' % filename)
909909
if file_type == self.FILE_TYPE_PACKAGE:
910-
script_text = script_item.to_json(indent=4)
910+
script_text = script_item.to_yaml()
911911
try:
912912
with open(filename, 'w', encoding='utf8') as o_file:
913913
o_file.write(script_text)

requirements-macos-10.12.txt

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ mutagen==1.45.1
66
pyobjc-core==6.2.2
77
pyobjc-framework-Cocoa==6.2.2
88
PyQt5==5.13.1
9+
pyyaml==5.4.1

requirements-macos-10.14.txt

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ mutagen==1.45.1
66
pyobjc-core==6.2.2
77
pyobjc-framework-Cocoa==6.2.2
88
PyQt5==5.15.4
9+
pyyaml==5.4.1

requirements-win.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ markdown==3.3.4
55
mutagen==1.45.1
66
PyQt5==5.15.4
77
pywin32==300
8+
pyyaml==5.4.1

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ pyobjc-core~=6.2; sys_platform == 'darwin'
77
pyobjc-framework-Cocoa~=6.2; sys_platform == 'darwin'
88
PyQt5~=5.10
99
pywin32; sys_platform == 'win32'
10+
pyyaml>=5.1

0 commit comments

Comments
 (0)