From c2a6b2a43fb8f32cff078c823054e2e65f325464 Mon Sep 17 00:00:00 2001 From: Ramiro Morales Date: Wed, 12 Dec 2012 00:33:03 -0300 Subject: [PATCH] Fixed #9589 -- Made development web server more robust in the presence of a wider variety of code errors. Thanks goes to contributor with Trac user 'berto' for the patch. --- AUTHORS | 1 + django/utils/autoreload.py | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6496005082..0f793cc5f4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -91,6 +91,7 @@ answer newbie questions, and generally made Django that much better: James Bennett Danilo Bargen Shai Berger + berto Julian Bez Arvis Bickovskis Natalia Bidart diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py index 2daafedd85..f600f0611c 100644 --- a/django/utils/autoreload.py +++ b/django/utils/autoreload.py @@ -28,7 +28,7 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import os, sys, time, signal +import os, sys, time, signal, traceback try: from django.utils.six.moves import _thread as thread @@ -52,10 +52,12 @@ RUN_RELOADER = True _mtimes = {} _win = (sys.platform == "win32") +_error_files = [] + def code_changed(): global _mtimes, _win filenames = [getattr(m, "__file__", None) for m in sys.modules.values()] - for filename in filter(None, filenames): + for filename in filter(None, filenames) + _error_files: if filename.endswith(".pyc") or filename.endswith(".pyo"): filename = filename[:-1] if filename.endswith("$py.class"): @@ -71,9 +73,34 @@ def code_changed(): continue if mtime != _mtimes[filename]: _mtimes = {} + try: + del _error_files[_error_files.index(filename)] + except ValueError: + pass return True return False +def check_errors(fn): + def wrapper(*args, **kwargs): + try: + fn(*args, **kwargs) + except (ImportError, IndentationError, NameError, SyntaxError, + TypeError, AttributeError): + et, ev, tb = sys.exc_info() + + if getattr(ev, 'filename', None) is None: + # get the filename from the last item in the stack + filename = traceback.extract_tb(tb)[-1][0] + else: + filename = ev.filename + + if filename not in _error_files: + _error_files.append(filename) + + raise + + return wrapper + def ensure_echo_on(): if termios: fd = sys.stdin @@ -142,5 +169,7 @@ def main(main_func, args=None, kwargs=None): reloader = jython_reloader else: reloader = python_reloader - reloader(main_func, args, kwargs) + + wrapped_main_func = check_errors(main_func) + reloader(wrapped_main_func, args, kwargs)