/
flask_gae_static.py
74 lines (52 loc) · 2.16 KB
/
flask_gae_static.py
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
73
74
"""Flask extension for static files based on Google App Engine app.yaml files.
app.yaml reference docs:
https://cloud.google.com/appengine/docs/standard/python3/config/appref
"""
import logging
from pathlib import Path
import re
from flask import current_app, request, send_file, send_from_directory
from werkzeug.routing import BaseConverter
import yaml
logger = logging.getLogger(__name__)
def init_app(app):
"""Load app.yaml and register a URL rule for each static handler."""
assert app.static_folder is None, 'flask-gae-static requires the Flask app to be constructed with static_folder=None.'
app.url_map.converters['regex'] = RegexConverter
with open(Path(app.root_path) / 'app.yaml', 'r') as f:
config = yaml.safe_load(f)
for route in config.get('handlers', []):
dir = route.get('static_dir')
files = route.get('static_files')
url = route['url']
if not dir and not files:
continue
if dir:
rule = str(Path(url) / '<path:file>')
logger.info(f'Registering {rule} to serve {dir}/*')
app.add_url_rule(rule, endpoint=url, view_func=static_dir(dir))
elif files:
rule = f'/<regex("{url.lstrip("/")}"):_>'
logger.info(f'Registering {rule} to serve {files}')
app.add_url_rule(rule, endpoint=url, view_func=static_file(url, files))
def static_dir(dir):
def wrapped(file):
return send_from_directory(Path(current_app.root_path) / dir, file)
return wrapped
def static_file(url_pattern, files_replacement):
def wrapped(_):
path = (Path(current_app.root_path) /
re.sub(url_pattern, files_replacement, request.path))
return send_file(path) if path.exists() else ('', 404)
return wrapped
class RegexConverter(BaseConverter):
"""Regexp URL route for Werkzeug/Flask.
Based on https://github.com/rhyselsmore/flask-reggie.
Usage: @app.route('/<regex("(abc|def)"):letters>')
Install with:
app = Flask(...)
app.url_map.converters['regex'] = RegexConverter
"""
def __init__(self, url_map, *items):
super(RegexConverter, self).__init__(url_map)
self.regex = items[0]