diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2015-08-05 11:07:36 +0200 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2015-08-29 20:49:56 +0200 |
| commit | fe6ddb837d18bd4e71cd22fc18272d31478b19f2 (patch) | |
| tree | 0604cc42c1e38b522a301194abb6c806bd248aa6 /django/utils/autoreload.py | |
| parent | c2fcba2ac76cdaed5ccf07ae0521a78feb598825 (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.py | 13 |
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 |
