import re


def extract_infos(filename, patterns=None, transformers=None):
    """
    patterns:       A dict of the form {key: pattern}. A collection of
                    regular expressions to extract information from the
                    filename: {key: re.match(pattern, filename)}
    transformers:   A dict of the form {key: trafo}. A collection of
                    transformers with signature trafo(ret), where ret is
                    the object returned by re.match(). The default
                    transformer for pattern is to return the first
                    capture group:
                        def trafo(ret): return ret.group(1)

    The info will be returned as a dict {key: info}

    Example:
        extract_initials = lambda ret: (ret.group(1)+ret.group(2)).upper()
        infos = extract_infos("walt_disney",
                              patterns={"surname": ".*_(.*)",
                                        "initials": "(.).*_(.).*"},
                              transformers={"initials": extract_initials})
        # infos = {'surname': 'disney', 'initials': 'WD'}
    """
    infos = {}
    if patterns is None:
        patterns = {}
    if transformers is None:
        transformers = {}
    def default_trafo(ret): return ret.group(1)
    for key, pattern in patterns.items():
        ret = re.match(pattern, filename)
        msg = "File pattern does not match filename: %s (%s)"
        assert ret is not None, (msg % (pattern, key))
        infos[key] = ret
        transformers.setdefault(key, default_trafo)
    msg = ("Can only transform information that was previously extracted. "
           "No pattern specified for trafo key '%s'")
    for key, trafo in transformers.items():
        assert key in patterns, msg % key
        infos[key] = trafo(infos[key])
    return infos