import os.path
import contextlib
import hashlib
from flask import Flask
from flask.helpers import safe_join

# Injects an "h" parameter on the URLs of static files that contains a hash of
# the file.  This allows the use of aggressive cache settings on static files,
# while ensuring that content changes are reflected immediately due to the
# changed URLs.  Hashes are cached in-memory and only checked for updates when
# the file modtime changes.
class AddStaticFileHashFlask(Flask):
    def __init__(self, *args, **kwargs):
        super(AddStaticFileHashFlask, self).__init__(*args, **kwargs)
        self._file_hash_cache = {}
    def inject_url_defaults(self, endpoint, values):
        super(AddStaticFileHashFlask, self).inject_url_defaults(endpoint, values)
        if endpoint == "static" and "filename" in values:
            filepath = safe_join(self.static_folder, values["filename"])
            if os.path.isfile(filepath):
                cache = self._file_hash_cache.get(filepath)
                mtime = os.path.getmtime(filepath)
                if cache != None:
                    cached_mtime, cached_hash = cache
                    if cached_mtime == mtime:
                        values["h"] = cached_hash
                        return
                h = hashlib.md5()
                with contextlib.closing(open(filepath, "rb")) as f:
                    h.update(f.read())
                h = h.hexdigest()
                self._file_hash_cache[filepath] = (mtime, h)
                values["h"] = h

app = AddStaticFileHashFlask(__name__)
# ...