Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Improved Python bindings #3829

Merged
merged 9 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added bindings/python/py.typed
Empty file.
103 changes: 58 additions & 45 deletions bindings/python/verovio.i
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
%ignore vrv::Toolkit::ResetLogBuffer( );
%ignore vrv::Toolkit::SetShowBoundingBoxes( bool );
%ignore vrv::Toolkit::SetCString( const std::string & );
%ignore vrv::Toolkit::PrintOptionUsage;
%ignore vrv::Toolkit::GetHumdrum;
%ignore vrv::Toolkit::RenderToDeviceContext;
%ignore vrv::EnableLogToBuffer;

%feature("autodoc", "1");

Expand All @@ -29,170 +33,179 @@

// Toolkit::Edit
%feature("shadow") vrv::Toolkit::Edit( const std::string & ) %{
def edit(toolkit, editor_action: dict) -> bool:
def edit(self, editor_action: dict) -> bool:
"""Edit the MEI data."""
return $action(toolkit, json.dumps(editor_action))
return $action(self, json.dumps(editor_action))
%}

// Toolkit::EditInfo
%feature("shadow") vrv::Toolkit::EditInfo() %{
def editInfo(toolkit) -> dict:
def editInfo(self) -> dict:
"""Return the editor status."""
return json.loads($action(toolkit))
return json.loads($action(self))
%}

// Toolkit::GetAvailableOptions
%feature("shadow") vrv::Toolkit::GetAvailableOptions() const %{
def getAvailableOptions(toolkit) -> dict:
def getAvailableOptions(self) -> dict:
"""Return a dictionary of all the options with their default value."""
return json.loads($action(toolkit))
return json.loads($action(self))
%}

// Toolkit::GetDefaultOptions
%feature("shadow") vrv::Toolkit::GetDefaultOptions() const %{
def getDefaultOptions(toolkit) -> dict:
def getDefaultOptions(self) -> dict:
"""Return a dictionary of all the options with their default value."""
return json.loads($action(toolkit))
return json.loads($action(self))
%}

// Toolkit::GetDescriptiveFeatures
%feature("shadow") vrv::Toolkit::GetDescriptiveFeatures(const std::string &) %{
def getDescriptiveFeatures(toolkit, options: Optional[dict] = None) -> dict:
def getDescriptiveFeatures(self, options: Optional[dict] = None) -> dict:
"""Return descriptive features as dictionary."""
if options is None:
options = {}
return json.loads($action(toolkit, json.dumps(options)))
return json.loads($action(self, json.dumps(options)))
%}

// Toolkit::GetElementAttr
%feature("shadow") vrv::Toolkit::GetElementAttr(const std::string &) %{
def getElementAttr(toolkit, xml_id: str) -> dict:
def getElementAttr(self, xmlId: str) -> dict:
"""Return element attributes as dictionary."""
return json.loads($action(toolkit, xml_id))
return json.loads($action(self, xmlId))
%}

// Toolkit::GetElementsAtTime
%feature("shadow") vrv::Toolkit::GetElementsAtTime(int) %{
def getElementsAtTime(toolkit, millisec: int) -> dict:
def getElementsAtTime(self, millisec: int) -> dict:
"""Return array of IDs of elements being currently played."""
return json.loads($action(toolkit, millisec))
return json.loads($action(self, millisec))
%}

// Toolkit::GetExpansionIdsForElement
%feature("shadow") vrv::Toolkit::GetExpansionIdsForElement(const std::string &) %{
def getExpansionIdsForElement(toolkit, xml_id: str) -> dict:
def getExpansionIdsForElement(self, xmlId: str) -> dict:
"""Return a vector of ID strings of all elements (the notated and the expanded) for a given element."""
return json.loads($action(toolkit, xml_id))
return json.loads($action(self, xmlId))
%}

// Toolkit::GetMEI
%feature("shadow") vrv::Toolkit::GetMEI(const std::string & = "") %{
def getMEI(toolkit, options: Optional[dict] = None) -> str:
def getMEI(self, options: Optional[dict] = None) -> str:
"""Get the MEI as a string."""
if options is None:
options = {}
return $action(toolkit, json.dumps(options))
return $action(self, json.dumps(options))
%}

