Skip to content

Commit

Permalink
Merge the two classes MscoreFile and MscoreXmlTree into a new class M…
Browse files Browse the repository at this point in the history
…useScoreFile
  • Loading branch information
Josef-Friedrich committed Jan 2, 2024
1 parent 6b59138 commit f303cdd
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 231 deletions.
26 changes: 7 additions & 19 deletions mscxyz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
.. code ::
MscoreFile
MscoreXmlTree
MuseScoreFile
MuseScoreFile
MscoreLyricsInterface
MscoreMetaInterface
MscoreStyleInterface
Expand Down Expand Up @@ -37,9 +37,8 @@
from mscxyz.meta import Meta
from mscxyz.rename import rename_filename
from mscxyz.score_file_classes import (
MscoreFile,
MscoreStyleInterface,
MscoreXmlTree,
MuseScoreFile,
list_scores,
)
from mscxyz.settings import DefaultArguments
Expand All @@ -54,17 +53,10 @@

# Classes

# Level 1

MscoreFile
MuseScoreFile
"""see submodule ``score_file_classes.py``"""

# Level 2

MscoreXmlTree
"""see submodule ``score_file_classes.py``"""

# Level 3

MscoreLyricsInterface
"""see submodule ``lyrics.py``"""
Expand Down Expand Up @@ -216,13 +208,11 @@ def execute(args: typing.Sequence[str] | None = None):
print("\n" + color(file, "red"))

if args.general_backup:
from mscxyz.score_file_classes import MscoreFile

score = MscoreFile(file)
score = MuseScoreFile(file)
score.backup()

if args.subcommand == "clean":
score = MscoreXmlTree(file)
score = MuseScoreFile(file)
print(score.filename)
score.clean()
if args.clean_style:
Expand Down Expand Up @@ -269,9 +259,7 @@ def execute(args: typing.Sequence[str] | None = None):
score = rename_filename(file)

elif args.subcommand == "export":
from mscxyz.score_file_classes import MscoreFile

score = MscoreFile(file)
score = MuseScoreFile(file)
score.export(extension=args.export_extension)

report_errors(score.errors)
Expand Down
4 changes: 2 additions & 2 deletions mscxyz/lyrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

import lxml.etree as etree

from mscxyz.score_file_classes import MscoreXmlTree
from mscxyz.score_file_classes import MuseScoreFile


class MscoreLyricsInterface(MscoreXmlTree):
class MscoreLyricsInterface(MuseScoreFile):
def __init__(self, relpath: str):
super(MscoreLyricsInterface, self).__init__(relpath)
self.lyrics = self.normalize_lyrics()
Expand Down
14 changes: 7 additions & 7 deletions mscxyz/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import tmep
from lxml.etree import _Element

from mscxyz.score_file_classes import MscoreXmlTree
from mscxyz.score_file_classes import MuseScoreFile
from mscxyz.utils import color, get_args

if typing.TYPE_CHECKING:
Expand Down Expand Up @@ -286,7 +286,7 @@ def __setattr__(self, field, value):
self._set_text(field.title(), value)


class Combined(MscoreXmlTree):
class Combined(MuseScoreFile):
fields = (
"composer",
"lyricist",
Expand Down Expand Up @@ -398,9 +398,9 @@ class InterfaceReadOnly:
"readonly_relpath_backup",
]

xml_tree: MscoreXmlTree
xml_tree: MuseScoreFile

def __init__(self, tree: MscoreXmlTree):
def __init__(self, tree: MuseScoreFile):
self.xml_tree = tree

@property
Expand Down Expand Up @@ -433,9 +433,9 @@ def readonly_relpath_backup(self) -> str:


class Interface:
xml_tree: MscoreXmlTree
xml_tree: MuseScoreFile

def __init__(self, tree: MscoreXmlTree):
def __init__(self, tree: MuseScoreFile):
self.xml_tree = tree
self.read_only = InterfaceReadOnly(tree)
self.read_write = InterfaceReadWrite(tree.xml_root)
Expand Down Expand Up @@ -463,7 +463,7 @@ def __setattr__(self, field: str, value):
raise ReadOnlyFieldError(field)


class Meta(MscoreXmlTree):
class Meta(MuseScoreFile):
def __init__(self, relpath: str):
super(Meta, self).__init__(relpath)

Expand Down
178 changes: 78 additions & 100 deletions mscxyz/score_file_classes.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
"""A collection of classes intended to represent one MuseScore file.
The classes build on each other hierarchically. The class hierarchy:
.. code ::
MscoreFile
MscoreXmlTree
MscoreStyleInterface
MscoreLyricsInterface
MuseScoreFile
MscoreStyleInterface
MscoreLyricsInterface
"""

from __future__ import annotations
Expand Down Expand Up @@ -74,92 +71,6 @@ def list_zero_alphabet() -> List[str]:
return score_dirs


###############################################################################
# Class hierarchy level 1
###############################################################################


class MscoreFile:
"""This class holds basic file properties of the MuseScore score file.
:param relpath: The relative (or absolute) path of a MuseScore
file.
"""

errors: List[Exception]
"""A list to store errors."""

path: Path
"""The absolute path of the input file."""

loadpath: str
"""The path of the uncompressed MuseScore file in XML format file.
This path may be located in the temporary directory."""

relpath: str
"""The relative path of the score file, for example:
``files/by_version/2/simple.mscx``.
"""

abspath: str
"""The absolute path of the score file, for example:
``/home/jf/test/files/by_version/2/simple.mscx``."""

relpath_backup: str

dirname: str
"""The name of the containing directory of the MuseScore file, for
example: ``files/by_version/2``."""

