curds: Move the ThreadPoolExecutor into the track code
I think it makes sense to do this transparently through the Track code so higher layers don't have to do as much work. We'll just return a Future-object corresponding to the track that will be added. It makes sense to only have one thread in this case, since __add() needs exclusive access to the track_list for its entire execution. Anything more would just create conflicts and actually increase execution time. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
2c022163ad
commit
1eac742bc4
|
@ -1,15 +1,17 @@
|
||||||
# Copyright 2019 (c) Anna Schumaker.
|
# Copyright 2019 (c) Anna Schumaker.
|
||||||
import asyncio
|
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import mutagen
|
import mutagen
|
||||||
import unittest
|
|
||||||
import os
|
import os
|
||||||
import track
|
import track
|
||||||
|
import unittest
|
||||||
|
|
||||||
test_tracks = os.path.abspath("./trier/Test Album")
|
test_tracks = os.path.abspath("./trier/Test Album")
|
||||||
test_library = os.path.abspath("./trier/Test Library")
|
test_library = os.path.abspath("./trier/Test Library")
|
||||||
|
|
||||||
class TestTrackClass(unittest.TestCase):
|
class TestTrackClass(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
track.track_list.clear()
|
||||||
|
|
||||||
def test_init_basic(self):
|
def test_init_basic(self):
|
||||||
p = [ test_tracks, "01 - Test Track.ogg" ]
|
p = [ test_tracks, "01 - Test Track.ogg" ]
|
||||||
t = track.Track(os.path.join(*p))
|
t = track.Track(os.path.join(*p))
|
||||||
|
@ -23,7 +25,7 @@ class TestTrackClass(unittest.TestCase):
|
||||||
self.assertEqual(t.album.date, 2019)
|
self.assertEqual(t.album.date, 2019)
|
||||||
self.assertEqual(t.album.genre, "Test")
|
self.assertEqual(t.album.genre, "Test")
|
||||||
self.assertEqual(t.album.albumartist, "Test Artist")
|
self.assertEqual(t.album.albumartist, "Test Artist")
|
||||||
self.assertEqual(len(track.tracklist), 0)
|
self.assertEqual(len(track.track_list), 0)
|
||||||
|
|
||||||
def test_init_empty(self):
|
def test_init_empty(self):
|
||||||
p = [ test_tracks, "00 - Empty Track.ogg" ]
|
p = [ test_tracks, "00 - Empty Track.ogg" ]
|
||||||
|
@ -38,7 +40,7 @@ class TestTrackClass(unittest.TestCase):
|
||||||
self.assertEqual(t.album.date, 0)
|
self.assertEqual(t.album.date, 0)
|
||||||
self.assertEqual(t.album.genre, "Unknown")
|
self.assertEqual(t.album.genre, "Unknown")
|
||||||
self.assertEqual(t.album.albumartist, "Unknown Artist")
|
self.assertEqual(t.album.albumartist, "Unknown Artist")
|
||||||
self.assertEqual(len(track.tracklist), 0)
|
self.assertEqual(len(track.track_list), 0)
|
||||||
|
|
||||||
def test_init_discno_detect(self):
|
def test_init_discno_detect(self):
|
||||||
join = os.path.join
|
join = os.path.join
|
||||||
|
@ -53,35 +55,40 @@ class TestTrackClass(unittest.TestCase):
|
||||||
self.assertEqual(track.Track(join(test_tracks, "10 - Test {Disc 20}.ogg")).discnumber, 20)
|
self.assertEqual(track.Track(join(test_tracks, "10 - Test {Disc 20}.ogg")).discnumber, 20)
|
||||||
|
|
||||||
def test_track_add(self):
|
def test_track_add(self):
|
||||||
track.tracklist.clear()
|
fs = track.add(os.path.join(test_tracks, "01 - Test Track.ogg"))
|
||||||
t = track.add(os.path.join(test_tracks, "01 - Test Track.ogg"))
|
self.assertEqual(len(track.track_list), 0)
|
||||||
|
t = fs.result()
|
||||||
self.assertIsNotNone(t)
|
self.assertIsNotNone(t)
|
||||||
self.assertEqual(len(track.tracklist), 1)
|
self.assertEqual(len(track.track_list), 1)
|
||||||
self.assertIn(t, track.tracklist)
|
self.assertIn(t, track.track_list)
|
||||||
|
|
||||||
self.assertIsNone(track.add(os.path.join(test_tracks, "01 - Test Track.ogg")))
|
self.assertIsNone(track.add(os.path.join(test_tracks, "01 - Test Track.ogg")).result())
|
||||||
self.assertEqual(len(track.tracklist), 1)
|
self.assertEqual(len(track.track_list), 1)
|
||||||
self.assertIsNone(track.add("99 - No Such Track.ogg"))
|
self.assertIsNone(track.add("99 - No Such Track.ogg").result())
|
||||||
self.assertEqual(len(track.tracklist), 1)
|
self.assertEqual(len(track.track_list), 1)
|
||||||
|
|
||||||
u = track.add(os.path.join(test_tracks, "02 - Test {Disc 2}.ogg"))
|
fs = track.add(os.path.join(test_tracks, "02 - Test {Disc 2}.ogg"))
|
||||||
|
u = fs.result()
|
||||||
self.assertIsNotNone(u)
|
self.assertIsNotNone(u)
|
||||||
self.assertEqual(len(track.tracklist), 2)
|
self.assertEqual(len(track.track_list), 2)
|
||||||
self.assertIn(u, track.tracklist)
|
self.assertIn(u, track.track_list)
|
||||||
|
|
||||||
def test_parallel_add(self):
|
def test_parallel_add(self):
|
||||||
track.tracklist.clear()
|
count = 0
|
||||||
count = 0
|
futures = [ ]
|
||||||
tracks = [ ]
|
done = [ ]
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as pool:
|
none = [ ]
|
||||||
for dirname, subdirs, files in os.walk(test_library):
|
for dirname, subdirs, files in os.walk(test_library):
|
||||||
for f in files:
|
for f in files:
|
||||||
tracks.append(pool.submit(track.add, os.path.join(dirname, f)))
|
futures.append(track.add(os.path.join(dirname, f)))
|
||||||
count += 1
|
futures.append(track.add(os.path.join(dirname, f)))
|
||||||
self.assertEqual(len(track.tracklist), count)
|
count += 1
|
||||||
self.assertEqual(len(tracks), count)
|
self.assertLess(len(track.track_list), count)
|
||||||
for t in tracks:
|
for fs in concurrent.futures.as_completed(futures):
|
||||||
self.assertIsNotNone(t)
|
if fs.result() is not None:
|
||||||
|
done.append(fs.result())
|
||||||
if __name__ == '__main--':
|
else:
|
||||||
unittest.main()
|
none.append(fs.result())
|
||||||
|
self.assertEqual(len(done), count)
|
||||||
|
self.assertEqual(len(none), count)
|
||||||
|
self.assertEqual(len(track.track_list), count)
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
# Copyright 2019 (c) Anna Schumaker.
|
# Copyright 2019 (c) Anna Schumaker.
|
||||||
import album
|
import album
|
||||||
|
import concurrent.futures
|
||||||
import mutagen
|
import mutagen
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
discno_map = { "one" : "1", "two" : "2", "three" : "3", "four" : "4", "five" : "5" }
|
discno_map = { "one" : "1", "two" : "2", "three" : "3", "four" : "4", "five" : "5" }
|
||||||
tracklist = [ ]
|
track_list = [ ]
|
||||||
|
track_pool = concurrent.futures.ThreadPoolExecutor(max_workers = 1)
|
||||||
|
|
||||||
class Track:
|
class Track:
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
|
@ -26,11 +28,14 @@ class Track:
|
||||||
self.discnumber = int(discno_map.get(match.group(), match.group()))
|
self.discnumber = int(discno_map.get(match.group(), match.group()))
|
||||||
|
|
||||||
|
|
||||||
def add(path):
|
def __add(path):
|
||||||
try:
|
try:
|
||||||
if not any(t.path == path for t in tracklist):
|
if not any(t.path == path for t in track_list):
|
||||||
track = Track(path)
|
track = Track(path)
|
||||||
tracklist.append(track)
|
track_list.append(track)
|
||||||
return track
|
return track
|
||||||
except mutagen.MutagenError:
|
except mutagen.MutagenError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def add(path):
|
||||||
|
return track_pool.submit(__add, path)
|
||||||
|
|
Loading…
Reference in New Issue