// Toolkit::GetMIDIValuesForElement
%feature("shadow") vrv::Toolkit::GetMIDIValuesForElement(const std::string &) %{
def getMIDIValuesForElement(toolkit, xml_id: str) -> dict:
def getMIDIValuesForElement(self, xmlId: str) -> dict:
"""Return MIDI values of the element with the ID (xml:id)."""
return json.loads($action(toolkit, xml_id))
return json.loads($action(self, xmlId))
%}

// Toolkit::GetOptions
%feature("shadow") vrv::Toolkit::GetOptions() const %{
def getOptions(toolkit) -> dict:
def getOptions(self) -> dict:
"""Return a dictionary of all the options with their current value."""
return json.loads($action(toolkit))
return json.loads($action(self))
%}

// Toolkit::GetTimesForElement
%feature("shadow") vrv::Toolkit::GetTimesForElement(const std::string &) %{
def getTimesForElement(toolkit, xml_id: str) -> dict:
def getTimesForElement(self, xmlId: str) -> dict:
"""Return a dictionary with the following key values for a given note."""
return json.loads($action(toolkit, xml_id))
return json.loads($action(self, xmlId))
%}

// Toolkit::RedoLayout
%feature("shadow") vrv::Toolkit::RedoLayout(const std::string & = "") %{
def redoLayout(toolkit, options: Optional[dict] = None) -> None:
def redoLayout(self, options: Optional[dict] = None) -> None:
"""Redo the layout of the loaded data."""
if options is None:
options = {}
return $action(toolkit, json.dumps(options))
return $action(self, json.dumps(options))
%}

// Toolkit::RenderData
%feature("shadow") vrv::Toolkit::RenderData(const std::string &, const std::string &) %{
def renderData(toolkit, data, options: dict) -> str:
def renderData(self, data: str, options: dict) -> str:
"""Render the first page of the data to SVG."""
return $action(toolkit, data, json.dumps(options))
return $action(self, data, json.dumps(options))
%}

// Toolkit::RenderToExpansionMap
%feature("shadow") vrv::Toolkit::RenderToExpansionMap() %{
def renderToExpansionMap(toolkit) -> list:
def renderToExpansionMap(self) -> list:
"""Render a document's expansion map, if existing."""
return json.loads($action(toolkit))
return json.loads($action(self))
%}

// Toolkit::RenderToExpansionMapFile
%feature("shadow") vrv::Toolkit::RenderToExpansionMapFile(const std::string &) %{
def renderToExpansionMapFile(toolkit, filename: str) -> bool:
def renderToExpansionMapFile(self, filename: str) -> bool:
"""Render a document's expansion map and save it to a file."""
return $action(toolkit, filename)
return $action(self, filename)
%}

// Toolkit::RenderToTimemap
%feature("shadow") vrv::Toolkit::RenderToTimemap(const std::string & = "") %{
def renderToTimemap(toolkit, options: Optional[dict] = None) -> list:
def renderToTimemap(self, options: Optional[dict] = None) -> list:
"""Render a document to a timemap."""
if options is None:
options = {}
return json.loads($action(toolkit, json.dumps(options)))
return json.loads($action(self, json.dumps(options)))
%}

// Toolkit::RenderToTimemapFile
%feature("shadow") vrv::Toolkit::RenderToTimemapFile(const std::string &, const std::string & = "") %{
def renderToTimemapFile(toolkit, filename: str, options: Optional[dict] = None) -> bool:
def renderToTimemapFile(self, filename: str, options: Optional[dict] = None) -> bool:
"""Render a document to timemap and save it to the file."""
if options is None:
options = {}
return $action(toolkit, filename, json.dumps(options))
return $action(self, filename, json.dumps(options))
%}

// Toolkit::SaveFile
%feature("shadow") vrv::Toolkit::SaveFile(const std::string &, const std::string & = "") %{
def saveFile(toolkit, filename: str, options: Optional[dict] = None) -> bool:
def saveFile(self, filename: str, options: Optional[dict] = None) -> bool:
"""Get the MEI and save it to the file."""
if options is None:
options = {}
return $action(toolkit, filename, json.dumps(options))
return $action(self, filename, json.dumps(options))
%}

