|
1 | 1 | import logging |
2 | 2 | import os |
| 3 | +from datetime import datetime, timedelta |
3 | 4 | from typing import Dict, List |
4 | 5 |
|
5 | 6 | import aw_datastore |
| 7 | +import flask.json.provider |
6 | 8 | from aw_datastore import Datastore |
7 | 9 | from flask import ( |
8 | 10 | Blueprint, |
|
26 | 28 |
|
27 | 29 |
|
28 | 30 | class AWFlask(Flask): |
29 | | - def __init__(self, name, testing: bool, *args, **kwargs): |
30 | | - self.json_provider_class = rest.CustomJSONProvider |
31 | | - |
32 | | - # Only pretty-print JSON if in testing mode (because of performance) |
| 31 | + def __init__( |
| 32 | + self, |
| 33 | + host: str, |
| 34 | + testing: bool, |
| 35 | + storage_method=None, |
| 36 | + cors_origins=[], |
| 37 | + custom_static=dict(), |
| 38 | + *args, |
| 39 | + **kwargs |
| 40 | + ): |
| 41 | + name = "aw-server" |
| 42 | + self.json_provider_class = CustomJSONProvider |
| 43 | + # only prettyprint JSON if testing (due to perf) |
33 | 44 | self.json_provider_class.compact = not testing |
34 | 45 |
|
35 | 46 | # Initialize Flask |
36 | 47 | Flask.__init__(self, name, *args, **kwargs) |
37 | | - |
38 | | - # Is set on later initialization |
39 | | - self.api: ServerAPI = None # type: ignore |
40 | | - |
41 | | - |
42 | | -def create_app( |
43 | | - host: str, testing=True, storage_method=None, cors_origins=[], custom_static=dict() |
44 | | -) -> AWFlask: |
45 | | - app = AWFlask("aw-server", testing, static_folder=static_folder, static_url_path="") |
46 | | - |
47 | | - with app.app_context(): |
48 | | - _config_cors(cors_origins, testing) |
49 | | - |
50 | | - app.register_blueprint(root) |
51 | | - app.register_blueprint(rest.blueprint) |
52 | | - app.register_blueprint(get_custom_static_blueprint(custom_static)) |
53 | | - |
54 | | - if storage_method is None: |
55 | | - storage_method = aw_datastore.get_storage_methods()["memory"] |
56 | | - db = Datastore(storage_method, testing=testing) |
57 | | - app.api = ServerAPI(db=db, testing=testing) |
58 | | - |
59 | | - # needed for host-header check |
60 | | - app.config["HOST"] = host |
61 | | - |
62 | | - return app |
| 48 | + self.config["HOST"] = host # needed for host-header check |
| 49 | + with self.app_context(): |
| 50 | + _config_cors(cors_origins, testing) |
| 51 | + |
| 52 | + # Initialize datastore and API |
| 53 | + if storage_method is None: |
| 54 | + storage_method = aw_datastore.get_storage_methods()["memory"] |
| 55 | + db = Datastore(storage_method, testing=testing) |
| 56 | + self.api = ServerAPI(db=db, testing=testing) |
| 57 | + |
| 58 | + self.register_blueprint(root) |
| 59 | + self.register_blueprint(rest.blueprint) |
| 60 | + self.register_blueprint(get_custom_static_blueprint(custom_static)) |
| 61 | + |
| 62 | + |
| 63 | +class CustomJSONProvider(flask.json.provider.DefaultJSONProvider): |
| 64 | + # encoding/decoding of datetime as iso8601 strings |
| 65 | + # encoding of timedelta as second floats |
| 66 | + def default(self, obj, *args, **kwargs): |
| 67 | + try: |
| 68 | + if isinstance(obj, datetime): |
| 69 | + return obj.isoformat() |
| 70 | + if isinstance(obj, timedelta): |
| 71 | + return obj.total_seconds() |
| 72 | + except TypeError: |
| 73 | + pass |
| 74 | + return super().default(obj) |
63 | 75 |
|
64 | 76 |
|
65 | 77 | @root.route("/") |
@@ -105,10 +117,10 @@ def _start( |
105 | 117 | cors_origins: List[str] = [], |
106 | 118 | custom_static: Dict[str, str] = dict(), |
107 | 119 | ): |
108 | | - app = create_app( |
| 120 | + app = AWFlask( |
109 | 121 | host, |
110 | | - storage_method=storage_method, |
111 | 122 | testing=testing, |
| 123 | + storage_method=storage_method, |
112 | 124 | cors_origins=cors_origins, |
113 | 125 | custom_static=custom_static, |
114 | 126 | ) |
|
0 commit comments