Skip to content

Commit

Permalink
Merge branch 'master' into experimental-meisolesmes
Browse files Browse the repository at this point in the history
Conflicts:
	python/pymei/Modules/layout.py
	python/pymei/Modules/shared.py
  • Loading branch information
alastair committed Mar 26, 2012
2 parents f9986e2 + c43993a commit 3144ca8
Show file tree
Hide file tree
Showing 19 changed files with 415 additions and 33 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Expand Up @@ -19,4 +19,8 @@ build/
/tools/mei-customization.xml /tools/mei-customization.xml
/tools/mei-source.xml /tools/mei-source.xml


/tools/mei-all.xml /tools/mei-all.xml
python/build
*.so
python/dist
pymei.egg-info
2 changes: 1 addition & 1 deletion python/pymei/Modules/layout.py
Expand Up @@ -15,7 +15,7 @@
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANDpython/pymei/Modules/layout.py
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Expand Down
11 changes: 10 additions & 1 deletion python/pymei/__init__.py
Expand Up @@ -19,4 +19,13 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


from _libmei import * from _libmei import *
import types

def read(filename):
""" Extra wrapper to make sure we can handle unicode filenames. """
if isinstance(filename, types.UnicodeType):
filename = str(filename)
doc = XmlImport.documentFromFile(filename)
return doc
XmlImport.read = staticmethod(read)
52 changes: 50 additions & 2 deletions python/src/_libmei.cpp
Expand Up @@ -39,6 +39,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <exception> #include <exception>
#include <sstream>


using namespace boost::python; using namespace boost::python;
using namespace std; using namespace std;
Expand All @@ -56,27 +57,59 @@ typedef vector<MeiNamespace*> MeiNamespaceList;


bool MeiElement_EqualWrap(const MeiElement* x, const MeiElement* y) { return x == y; } bool MeiElement_EqualWrap(const MeiElement* x, const MeiElement* y) { return x == y; }
bool MeiElement_NEqualWrap(const MeiElement* x, const MeiElement* y) { return x != y; } bool MeiElement_NEqualWrap(const MeiElement* x, const MeiElement* y) { return x != y; }
string MeiElement_Print(MeiElement* x) { return "<MeiElement " + x->getName() + ":" + x->getId() + ">"; }


bool MeiDocument_EqualWrap(const MeiDocument* x, const MeiDocument* y) { return x == y; } bool MeiDocument_EqualWrap(const MeiDocument* x, const MeiDocument* y) { return x == y; }
bool MeiDocument_NEqualWrap(const MeiDocument* x, const MeiDocument* y) { return x != y; } bool MeiDocument_NEqualWrap(const MeiDocument* x, const MeiDocument* y) { return x != y; }
string MeiDocument_Print(MeiDocument *x) { return "<MeiDocument " + x->getVersion() + ">"; }


bool MeiAttribute_EqualWrap(const MeiAttribute* x, const MeiAttribute* y) { return x == y; } bool MeiAttribute_EqualWrap(const MeiAttribute* x, const MeiAttribute* y) { return x == y; }
bool MeiAttribute_NEqualWrap(const MeiAttribute* x, const MeiAttribute* y) { return x != y; } bool MeiAttribute_NEqualWrap(const MeiAttribute* x, const MeiAttribute* y) { return x != y; }
string MeiAttribute_Print(MeiAttribute* x) { return "<MeiAttribute " + x->getName() + ":" + x->getValue() + ">"; }


bool MeiNamespace_EqualWrap(const MeiNamespace* x, const MeiNamespace* y) { return x == y; } bool MeiNamespace_EqualWrap(const MeiNamespace* x, const MeiNamespace* y) { return x == y; }
bool MeiNamespace_NEqualWrap(const MeiNamespace* x, const MeiNamespace* y) { return x != y; } bool MeiNamespace_NEqualWrap(const MeiNamespace* x, const MeiNamespace* y) { return x != y; }
string MeiNamespace_Print(MeiNamespace* x) { return "<MeiNamespace " + x->getPrefix() + ":" + x->getHref() + ">"; }


