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:
Anna Schumaker 2019-02-15 15:54:00 -05:00
parent 2c022163ad
commit 1eac742bc4
2 changed files with 46 additions and 34 deletions

View File

@ -1,15 +1,17 @@
# Copyright 2019 (c) Anna Schumaker.
import asyncio
import concurrent.futures
import mutagen
import unittest
import os
import track
import unittest
test_tracks = os.path.abspath("./trier/Test Album")
test_library = os.path.abspath("./trier/Test Library")
class TestTrackClass(unittest.TestCase):
def setUp(self):
track.track_list.clear()
def test_init_basic(self):
p = [ test_tracks, "01 - Test Track.ogg" ]
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.genre, "Test")
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):
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.genre, "Unknown")
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):
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)
def test_track_add(self):
track.tracklist.clear()
t = track.add(os.path.join(test_tracks, "01 - Test Track.ogg"))
fs = 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.assertEqual(len(track.tracklist), 1)
self.assertIn(t, track.tracklist)
self.assertEqual(len(track.track_list), 1)
self.assertIn(t, track.track_list)
self.assertIsNone(track.add(os.path.join(test_tracks, "01 - Test Track.ogg")))
self.assertEqual(len(track.tracklist), 1)
self.assertIsNone(track.add("99 - No Such Track.ogg"))
self.assertEqual(len(track.tracklist), 1)
self.assertIsNone(track.add(os.path.join(test_tracks, "01 - Test Track.ogg")).result())
self.assertEqual(len(track.track_list), 1)
self.assertIsNone(track.add("99 - No Such Track.ogg").result())
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.assertEqual(len(track.tracklist), 2)
self.assertIn(u, track.tracklist)
self.assertEqual(len(track.track_list), 2)
self.assertIn(u, track.track_list)
def test_parallel_add(self):
track.tracklist.clear()
count = 0
tracks = [ ]
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as pool:
for dirname, subdirs, files in os.walk(test_library):
for f in files:
tracks.append(pool.submit(track.add, os.path.join(dirname, f)))
count += 1
self.assertEqual(len(track.tracklist), count)
self.assertEqual(len(tracks), count)
for t in tracks:
self.assertIsNotNone(t)
if __name__ == '__main--':
unittest.main()
count = 0
futures = [ ]
done = [ ]
none = [ ]
for dirname, subdirs, files in os.walk(test_library):
for f in files:
futures.append(track.add(os.path.join(dirname, f)))
futures.append(track.add(os.path.join(dirname, f)))
count += 1
self.assertLess(len(track.track_list), count)
for fs in concurrent.futures.as_completed(futures):
if fs.result() is not None:
done.append(fs.result())
else:
none.append(fs.result())
self.assertEqual(len(done), count)
self.assertEqual(len(none), count)
self.assertEqual(len(track.track_list), count)

View File

@ -1,11 +1,13 @@
# Copyright 2019 (c) Anna Schumaker.
import album
import concurrent.futures
import mutagen
import os
import re
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:
def __init__(self, path):
@ -26,11 +28,14 @@ class Track:
self.discnumber = int(discno_map.get(match.group(), match.group()))
def add(path):
def __add(path):
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)
tracklist.append(track)
track_list.append(track)
return track
except mutagen.MutagenError:
return None
def add(path):
return track_pool.submit(__add, path)