File: mutagen_wrapper.py

package info (click to toggle)
python-mediafile 0.14.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 1,968 kB
  • sloc: python: 2,953; makefile: 193
file content (72 lines) | stat: -rw-r--r-- 2,432 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import functools
import logging
import traceback

import mutagen
import mutagen._util

from mediafile.exceptions import MutagenError, UnreadableFileError

log = logging.getLogger(__name__)


def mutagen_call(action, filename, func, *args, **kwargs):
    """Call a Mutagen function with appropriate error handling.

    `action` is a string describing what the function is trying to do,
    and `filename` is the relevant filename. The rest of the arguments
    describe the callable to invoke.

    We require at least Mutagen 1.33, where `IOError` is *never* used,
    neither for internal parsing errors *nor* for ordinary IO error
    conditions such as a bad filename. Mutagen-specific parsing errors and IO
    errors are reraised as `UnreadableFileError`. Other exceptions
    raised inside Mutagen---i.e., bugs---are reraised as `MutagenError`.
    """
    try:
        return func(*args, **kwargs)
    except mutagen._util.MutagenError as exc:
        log.debug("%s failed: %s", action, str(exc))
        raise UnreadableFileError(filename, str(exc))
    except UnreadableFileError:
        # Reraise our errors without changes.
        # Used in case of decorating functions (e.g. by `loadfile`).
        raise
    except Exception as exc:
        # Isolate bugs in Mutagen.
        log.debug("%s", traceback.format_exc())
        log.error("uncaught Mutagen exception in %s: %s", action, exc)
        raise MutagenError(filename, exc)


def loadfile(method=True, writable=False, create=False):
    """A decorator that works like `mutagen._util.loadfile` but with
    additional error handling.

    Opens a file and passes a `mutagen._utils.FileThing` to the
    decorated function. Should be used as a decorator for functions
    using a `filething` parameter.
    """

    def decorator(func):
        f = mutagen._util.loadfile(method, writable, create)(func)

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return mutagen_call("loadfile", "", f, *args, **kwargs)

        return wrapper

    return decorator


def update_filething(filething):
    """Reopen a `filething` if it's a local file.

    A filething that is *not* an actual file is left unchanged; a
    filething with a filename is reopened and a new object is returned.
    """
    if filething.filename:
        return mutagen._util.FileThing(None, filething.filename, filething.name)
    else:
        return filething