bool MeiElementList_EqualWrap(const MeiElementList x, const MeiElementList y) { return x == y; } bool MeiElementList_EqualWrap(const MeiElementList x, const MeiElementList y) { return x == y; }
bool MeiElementList_NEqualWrap(const MeiElementList x, const MeiElementList y) { return x != y; } bool MeiElementList_NEqualWrap(const MeiElementList x, const MeiElementList y) { return x != y; }
bool MeiElementList_NonZero(const MeiElementList x) { return !x.empty(); } bool MeiElementList_NonZero(const MeiElementList x) { return !x.empty(); }
string MeiElementList_Print(MeiElementList x) {
stringstream res;
res << "[ ";
for(vector<MeiElement*>::iterator iter = x.begin(); iter != x.end(); ++iter) {
res << "<MeiElement " << (*iter)->getName() << ":" << (*iter)->getId() << "> ";
}
res << "]";
return res.str();
}


bool MeiAttributeList_EqualWrap(const MeiAttributeList x, const MeiAttributeList y) { return x == y; } bool MeiAttributeList_EqualWrap(const MeiAttributeList x, const MeiAttributeList y) { return x == y; }
bool MeiAttributeList_NEqualWrap(const MeiAttributeList x, const MeiAttributeList y) { return x != y; } bool MeiAttributeList_NEqualWrap(const MeiAttributeList x, const MeiAttributeList y) { return x != y; }
bool MeiAttributeList_NonZero(const MeiAttributeList x) { return !x.empty(); } bool MeiAttributeList_NonZero(const MeiAttributeList x) { return !x.empty(); }
string MeiAttributeList_Print(MeiAttributeList x) {
stringstream res;
res << "[ ";
for(vector<MeiAttribute*>::iterator iter = x.begin(); iter != x.end(); ++iter) {
res << "<MeiAttribute " << (*iter)->getName() << ":" << (*iter)->getValue() << "> ";
}
res << "]";
return res.str();
}


bool MeiNamespaceList_EqualWrap(const MeiNamespaceList x, const MeiNamespaceList y) { return x == y; } bool MeiNamespaceList_EqualWrap(const MeiNamespaceList x, const MeiNamespaceList y) { return x == y; }
bool MeiNamespaceList_NEqualWrap(const MeiNamespaceList x, const MeiNamespaceList y) { return x != y; } bool MeiNamespaceList_NEqualWrap(const MeiNamespaceList x, const MeiNamespaceList y) { return x != y; }
bool MeiNamespaceList_NonZero(const MeiNamespaceList x) { return !x.empty(); } bool MeiNamespaceList_NonZero(const MeiNamespaceList x) { return !x.empty(); }
string MeiNamespaceList_Print(MeiNamespaceList x) {
stringstream res;
res << "[ ";
for(vector<MeiNamespace*>::iterator iter = x.begin(); iter != x.end(); ++iter) {
res << "<MeiNamespace " << (*iter)->getPrefix() << ":" << (*iter)->getHref() << "> ";
}
res << "]";
return res.str();
}



