summaryrefslogtreecommitdiff
path: root/django/utils/autoreload.py
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2015-08-05 11:07:36 +0200
committerAymeric Augustin <aymeric.augustin@m4x.org>2015-08-29 20:49:56 +0200
commitfe6ddb837d18bd4e71cd22fc18272d31478b19f2 (patch)
tree0604cc42c1e38b522a301194abb6c806bd248aa6 /django/utils/autoreload.py
parentc2fcba2ac76cdaed5ccf07ae0521a78feb598825 (diff)
Fixed #24704 -- Made the autoreloader survive SyntaxErrors.
With this change, it's expected to survive anything except errors that make it impossible to import the settings. It's too complex to fallback to a sensible behavior with a broken settings module. Harcoding things about runserver in ManagementUtility.execute is atrocious but it's the only way out of the chicken'n'egg problem: the current implementation of the autoreloader primarily watches imported Python modules -- and then a few other things that were bolted on top of this design -- but we want it to kick in even if the project contains import-time errors and django.setup() fails. At some point we should throw away this code and replace it by an off-the-shelf autoreloader that watches the working directory and re-runs `django-admin runserver` whenever something changes.
Diffstat (limited to 'django/utils/autoreload.py')
-rw-r--r--django/utils/autoreload.py13
1 files changed, 12 insertions, 1 deletions
diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py
index c4b12241f0..0cf00a9646 100644
--- a/django/utils/autoreload.py
+++ b/django/utils/autoreload.py
@@ -37,6 +37,7 @@ import traceback
from django.apps import apps
from django.conf import settings
from django.core.signals import request_finished
+from django.utils import six
from django.utils._os import npath
from django.utils.six.moves import _thread as thread
@@ -72,6 +73,7 @@ I18N_MODIFIED = 2
_mtimes = {}
_win = (sys.platform == "win32")
+_exception = None
_error_files = []
_cached_modules = set()
_cached_filenames = []
@@ -219,11 +221,14 @@ def code_changed():
def check_errors(fn):
def wrapper(*args, **kwargs):
+ global _exception
try:
fn(*args, **kwargs)
except (ImportError, IndentationError, NameError, SyntaxError,
TypeError, AttributeError):
- et, ev, tb = sys.exc_info()
+ _exception = sys.exc_info()
+
+ et, ev, tb = _exception
if getattr(ev, 'filename', None) is None:
# get the filename from the last item in the stack
@@ -239,6 +244,12 @@ def check_errors(fn):
return wrapper
+def raise_last_exception():
+ global _exception
+ if _exception is not None:
+ six.reraise(*_exception)
+
+
def ensure_echo_on():
if termios:
fd = sys.stdin