Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 21f528f

Browse files
author
Kareem Zidane
committedOct 31, 2019
lazily importing flask
1 parent 72a1706 commit 21f528f

File tree

3 files changed

+73
-78
lines changed

3 files changed

+73
-78
lines changed
 

‎src/cs50/__init__.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
1+
import logging
12
import os
23
import sys
34

4-
try:
5-
6-
# Save student's sys.path
7-
_path = sys.path[:]
85

9-
# In case student has files that shadow packages
10-
sys.path = [p for p in sys.path if p not in ("", os.getcwd())]
6+
# Disable cs50 logger by default
7+
logging.getLogger("cs50").disabled = True
118

12-
# Import cs50_*
13-
from .cs50 import get_char, get_float, get_int, get_string
9+
# In case student has files that shadow packages
10+
for p in ("", os.getcwd()):
1411
try:
15-
from .cs50 import get_long
16-
except ImportError:
12+
sys.path.remove(p)
13+
except ValueError:
1714
pass
1815

19-
# Replace Flask's logger
20-
from . import flask
21-
22-
# Wrap SQLAlchemy
23-
from .sql import SQL
16+
# Import cs50_*
17+
from .cs50 import get_char, get_float, get_int, get_string
18+
try:
19+
from .cs50 import get_long
20+
except ImportError:
21+
pass
2422

25-
finally:
23+
# Hook into flask importing
24+
from . import flask
2625

27-
# Restore student's sys.path (just in case library raised an exception that caller caught)
28-
sys.path = _path
26+
# Wrap SQLAlchemy
27+
from .sql import SQL

‎src/cs50/flask.py

Lines changed: 36 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,36 @@
1-
import logging
2-
3-
from distutils.version import StrictVersion
4-
from pkg_resources import get_distribution
5-
6-
from .cs50 import _formatException
7-
8-
# Try to monkey-patch Flask, if installed
9-
try:
10-
11-
# Only patch >= 1.0
12-
_version = StrictVersion(get_distribution("flask").version)
13-
assert _version >= StrictVersion("1.0")
14-
15-
# Reformat logger's exceptions
16-
# http://flask.pocoo.org/docs/1.0/logging/
17-
# https://docs.python.org/3/library/logging.html#logging.Formatter.formatException
18-
try:
19-
import flask.logging
20-
flask.logging.default_handler.formatter.formatException = lambda exc_info: _formatException(*exc_info)
21-
except Exception:
22-
pass
23-
24-
# Enable logging when Flask is in use,
25-
# monkey-patching own SQL module, which shouldn't need to know about Flask
26-
logging.getLogger("cs50").disabled = True
27-
try:
28-
import flask
29-
from .sql import SQL
30-
except ImportError:
31-
pass
32-
else:
33-
_execute_before = SQL.execute
34-
def _execute_after(*args, **kwargs):
35-
disabled = logging.getLogger("cs50").disabled
36-
if flask.current_app:
37-
logging.getLogger("cs50").disabled = False
38-
try:
39-
return _execute_before(*args, **kwargs)
40-
finally:
41-
logging.getLogger("cs50").disabled = disabled
42-
SQL.execute = _execute_after
43-
44-
# When behind CS50 IDE's proxy, ensure that flask.redirect doesn't redirect from HTTPS to HTTP
45-
# https://werkzeug.palletsprojects.com/en/0.15.x/middleware/proxy_fix/#module-werkzeug.middleware.proxy_fix
46-
from os import getenv
47-
if getenv("CS50_IDE_TYPE") == "online":
48-
try:
49-
import flask
50-
from werkzeug.middleware.proxy_fix import ProxyFix
51-
_flask_init_before = flask.Flask.__init__
52-
def _flask_init_after(self, *args, **kwargs):
53-
_flask_init_before(self, *args, **kwargs)
54-
self.wsgi_app = ProxyFix(self.wsgi_app, x_proto=1)
55-
flask.Flask.__init__ = _flask_init_after
56-
except:
57-
pass
58-
59-
except Exception:
60-
pass
1+
import os
2+
import pkgutil
3+
import sys
4+
5+
def _wrap_flask(f):
6+
from distutils.version import StrictVersion
7+
8+
if f.__version__ < StrictVersion("1.0"):
9+
return
10+
11+
from .cs50 import _formatException
12+
f.logging.default_handler.formatter.formatException = lambda exc_info: _formatException(*exc_info)
13+
14+
if os.getenv("CS50_IDE_TYPE") == "online":
15+
from werkzeug.middleware.proxy_fix import ProxyFix
16+
_flask_init_before = f.Flask.__init__
17+
def _flask_init_after(self, *args, **kwargs):
18+
_flask_init_before(self, *args, **kwargs)
19+
self.wsgi_app = ProxyFix(self.wsgi_app, x_proto=1)
20+
f.Flask.__init__ = _flask_init_after
21+
22+
23+
# Flask was imported before cs50
24+
if "flask" in sys.modules:
25+
_wrap_flask(sys.modules["flask"])
26+
27+
# Flask wasn't imported
28+
else:
29+
flask_loader = pkgutil.get_loader('flask')
30+
_exec_module_before = flask_loader.exec_module
31+
32+
def _exec_module_after(*args, **kwargs):
33+
_exec_module_before(*args, **kwargs)
34+
_wrap_flask(sys.modules["flask"])
35+
36+
flask_loader.exec_module = _exec_module_after

‎src/cs50/sql.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
def _enable_logging(f):
2+
import logging
3+
import functools
4+
5+
@functools.wraps(f)
6+
def decorator(*args, **kwargs):
7+
import flask
8+
9+
disabled = logging.getLogger("cs50").disabled
10+
if flask.current_app:
11+
logging.getLogger("cs50").disabled = False
12+
try:
13+
return f(*args, **kwargs)
14+
finally:
15+
logging.getLogger("cs50").disabled = disabled
16+
17+
return decorator
18+
19+
120
class SQL(object):
221
"""Wrap SQLAlchemy to provide a simple SQL API."""
322

@@ -64,6 +83,7 @@ def connect(dbapi_connection, connection_record):
6483
finally:
6584
self._logger.disabled = disabled
6685

86+
@_enable_logging
6787
def execute(self, sql, *args, **kwargs):
6888
"""Execute a SQL statement."""
6989

0 commit comments

Comments
 (0)
Please sign in to comment.