]> diplodocus.org Git - flac-archive/commitdiff
Move Tags class into new flac_archive package, fix a bug in it, and
authorepg <>
Sat, 21 Apr 2007 19:26:22 +0000 (19:26 +0000)
committerepg <>
Sat, 21 Apr 2007 19:26:22 +0000 (19:26 +0000)
test it.  These stupid scripts will finally start sharing code and
getting some formal testing.

flac_archive/tags.py:
    (Tags): Move here from flac2mp3, and rename ._tags to ._tracks .
    The tag-loading loop from flac2mp3 get_tags becomes the new .load
    method.

    (Tags.get): Return all matching tag data instead of either global
    or per-track (oops).

    (Tags.gets): Adapt to that change, and allow other separators than
    just '\n', which becomes a default.

    (Tags.all, Tags.track): New methods for getting a tag block for
    all tags (whole disc) or just a track, respectively.  To be used
    by fa-flacd in single-file and per-track modes, respectively.

flac2mp3:
    Use flac_archive.tags.Tags.  Use Tags.load in get_tags .

setup.py:
    Note MIT license and install flac_archive package.

test/run:
    Copy test-runner from py-gurps.

test/test.py:
    Load all tests.

test/testtags.py:
    Test Tags class.

flac2mp3
flac_archive/tags.py [new file with mode: 0644]
setup.py
test/run [new file with mode: 0755]
test/test.py [new file with mode: 0644]
test/testtags.py [new file with mode: 0755]

index 1e29ad0..3f0ef90 100755 (executable)
--- a/flac2mp3
+++ b/flac2mp3
@@ -58,6 +58,8 @@ import org.diplodocus.jobs
 from org.diplodocus import flac, taglib
 from org.diplodocus.util import run_or_die
 
+from flac_archive.tags import Tags
+
 ################################################################################
 # The child processes
 
@@ -146,42 +148,6 @@ def get_decode_args(fn):
 
     return args
 
-# XXX other things should usue this; flac files, for example, should
-# get PART as part of the filelname, same as mp3s.
-class Tags(object):
-    def __init__(self):
-        self._global = {}
-        self._tags = {}
-    def __len__(self):
-        # All files have at least one track.
-        return max(1, len(self._tags))
-    def get(self, key, track=None):
-        key = key.upper()
-        try:
-            try:
-                return self._tags[track][key]
-            except KeyError:
-                return self._global[key]
-        except KeyError:
-            return None
-    def gets(self, key, track=None):
-        value = self.get(key, track)
-        if value == None:
-            return None
-        return '\n'.join(value)
-    def set(self, key, value, track=None):
-        key = key.upper()
-        if track == None:
-            tags = self._global
-        else:
-            try:
-                tags = self._tags[track]
-            except KeyError:
-                tags = self._tags[track] = {}
-        if key not in tags:
-            tags[key] = []
-        tags[key].append(value)
-
 def get_tags(fn):
     """Return the ARTIST, ALBUM, and DATE tags followed by the TITLE tags
     in the file FN."""
@@ -189,17 +155,8 @@ def get_tags(fn):
     tags = Tags()
 
     p = Popen(['metaflac', '--export-tags-to=-', fn], stdout=PIPE)
-    for line in (x.rstrip() for x in p.stdout):
-        (tag, value) = line.split('=', 1)
-
-        m = re.search(r'\[([0-9]+)]$', tag)
-        if m != None:
-            tag = tag[:m.start()]
-            track = int(m.group(1))
-        else:
-            track = None
+    tags.load(p.stdout)
 
-        tags.set(tag, value, track)
     # XXX dataloss!  check status
     status = p.wait()
 
