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

Load Scores from URL #404

Merged
merged 18 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from 14 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
32 changes: 31 additions & 1 deletion partitura/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"""
from typing import Union
import os

import urllib.request
from urllib.parse import urlparse
import tempfile
from .importmusicxml import load_musicxml
from .importmidi import load_score_midi, load_performance_midi
from .musescore import load_via_musescore
Expand All @@ -32,6 +34,32 @@ class NotSupportedFormatError(Exception):
pass


def is_url(input):
try:
result = urlparse(input)
return all([result.scheme, result.netloc])
except ValueError:
return False


def download_file(url):
# Send a GET request to the URL
with urllib.request.urlopen(url) as response:
data = response.read()

# Extract the file extension from the URL
extension = os.path.splitext(url)[-1]

# Create a temporary file
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=extension)
Copy link
Member

Choose a reason for hiding this comment

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

Won't it be the case that this file is never deleted, and keep accumulating on the computer?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I agree. Probably, I need to find a better solution and debug. The load score file needs access to the file to check the extension but maybe when delete=True the file is not deleted immediately when loaded. I will push a change soon.

Copy link
Member Author

Choose a reason for hiding this comment

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

Turns out that for python version 3.8 the temporary file options are not the same as for newer versions of python therefore I had to add more edits to ensure the deletion of tmp files immediately after the end of the function.


# Write the content to the temporary file
with open(temp_file.name, 'wb') as f:
f.write(data)

return temp_file.name


@deprecated_alias(score_fn="filename")
@deprecated_parameter("ensure_list")
def load_score(filename: PathLike, force_note_ids="keep") -> Score:
Expand All @@ -57,6 +85,8 @@ def load_score(filename: PathLike, force_note_ids="keep") -> Score:
scr: :class:`partitura.score.Score`
A score instance.
"""
if is_url(filename):
filename = download_file(filename)

extension = os.path.splitext(filename)[-1].lower()
if extension in (".mxl", ".xml", ".musicxml"):
Expand Down
4 changes: 2 additions & 2 deletions partitura/score.py
Original file line number Diff line number Diff line change
Expand Up @@ -6037,8 +6037,8 @@ def process_local_key(loc_k_text, glob_k_text, return_step_alter=False):
"iii": Interval(3, "m"),
"iv": Interval(4, "P"),
"v": Interval(5, "P"),
"vi": Interval(6, "m"),
"vii": Interval(7, "m"),
"vi": Interval(6, "M"),
"vii": Interval(7, "M"),
"viio": Interval(7, "M"),
"N": Interval(2, "m"),
"iio": Interval(2, "M"),
Expand Down
26 changes: 26 additions & 0 deletions tests/test_urlload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import unittest
from partitura import load_score
import numpy as np


class TestImport(unittest.TestCase):
def test_load_kern(self):
score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.krn")
note_array = score.note_array()
self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76]))

def test_load_mei(self):
score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.mei")
note_array = score.note_array()
self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76]))

def test_load_midi(self):
score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.mid")
note_array = score.note_array()
self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76]))

def test_load_musicxml(self):
score = load_score("https://raw.githubusercontent.com/CPJKU/partitura/refs/heads/main/partitura/assets/score_example.musicxml")
note_array = score.note_array()
self.assertTrue(np.all(note_array["pitch"] == [69, 72, 76]))

Loading