From: epg <> Date: Sat, 21 Apr 2007 19:26:22 +0000 (+0000) Subject: Move Tags class into new flac_archive package, fix a bug in it, and X-Git-Url: https://diplodocus.org/git/flac-archive/commitdiff_plain/cbfd1b29112cd8ab5540c1019f2a400f4bf20410?ds=sidebyside Move Tags class into new flac_archive package, fix a bug in it, and 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. --- diff --git a/flac2mp3 b/flac2mp3 index 1e29ad0..3f0ef90 100755 --- 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 index 0000000..9843e37 --- /dev/null +++ b/flac_archive/tags.py @@ -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 diff --git a/setup.py b/setup.py index 766f900..17c0f47 100644 --- 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 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 index 0000000..01443ba --- /dev/null +++ b/test/test.py @@ -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 index 0000000..765d7e3 --- /dev/null +++ b/test/testtags.py @@ -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()