// Toolkit::Select
%feature("shadow") vrv::Toolkit::Select(const std::string &) %{
def select(toolkit, selection: dict) -> bool:
def select(self, selection: dict) -> bool:
"""Set the value for a selection."""
return $action(toolkit, json.dumps(selection))
return $action(self, json.dumps(selection))
%}

// Toolkit::SetOptions
%feature("shadow") vrv::Toolkit::SetOptions(const std::string &) %{
def setOptions(toolkit, json_options: dict) -> bool:
def setOptions(self, json_options: dict) -> bool:
"""Set option values."""
return $action(toolkit, json.dumps(json_options))
return $action(self, json.dumps(json_options))
%}

// Toolkit::ValidatePAE
%feature("shadow") vrv::Toolkit::ValidatePAE(const std::string &) %{
def validatePAE(toolkit, data: Union[str, dict]) -> dict:
def validatePAE(self, data: Union[str, dict]) -> dict:
"""Validate the Plaine and Easie code passed in the string data."""
if isinstance(data, dict):
data = json.dumps(data);
return json.loads($action(toolkit, data))
return json.loads($action(self, data))
%}

// Toolkit::ValidatePAEFile
%feature("shadow") vrv::Toolkit::ValidatePAEFile(const std::string &) %{
def validatePAEFile(self, filename: str) -> dict:
"""Validate the Plaine and Easie code passed in the string data."""
if isinstance(data, dict):
data = json.dumps(data);
return json.loads($action(self, data))
%}

%module(package="verovio") verovio
Expand All @@ -203,7 +216,7 @@ def validatePAE(toolkit, data: Union[str, dict]) -> dict:
%{
#include "../../include/vrv/toolkit.h"
#include "../../include/vrv/toolkitdef.h"

using namespace vrv;
using namespace std;
%}
105 changes: 105 additions & 0 deletions bindings/python/verovio.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# This file was generated by mypy stubgen and then hand-edited
# to match the contents of verovio.py. It should be kept up-to-date
# when methods are added to the toolkit.

from typing import Any

class _SwigNonDynamicMeta(type):
def __setattr__(self, name: str, value: Any, /) -> None: ...