BOOST_PYTHON_MODULE(_libmei) { BOOST_PYTHON_MODULE(_libmei) {
docstring_options local_docstring_options(true, true, false); docstring_options local_docstring_options(true, true, false);
Expand All @@ -87,6 +120,8 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("__ne__", &MeiElementList_NEqualWrap) .def("__ne__", &MeiElementList_NEqualWrap)
.def("__iter__", boost::python::iterator<MeiElementList>()) .def("__iter__", boost::python::iterator<MeiElementList>())
.def("__nonzero__", &MeiElementList_NonZero) .def("__nonzero__", &MeiElementList_NonZero)
.def("__str__", &MeiElementList_Print)
.def("__repr__", &MeiElementList_Print)
; ;


class_<MeiAttributeList>("MeiAttributeList") class_<MeiAttributeList>("MeiAttributeList")
Expand All @@ -95,6 +130,8 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("__ne__", &MeiAttributeList_NEqualWrap) .def("__ne__", &MeiAttributeList_NEqualWrap)
.def("__iter__", boost::python::iterator<MeiAttributeList>()) .def("__iter__", boost::python::iterator<MeiAttributeList>())
.def("__nonzero__", &MeiAttributeList_NonZero) .def("__nonzero__", &MeiAttributeList_NonZero)
.def("__str__", &MeiAttributeList_Print)
.def("__repr__", &MeiAttributeList_Print)
; ;


class_<MeiNamespaceList>("MeiNamespaceList") class_<MeiNamespaceList>("MeiNamespaceList")
Expand All @@ -103,11 +140,15 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("__ne__", &MeiNamespaceList_NEqualWrap) .def("__ne__", &MeiNamespaceList_NEqualWrap)
.def("__iter__", boost::python::iterator<MeiNamespaceList>()) .def("__iter__", boost::python::iterator<MeiNamespaceList>())
.def("__nonzero__", &MeiNamespaceList_NonZero) .def("__nonzero__", &MeiNamespaceList_NonZero)
.def("__str__", &MeiNamespaceList_Print)
.def("__repr__", &MeiNamespaceList_Print)
; ;


class_<MeiNamespace, MeiNamespace*>("MeiNamespace", init<string, string>()) class_<MeiNamespace, MeiNamespace*>("MeiNamespace", init<string, string>())
.def("__eq__", &MeiNamespace_EqualWrap) .def("__eq__", &MeiNamespace_EqualWrap)
.def("__ne__", &MeiNamespace_NEqualWrap) .def("__ne__", &MeiNamespace_NEqualWrap)
.def("__str__", &MeiNamespace_Print)
.def("__repr__", &MeiNamespace_Print)
.def("getHref", &MeiNamespace::getHref) .def("getHref", &MeiNamespace::getHref)
.add_property("href", &MeiNamespace::getHref) .add_property("href", &MeiNamespace::getHref)
.def("getPrefix", &MeiNamespace::getPrefix) .def("getPrefix", &MeiNamespace::getPrefix)
Expand Down Expand Up @@ -145,9 +186,13 @@ BOOST_PYTHON_MODULE(_libmei) {
class_<MeiDocument, MeiDocument*>("MeiDocument", init<optional<string> >()) class_<MeiDocument, MeiDocument*>("MeiDocument", init<optional<string> >())
.def("__eq__", &MeiDocument_EqualWrap) .def("__eq__", &MeiDocument_EqualWrap)
.def("__ne__", &MeiDocument_NEqualWrap) .def("__ne__", &MeiDocument_NEqualWrap)
.def("__str__", &MeiDocument_Print)
.def("__repr__", &MeiDocument_Print)
.def("hasNamespace", &MeiDocument::hasNamespace) .def("hasNamespace", &MeiDocument::hasNamespace)
.def("getNamespace", &MeiDocument::getNamespace, return_value_policy<reference_existing_object>()) .def("getNamespace", &MeiDocument::getNamespace, return_value_policy<reference_existing_object>())
.def("getNamespaces", &MeiDocument::getNamespaces) .def("getNamespaces", &MeiDocument::getNamespaces)
.add_property("namespaces", &MeiDocument::getNamespaces)

.def("addNamespace", &MeiDocument::addNamespace) .def("addNamespace", &MeiDocument::addNamespace)
.def("getVersion", &MeiDocument::getVersion) .def("getVersion", &MeiDocument::getVersion)
.add_property("version", &MeiDocument::getVersion) .add_property("version", &MeiDocument::getVersion)
Expand All @@ -174,6 +219,9 @@ BOOST_PYTHON_MODULE(_libmei) {
// .def(init<const MeiElement&>()) // .def(init<const MeiElement&>())
.def("__eq__", &MeiElement_EqualWrap) .def("__eq__", &MeiElement_EqualWrap)
.def("__ne__", &MeiElement_NEqualWrap) .def("__ne__", &MeiElement_NEqualWrap)
.def("__str__", &MeiElement_Print)
.def("__repr__", &MeiElement_Print)

.def("getId", &MeiElement::getId) .def("getId", &MeiElement::getId)
.def("setId", &MeiElement::setId) .def("setId", &MeiElement::setId)
.add_property("id", &MeiElement::getId, &MeiElement::setId) .add_property("id", &MeiElement::getId, &MeiElement::setId)
Expand Down Expand Up @@ -243,15 +291,15 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("getPositionInDocument", &MeiElement::getPositionInDocument) .def("getPositionInDocument", &MeiElement::getPositionInDocument)
.def("lookBack", &MeiElement::lookBack, return_value_policy<reference_existing_object>()) .def("lookBack", &MeiElement::lookBack, return_value_policy<reference_existing_object>())
.def("flatten", &MeiElement::flatten) .def("flatten", &MeiElement::flatten)
.def("print", printAll)
.def("print", printLvl)
.def("updateDocument", &MeiElement::updateDocument) .def("updateDocument", &MeiElement::updateDocument)
; ;


class_<MeiAttribute, MeiAttribute*>("MeiAttribute", init<string, string>()) class_<MeiAttribute, MeiAttribute*>("MeiAttribute", init<string, string>())
.def(init<MeiNamespace*, string, string>()) .def(init<MeiNamespace*, string, string>())
.def("__eq__", &MeiAttribute_EqualWrap) .def("__eq__", &MeiAttribute_EqualWrap)
.def("__ne__", &MeiAttribute_NEqualWrap) .def("__ne__", &MeiAttribute_NEqualWrap)
.def("__str__", &MeiAttribute_Print)
.def("__repr__", &MeiAttribute_Print)
.def("getName", &MeiAttribute::getName) .def("getName", &MeiAttribute::getName)
.add_property("name", &MeiAttribute::getName) .add_property("name", &MeiAttribute::getName)


Expand Down
30 changes: 30 additions & 0 deletions python/src/_libmei_exceptions.cpp
Expand Up @@ -41,6 +41,8 @@ object pyChildNotFoundExceptionType;
object pyNoVersionFoundExceptionType; object pyNoVersionFoundExceptionType;
object pyElementNotRegisteredExceptionType; object pyElementNotRegisteredExceptionType;
object pyDocumentRootNotSetExceptionType; object pyDocumentRootNotSetExceptionType;
object pyFileWriteFailureExceptionType;
object pyMalformedFileExceptionType;


void MeiExceptionTranslate(mei::MeiException const& e) { void MeiExceptionTranslate(mei::MeiException const& e) {
assert(pyMeiExceptionType != NULL); assert(pyMeiExceptionType != NULL);
Expand Down Expand Up @@ -98,6 +100,20 @@ void DocumentRootNotSetExceptionTranslate(mei::DocumentRootNotSetException const
throw_error_already_set(); throw_error_already_set();
} }


void FileWriteFailureExceptionTranslate(mei::FileWriteFailureException const& e) {
assert(pyFileWriteFailureExceptionType != NULL);
object pythonExceptionInstance(e);
PyErr_SetObject(pyFileWriteFailureExceptionType.ptr(), pythonExceptionInstance.ptr());
throw_error_already_set();
}

void MalformedFileExceptionTranslate(mei::MalformedFileException const& e) {
assert(pyMalformedFileExceptionType != NULL);
object pythonExceptionInstance(e);
PyErr_SetObject(pyMalformedFileExceptionType.ptr(), pythonExceptionInstance.ptr());
throw_error_already_set();
}



BOOST_PYTHON_MODULE(_libmei_exceptions) { BOOST_PYTHON_MODULE(_libmei_exceptions) {
object meiexception = class_<mei::MeiException>("MeiException", init<string>()) object meiexception = class_<mei::MeiException>("MeiException", init<string>())
Expand Down Expand Up @@ -156,4 +172,18 @@ BOOST_PYTHON_MODULE(_libmei_exceptions) {
pyDocumentRootNotSetExceptionType = noroot; pyDocumentRootNotSetExceptionType = noroot;
register_exception_translator<mei::DocumentRootNotSetException>(&DocumentRootNotSetExceptionTranslate); register_exception_translator<mei::DocumentRootNotSetException>(&DocumentRootNotSetExceptionTranslate);


object filewrite = class_<mei::FileWriteFailureException>("FileWriteFailureException", init<string>())
.def("what", &mei::FileWriteFailureException::what)
.add_property("message", &mei::FileWriteFailureException::what)
;
pyFileWriteFailureExceptionType = filewrite;
register_exception_translator<mei::FileWriteFailureException>(&FileWriteFailureExceptionTranslate);

object malformed = class_<mei::MalformedFileException>("MalformedFileException", init<string>())
.def("what", &mei::MalformedFileException::what)
.add_property("message", &mei::MalformedFileException::what)
;
pyMalformedFileExceptionType = malformed;
register_exception_translator<mei::MalformedFileException>(&MalformedFileExceptionTranslate);

} }
111 changes: 111 additions & 0 deletions python/test/testdocs/malformed.mei
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?oxygen SCHSchema="http://music-encoding.org/mei/schemata/2010-05/rng/mei-all.rng"?>
<?oxygen RNGSchema="http://music-encoding.org/mei/schemata/2010-05/rng/mei-all.rng"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="2012">
<meiHead>
<fileDesc>
<titleStmt>
<title>Lute Tablature</title>
<respStmt>
<name>Campion</name>
</respStmt>
</titleStmt>
<pubStmt/>
<sourceDesc>
<source>
<titleStmt>
<title/>
<respStmt>
<name/>
</respStmt>
</titleStmt>
<pubStmt/>
</source>
</sourceDesc>
</meiHead>
<music>
<body>
<!-- Encoding 1: above-the-staff duration values not explicitly encoded
They can be implied from the @dur attributes on chord/note. -->
<mdiv>
<score>
<scoreDef meter.count="2" meter.unit="2" meter.sym="cut" key.sig="0">
<staffGrp>
<!-- Tab "staff" has same number of lines as tokens in tab.strings -->
<!-- String pitches (written) given from highest to lowest -->
<staffDef n="1" lines="6" tab.strings="e5 b4 g4 d4 a3 e3"/>
</staffGrp>
</scoreDef>
<section>
<measure n="1">
<staff>
<layer>
<chord dur="2">
<!-- extend tab.fret notation to include non-numerical values, such as 'a'? -->
<note tab.fret="1" tab.string="6"/>
<!-- more notes -->
</chord>
<chord dur="4">
<!-- notes -->
</chord>
<!-- Ambiguous rhythmic representation, i.e., missing @dur on chord, is OK in MEI -->
<chord>
<!-- notes -->
</chord>
</layer>
</staff>
</measure>
<measure n="2"/>
<measure n="3"/>
<!-- Extend list of values for @left/@right to include value that indicates dots in all spaces? -->
<measure n="4" right="rptboth"/>
<measure n="5" left="rptboth"/>
</section>
</score>
</mdiv>

<!-- Encoding 2: above-the-staff duration values explicitly encoded
This is probably bad practice as it puts stuff in the model (the MEI) that ought to be in the view. -->
<mdiv>
<score>
<scoreDef meter.count="2" meter.unit="2" meter.sym="cut" key.sig="0">
<staffGrp>
<!-- A single-line staff where the line is invisible, all notes placed 'on the line' -->
<staffDef n="1" lines="1" lines.visible="false" ontheline="true"/>
<staffDef n="2" lines="6" tab.strings="e5 b4 g4 d4 a3 e3"/>
</staffGrp>
</scoreDef>
<section>
<measure n="1">
<staff n="1">
<layer>
<note dur="2"/>
<note dur="4"/>
<space/>
</layer>
</staff>
<staff n="2">
<layer>
<chord dur="2">
<note tab.fret="1" tab.string="6"/>
<!-- notes -->
</chord>
<chord dur="4">
<!-- notes -->
</chord>
<chord>
<!-- notes -->
</chord>
</layer>
</staff>
</measure>
<measure n="2"/>
<measure n="3"/>
<measure n="4" right="rptboth"/>
<measure n="5" left="rptboth"/>
</section>
</score>
</mdiv>
</body>
</music>
</mei>
11 changes: 10 additions & 1 deletion python/test/xmlexport_test.py
Expand Up @@ -5,7 +5,7 @@
import shutil import shutil
import pymei import pymei
from pymei import MeiElement, MeiAttribute, MeiElementList, MeiDocument, MeiNamespace, XmlImport, XmlExport from pymei import MeiElement, MeiAttribute, MeiElementList, MeiDocument, MeiNamespace, XmlImport, XmlExport
from pymei.exceptions import DocumentRootNotSetException from pymei.exceptions import DocumentRootNotSetException, FileWriteFailureException


class XmlExportTest(unittest.TestCase): class XmlExportTest(unittest.TestCase):


Expand Down Expand Up @@ -37,6 +37,15 @@ def test_documentrootnotset(self):
with self.assertRaises(DocumentRootNotSetException) as cm: with self.assertRaises(DocumentRootNotSetException) as cm:
ret = XmlExport.meiDocumentToText(doc) ret = XmlExport.meiDocumentToText(doc)
self.assertTrue(isinstance(cm.exception, DocumentRootNotSetException)) self.assertTrue(isinstance(cm.exception, DocumentRootNotSetException))

def test_documentwritefailure(self):
doc = MeiDocument()
root = MeiElement("mei")
root.id = "myid"
doc.root = root
with self.assertRaises(FileWriteFailureException) as cm:
ret = XmlExport.meiDocumentToFile(doc, "C:/StupidPath")
self.assertTrue(isinstance(cm.exception, FileWriteFailureException))


def test_exportvalueandtail(self): def test_exportvalueandtail(self):
doc = MeiDocument() doc = MeiDocument()
Expand Down

0 comments on commit 3144ca8

Please sign in to comment.