basename: str
"""The basename of the score file, for example: ``simple``."""

zip_container: Optional[ZipContainer]

def __init__(self, relpath: str) -> None:
self.errors = []
self.relpath = relpath
self.path = Path(relpath).resolve()
self.abspath = os.path.abspath(relpath)
self.relpath_backup = relpath.replace(
"." + self.extension, "_bak." + self.extension
)
self.dirname = os.path.dirname(relpath)
self.basename = self.filename.replace(".mscx", "")

if self.extension == "mscz":
self.zip_container = ZipContainer(self.path)
self.loadpath = str(self.zip_container.mscx_file)
else:
self.loadpath = self.abspath

@property
def filename(self) -> str:
"""The filename of the MuseScore file, for example:
``simple.mscx``."""
return self.path.name

@property
def extension(self) -> str:
"""The extension (``mscx`` or ``mscz``) of the score file, for
example: ``mscx``."""
return self.filename.split(".")[-1].lower()

def backup(self) -> None:
"""Make a copy of the MuseScore file."""
shutil.copy2(self.relpath, self.relpath_backup)

def export(self, extension: str = "pdf") -> None:
"""Export the score to the specifed file type.
:param extension: The extension (default: pdf)
"""
score: str = self.relpath
mscore(
["--export-to", score.replace("." + self.extension, "." + extension), score]
)


class ZipContainer:
"""Container for the file paths of the different files in an unzipped MuseScore file
Expand Down Expand Up @@ -236,17 +147,41 @@ def save(self, dest: str | Path) -> None:
zip.close()


###############################################################################
# Class hierarchy level 2
###############################################################################
class MuseScoreFile:
"""This class holds basic file properties of the MuseScore score file.
:param relpath: The relative (or absolute) path of a MuseScore
file.
"""

errors: List[Exception]
"""A list to store errors."""

path: Path
"""The absolute path of the input file."""

class MscoreXmlTree(MscoreFile):
"""XML tree manipulation
loadpath: str
"""The path of the uncompressed MuseScore file in XML format file.
This path may be located in the temporary directory."""

:param relpath: The relative (or absolute) path of a MuseScore file.
relpath: str
"""The relative path of the score file, for example:
``files/by_version/2/simple.mscx``.
"""

abspath: str
"""The absolute path of the score file, for example:
``/home/jf/test/files/by_version/2/simple.mscx``."""

relpath_backup: str

dirname: str
"""The name of the containing directory of the MuseScore file, for
example: ``files/by_version/2``."""

basename: str
"""The basename of the score file, for example: ``simple``."""

xml_tree: _ElementTree

version_major: int
Expand All @@ -255,8 +190,25 @@ class MscoreXmlTree(MscoreFile):
version: float
"""The MuseScore version, for example 2.03 or 3.01"""

zip_container: Optional[ZipContainer]

def __init__(self, relpath: str) -> None:
super(MscoreXmlTree, self).__init__(relpath)
self.errors = []
self.relpath = relpath
self.path = Path(relpath).resolve()
self.abspath = os.path.abspath(relpath)
self.relpath_backup = relpath.replace(
"." + self.extension, "_bak." + self.extension
)
self.dirname = os.path.dirname(relpath)
self.basename = self.filename.replace(".mscx", "")

if self.extension == "mscz":
self.zip_container = ZipContainer(self.path)
self.loadpath = str(self.zip_container.mscx_file)
else:
self.loadpath = self.abspath

try:
self.xml_tree = lxml.etree.parse(self.loadpath)
except lxml.etree.XMLSyntaxError as e:
Expand All @@ -266,6 +218,32 @@ def __init__(self, relpath: str) -> None:
self.version = self.get_version()
self.version_major = int(self.version)

@property
def filename(self) -> str:
"""The filename of the MuseScore file, for example:
``simple.mscx``."""
return self.path.name

@property
def extension(self) -> str:
"""The extension (``mscx`` or ``mscz``) of the score file, for
example: ``mscx``."""
return self.filename.split(".")[-1].lower()

def backup(self) -> None:
"""Make a copy of the MuseScore file."""
shutil.copy2(self.relpath, self.relpath_backup)

def export(self, extension: str = "pdf") -> None:
"""Export the score to the specifed file type.
:param extension: The extension (default: pdf)
"""
score: str = self.relpath
mscore(
["--export-to", score.replace("." + self.extension, "." + extension), score]
)

def get_version(self) -> float:
"""
Get the version number of the MuseScore file.
Expand Down Expand Up @@ -434,7 +412,7 @@ def save(self, new_name: str = "", mscore: bool = False):
###############################################################################


class MscoreStyleInterface(MscoreXmlTree):
class MscoreStyleInterface(MuseScoreFile):
"""
Interface specialized for the style manipulation.
Expand Down
6 changes: 3 additions & 3 deletions tests/helper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""MscoreFile for various tests"""
"""MuseScoreFile for various tests"""

from __future__ import annotations

Expand All @@ -10,7 +10,7 @@

from lxml.etree import _ElementTree

from mscxyz import MscoreXmlTree
from mscxyz import MuseScoreFile

# if typing.TYPE_CHECKING:

Expand Down Expand Up @@ -66,7 +66,7 @@ def get_xml_tree(filename: str, version: int = 2) -> _ElementTree:
:param version: The version of the file (default is 2).
:return: The XML tree.
"""
return MscoreXmlTree(get_file(filename, version)).xml_tree
return MuseScoreFile(get_file(filename, version)).xml_tree


def read_file(filename: str) -> str:
Expand Down
Loading

0 comments on commit f303cdd

Please sign in to comment.