diff options
| author | Steve Piercy <web@stevepiercy.com> | 2015-11-14 02:44:27 -0800 |
|---|---|---|
| committer | Steve Piercy <web@stevepiercy.com> | 2015-11-14 02:44:27 -0800 |
| commit | 0d403e8236cc9c1c5dc8d79f1131f95363189495 (patch) | |
| tree | b11bf63e1f4eecf14354b6386c77a970fe8c75a5 | |
| parent | 63163f7bd71fba313bdab162201cb00a8dcc7c9b (diff) | |
| parent | 031b5b69f4ae3e2187e3b9f1f7e582d71fac45b1 (diff) | |
| download | pyramid-0d403e8236cc9c1c5dc8d79f1131f95363189495.tar.gz pyramid-0d403e8236cc9c1c5dc8d79f1131f95363189495.tar.bz2 pyramid-0d403e8236cc9c1c5dc8d79f1131f95363189495.zip | |
Merge remote-tracking branch 'upstream/master'
| -rw-r--r-- | CHANGES.txt | 3 | ||||
| -rw-r--r-- | pyramid/scripts/pserve.py | 61 |
2 files changed, 57 insertions, 7 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 739eb870d..9ff26420b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -155,6 +155,9 @@ Features docstrings instead of the default ``str(obj)`` when possible. See https://github.com/Pylons/pyramid/pull/1929 +- ``pserve --reload`` will no longer crash on syntax errors!!! + See https://github.com/Pylons/pyramid/pull/2044 + Bug Fixes --------- diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py index 01d6383d6..efad0cc68 100644 --- a/pyramid/scripts/pserve.py +++ b/pyramid/scripts/pserve.py @@ -14,9 +14,11 @@ import errno import logging import optparse import os +import py_compile import re import subprocess import sys +import tempfile import textwrap import threading import time @@ -227,7 +229,10 @@ class PServeCommand(object): cmd = None if self.options.reload: - if self.options.daemon or cmd in ('start', 'stop', 'restart'): + if ( + getattr(self.options, 'daemon', False) or + cmd in ('start', 'stop', 'restart') + ): self.out( 'Error: Cannot use reloading while running as a dameon.') return 2 @@ -843,7 +848,7 @@ class Monitor(object): # pragma: no cover if %errorlevel% == 3 goto repeat or run a monitoring process in Python (``pserve --reload`` does - this). + this). Use the ``watch_file(filename)`` function to cause a reload/restart for other non-Python files (e.g., configuration files). If you have @@ -866,9 +871,19 @@ class Monitor(object): # pragma: no cover self.poll_interval = poll_interval self.extra_files = list(self.global_extra_files) self.instances.append(self) + self.syntax_error_files = set() + self.pending_reload = False self.file_callbacks = list(self.global_file_callbacks) + temp_pyc_fp = tempfile.NamedTemporaryFile(delete=False) + self.temp_pyc = temp_pyc_fp.name + temp_pyc_fp.close() def _exit(self): + try: + os.unlink(self.temp_pyc) + except IOError: + # not worried if the tempfile can't be removed + pass # use os._exit() here and not sys.exit() since within a # thread sys.exit() just closes the given thread and # won't kill the process; note os._exit does not call @@ -899,6 +914,7 @@ class Monitor(object): # pragma: no cover continue if filename is not None: filenames.append(filename) + new_changes = False for filename in filenames: try: stat = os.stat(filename) @@ -910,11 +926,42 @@ class Monitor(object): # pragma: no cover continue if filename.endswith('.pyc') and os.path.exists(filename[:-1]): mtime = max(os.stat(filename[:-1]).st_mtime, mtime) - if filename not in self.module_mtimes: - self.module_mtimes[filename] = mtime - elif self.module_mtimes[filename] < mtime: - print("%s changed; reloading..." % filename) - return False + pyc = True + else: + pyc = False + old_mtime = self.module_mtimes.get(filename) + self.module_mtimes[filename] = mtime + if old_mtime is not None and old_mtime < mtime: + new_changes = True + if pyc: + filename = filename[:-1] + is_valid = True + if filename.endswith('.py'): + is_valid = self.check_syntax(filename) + if is_valid: + print("%s changed ..." % filename) + if new_changes: + self.pending_reload = True + if self.syntax_error_files: + for filename in sorted(self.syntax_error_files): + print("%s has a SyntaxError; NOT reloading." % filename) + if self.pending_reload and not self.syntax_error_files: + self.pending_reload = False + return False + return True + + def check_syntax(self, filename): + # check if a file has syntax errors. + # If so, track it until it's fixed. + try: + py_compile.compile(filename, cfile=self.temp_pyc, doraise=True) + except py_compile.PyCompileError as ex: + print(ex.msg) + self.syntax_error_files.add(filename) + return False + else: + if filename in self.syntax_error_files: + self.syntax_error_files.remove(filename) return True def watch_file(self, cls, filename): |