diff --git a/flac_archive/tags.py b/flac_archive/tags.py
new file mode 100644 (file)
index 0000000..9843e37
--- /dev/null
@@ -0,0 +1,79 @@
+import re
+
+class Tags(object):
+    def __init__(self):
+        self._global = {}
+        self._tracks = {}
+
+    def __len__(self):
+        # All files have at least one track.
+        return max(1, len(self._tracks))
+
+    def set(self, key, value, track=None):
+        key = key.upper()
+        if track == None:
+            tags = self._global
+        else:
+            try:
+                tags = self._tracks[track]
+            except KeyError:
+                tags = self._tracks[track] = {}
+        if key not in tags:
+            tags[key] = []
+        tags[key].append(value)
+
+    def load(self, fp):
+        for line in (x.rstrip() for x in fp):
+            (tag, value) = line.split('=', 1)
+
+            m = re.search(r'\[([0-9]+)]$', tag)
+            if m != None:
+                tag = tag[:m.start()]
+                track = int(m.group(1))
+            else:
+                track = None
+
+            self.set(tag, value, track)
+
+    def get(self, key, track=None):
+        result = []
+        key = key.upper()
+        try:
+            result.extend(self._global[key])
+        except KeyError:
+            pass
+        try:
+            result.extend(self._tracks[track][key])
+        except KeyError:
+            pass
+        return result
+
+    def gets(self, key, track=None, separator='\n'):
+        value = self.get(key, track)
+        if len(value) == 0:
+            return None
+        return separator.join(value)
+
+    def all(self):
+        result = []
+        for (tag, values) in self._global.iteritems():
+            for value in values:
+                result.append('='.join([tag, value]))
+        for (track, tags) in self._tracks.iteritems():
+            for (tag, values) in tags.iteritems():
+                for value in values:
+                    result.append('%s[%d]=%s' % (tag, track, value))
+        return result
+
+    def track(self, track):
+        result = ['TRACKNUMBER=%d' % (track,)]
+        for (tag, values) in self._global.iteritems():
+            for value in values:
+                result.append('='.join([tag, value]))
+        for (this_track, tags) in self._tracks.iteritems():
+            if this_track != track:
+                continue
+            for (tag, values) in tags.iteritems():
+                for value in values:
+                    result.append('%s=%s' % (tag, value))
+        return result
index 766f900..17c0f47 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -9,8 +9,10 @@ taglib_cflags = Popen([taglib_config, '--cflags'],
 taglib_libs = Popen([taglib_config, '--libs'],
                     stdout=PIPE).communicate()[0].strip().split()
 
-setup(name='flac-archive',
-      version='6',
+setup(name='flac-archive', version='6',
+      license='MIT',
+
+      packages=['flac_archive'],
       scripts=[
     'fa-flacd',
     'fa-rip',
diff --git a/test/run b/test/run
new file mode 100755 (executable)
index 0000000..0169785
--- /dev/null
+++ b/test/run
@@ -0,0 +1,65 @@
+#! /usr/bin/env zsh
+
+dir=$(cd $(dirname $0) && pwd)
+top=$(cd ${dir}/.. && pwd)
+export PYTHONPATH="${top}:${PYTHONPATH}"
+
+typeset -a coverage_init
+typeset -a coverage
+: ${PYTHON:=python2.4}
+while getopts 'C:cp:' ch; do
+    case ${ch} in
+    C)
+        coverage_report=${OPTARG}
+        ;;
+    c)
+        coverage_init=(${PYTHON} ${top}/coverage.py -e)
+        coverage=(${top}/coverage.py -x)
+        ;;
+    p)
+        PYTHON=${OPTARG}
+        ;;
+    ?)
+        echo ${help}
+        exit -1
+        ;;
+    esac
+done
+shift $((${OPTIND} - 1))
+
+################################################################################
+if [[ -n ${coverage_report} ]]; then
+    if [[ ${coverage_report} == '.' ]]; then
+        cov=()
+        coverage_report=(flac_archive/*.py)
+    else
+        cov=(-c "${coverage_report}.coverage")
+    fi
+
+    opts=("$@")
+    [[ ${#opts} == 0 ]] && opts=(-mr)
+    exec ${PYTHON} ${top}/coverage.py ${cov} ${opts} ${coverage_report}
+fi
+
+################################################################################
+
+failed=0
+
+${coverage_init}
+if [[ -n ${coverage} ]] && [[ $# -eq 1 ]]; then
+    out=$1.coverage
+    rm -f ${out}
+    exec ${PYTHON} ${coverage} -c ${out} ${1/flac_archive\//test/test}
+fi
+${PYTHON} ${coverage} ${dir}/test.py || (( failed++ ))
+
+setopt EXTENDED_GLOB
+if [[ -n ${coverage} ]]; then
+    for i in ${dir}/test[a-z]*.py; do
+        out=${top}/flac_archive/${i#${dir}/test}.coverage
+        rm -f ${out}
+        ${PYTHON} ${coverage} -c ${out} -x ${i}
+    done
+fi
+
+exit ${failed}
diff --git a/test/test.py b/test/test.py
new file mode 100644 (file)
index 0000000..01443ba
--- /dev/null
@@ -0,0 +1,6 @@
+from unittest import main
+
+from testtags import *
+
+if __name__ == '__main__':
+    main()
diff --git a/test/testtags.py b/test/testtags.py
new file mode 100755 (executable)
index 0000000..765d7e3
--- /dev/null
@@ -0,0 +1,40 @@
+#! /usr/bin/python2.4
+
+import cStringIO, sys
+
+from unittest import TestCase, main
+
+sys.path.insert(0, '.')
+from flac_archive.tags import Tags
+
+_tags1 = """ARTIST=Basil
+ALBUM=The Rat
+DATE=1994
+TITLE[1]=Song 1
+ARTIST[1]=Manuel
+TITLE[2]=Song 2
+TITLE[3]=Song 3
+PART[3]=Part the First
+"""
+
+class TagsTestCase(TestCase):
+    def testBasic(self):
+        tags = Tags()
+        tags.load(cStringIO.StringIO(_tags1))
+        self.assertEquals(tags.gets('ARTIST'), 'Basil')
+        self.assertEquals(tags.gets('ARTIST', 1), 'Basil\nManuel')
+        self.assertEquals(tags.gets('ARTIST', 1, ' foo ' ), 'Basil foo Manuel')
+        self.assertEquals(tags.gets('ARTIST', 2), 'Basil')
+
+        self.assertEquals(sorted(tags.all()),
+                          sorted(_tags1.strip().split('\n')))
+        self.assertEquals(sorted(tags.track(1)),
+                          ['ALBUM=The Rat', 'ARTIST=Basil', 'ARTIST=Manuel',
+                           'DATE=1994', 'TITLE=Song 1', 'TRACKNUMBER=1'])
+        self.assertEquals(sorted(tags.track(3)),
+                          ['ALBUM=The Rat', 'ARTIST=Basil', 'DATE=1994',
+                           'PART=Part the First', 'TITLE=Song 3',
+                           'TRACKNUMBER=3'])
+
+if __name__ == '__main__':
+    main()