class toolkit:
thisown: toolkit
def __init__(self, initFont: bool = True) -> None: ...
__swig_destroy__: None
def getID(self) -> str: ...
def getResourcePath(self) -> str: ...
def setResourcePath(self, path: str) -> None: ...
def getLog(self) -> str: ...
def getVersion(self) -> str: ...
def resetXmlIdSeed(self, seed: int) -> None: ...
def loadFile(self, filename: str) -> bool: ...
def loadData(self, data: str) -> bool: ...
def loadZipDataBase64(self, data: str) -> bool: ...
def loadZipDataBuffer(self, data: bytes, length: int) -> bool: ...
def validatePAEFile(self, filename: str) -> dict: ...
def validatePAE(self, data: str | dict) -> dict: ...
def getPageCount(self) -> int: ...
def getOptions(self) -> dict: ...
def getDefaultOptions(self) -> dict: ...
def getAvailableOptions(self) -> dict: ...
def setOptions(self, json_options: dict) -> bool: ...
def resetOptions(self) -> None: ...
def getOptionUsageString(self) -> str: ...
def setScale(self, scale: int) -> bool: ...
def getScale(self) -> int: ...
def setOutputTo(self, outputTo: str) -> bool: ...
def select(self, selection: dict) -> bool: ...
def edit(self, editor_action: dict) -> bool: ...
def editInfo(self) -> dict: ...
def renderData(self, data: str, options: dict) -> str: ...
def renderToSVG(self, pageNo: int = 1, xmlDeclaration: bool = False) -> str: ...
def renderToSVGFile(self, filename, pageNo: int = 1) -> bool: ...
def renderToMIDI(self) -> str: ...
def renderToMIDIFile(self, filename: str) -> bool: ...
def renderToPAE(self) -> str: ...
def renderToPAEFile(self, filename: str) -> bool: ...
def renderToTimemap(self, options: dict | None = None) -> list: ...
def renderToExpansionMap(self) -> list: ...
def renderToTimemapFile(self, filename: str, options: dict | None = None) -> bool: ...
def renderToExpansionMapFile(self, filename: str) -> bool: ...
def convertMEIToHumdrum(self, meiData: str) -> str: ...
def convertHumdrumToHumdrum(self, humdrumData: str) -> str: ...
def convertHumdrumToMIDI(self, humdrumData: str) -> str: ...
def getHumdrumFile(self, filename: str) -> bool: ...
def getMEI(self, options: dict | None = None) -> str: ...
def saveFile(self, filename: str, options: dict | None = None) -> bool: ...
def getDescriptiveFeatures(self, options: dict | None = None) -> dict: ...
def getElementsAtTime(self, millisec: int) -> dict: ...
def getPageWithElement(self, xmlId: str) -> int: ...
def getElementAttr(self, xmlId: str) -> dict: ...
def getNotatedIdForElement(self, xmlId: str) -> str: ...
def getExpansionIdsForElement(self, xmlId: str) -> dict: ...
def getTimeForElement(self, xmlId: str) -> int: ...
def getMIDIValuesForElement(self, xmlId: str) -> dict: ...
def getTimesForElement(self, xmlId: str) -> dict: ...
def redoLayout(self, options: dict | None = None) -> None: ...
def redoPagePitchPosLayout(self) -> None: ...
def setHumdrumBuffer(self, contents: bytes) -> None: ...
def getHumdrumBuffer(self) -> bytes: ...
def clearHumdrumBuffer(self) -> None: ...
def setInputFrom(self, format: str) -> bool: ...
def getInputFrom(self) -> int: ...
def getOutputTo(self) -> int: ...
def setLocale(self) -> None: ...
def resetLocale(self) -> None: ...
def initClock(self) -> None: ...
def resetClock(self) -> None: ...
def getRuntimeInSeconds(self) -> float: ...
def logRuntime(self) -> None: ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any particular logic to the order? Alphabetical sorting would make hand-editing much easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's the order that's in toolkit.h, which is in semi-alphabetical order.

But the ones at the end are kinda questionable, since these are annotated with @nodocs and don't appear in the Verovio book, so they're not technically "public."


UNKNOWN: int
AUTO: int
MEI: int
HUMDRUM: int
HUMMEI: int
HUMMIDI: int
PAE: int
ABC: int
DARMS: int
VOLPIANO: int
MUSICXML: int
MUSICXMLHUM: int
MEIHUM: int
MUSEDATAHUM: int
ESAC: int
MIDI: int
TIMEMAP: int
EXPANSIONMAP: int
LOG_OFF: int
LOG_ERROR: int
LOG_WARNING: int
LOG_INFO: int
LOG_DEBUG: int

def setDefaultResourcePath(path: str) -> None: ...
def enableLog(level: int) -> None: ...
4 changes: 3 additions & 1 deletion cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ elseif (BUILD_AS_PYTHON)

if(${SWIG_VERSION} VERSION_GREATER_EQUAL "4.1.0")
list(APPEND CMAKE_SWIG_FLAGS "-doxygen")
list(APPEND CMAKE_SWIG_FLAGS "-fastproxy")
list(APPEND CMAKE_SWIG_FLAGS "-olddefs")
else()
list(APPEND CMAKE_SWIG_FLAGS "-py3;-DPY3")
endif()
Expand All @@ -234,7 +236,7 @@ elseif (BUILD_AS_PYTHON)
swig_add_library(verovio_module_${OUTPUT_VERSION_STRING} LANGUAGE python TYPE MODULE SOURCES ../bindings/python/verovio.i)
swig_link_libraries(verovio_module_${OUTPUT_VERSION_STRING} verovio ${Python_LIBRARIES})

add_library(verovio STATIC ../tools/c_wrapper.cpp ${all_SRC})
add_library(verovio STATIC ${all_SRC})

#####################
# Command-line tool #
Expand Down
2 changes: 1 addition & 1 deletion include/vrv/toolkit.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ class Toolkit {
*
* @remark nojs
*
* @param outputTo the output to value as string
* @param outputTo the value to output as string
* @return True if the option was successfully set
*/
bool SetOutputTo(std::string const &outputTo);
Expand Down
Loading