From 2e6e66e50abc615ea96edd7aa93ef6368a18e689 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Mon, 19 Mar 2012 12:53:10 -0400 Subject: [PATCH] Some more work on `pecan serve --reload`. Now the app and config directories are monitored (instead of cwd()). --- pecan/commands/serve.py | 52 ++++++++++++++++++++++++++++++----------- pecan/configuration.py | 6 +++-- pecan/core.py | 2 +- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/pecan/commands/serve.py b/pecan/commands/serve.py index 3bd55f4..13b45a1 100644 --- a/pecan/commands/serve.py +++ b/pecan/commands/serve.py @@ -38,9 +38,12 @@ class ServeCommand(BaseCommand): stdout=sys.stdout, stderr=sys.stderr ) - def watch_and_spawn(self): + def watch_and_spawn(self, conf): from watchdog.observers import Observer - from watchdog.events import FileSystemEventHandler + from watchdog.events import ( + FileSystemEventHandler, FileSystemMovedEvent, FileModifiedEvent, + DirModifiedEvent + ) print 'Monitoring for changes...' self.create_subprocess() @@ -48,24 +51,31 @@ class ServeCommand(BaseCommand): parent = self class AggressiveEventHandler(FileSystemEventHandler): - def should_reload(self, path): - extension = os.path.splitext(path)[1] - if extension in ( - '.py', '.pyc', '.html', '.mak', - '.mako', '.xml' + def should_reload(self, event): + for t in ( + FileSystemMovedEvent, FileModifiedEvent, DirModifiedEvent ): - return True + if isinstance(event, t): + return True return False def on_modified(self, event): - if self.should_reload(getattr(event, 'src_path', '')): + if self.should_reload(event): parent.server_process.kill() parent.create_subprocess() + # Determine a list of file paths to monitor + paths = self.paths_to_monitor(conf) + event_handler = AggressiveEventHandler() - observer = Observer() - observer.schedule(event_handler, path=os.getcwd(), recursive=True) - observer.start() + for path, recurse in paths: + observer = Observer() + observer.schedule( + event_handler, + path=path, + recursive=recurse + ) + observer.start() try: while True: @@ -73,6 +83,22 @@ class ServeCommand(BaseCommand): except KeyboardInterrupt: pass + def paths_to_monitor(self, conf): + paths = [] + + for package_name in getattr(conf.app, 'modules', []): + module = __import__(package_name, fromlist=['app']) + if hasattr(module, 'app') and hasattr(module.app, 'setup_app'): + paths.append(( + os.path.dirname(module.__file__), + True + )) + break + + paths.append((os.path.dirname(conf.__file__), False)) + return paths + + def _serve(self, app, conf): from wsgiref.simple_server import make_server @@ -100,7 +126,7 @@ class ServeCommand(BaseCommand): if self.args.reload: try: - self.watch_and_spawn() + self.watch_and_spawn(conf) except ImportError: print('The `--reload` option requires `watchdog` to be ' 'installed.') diff --git a/pecan/configuration.py b/pecan/configuration.py index a903ac8..bef11c7 100644 --- a/pecan/configuration.py +++ b/pecan/configuration.py @@ -161,7 +161,6 @@ def conf_from_dict(conf_dict): :param conf_dict: The configuration dictionary. ''' - conf = Config(filename=conf_dict.get('__file__', '')) for k, v in conf_dict.iteritems(): @@ -195,7 +194,10 @@ def set_config(config, overwrite=False): _runtime_conf.empty() if isinstance(config, basestring): - _runtime_conf.update(conf_from_file(config)) + config = conf_from_file(config) + _runtime_conf.update(config) + if config.__file__: + _runtime_conf.__file__ = config.__file__ elif isinstance(config, dict): _runtime_conf.update(conf_from_dict(config)) else: diff --git a/pecan/core.py b/pecan/core.py index fc71081..d104c55 100644 --- a/pecan/core.py +++ b/pecan/core.py @@ -1,4 +1,3 @@ -from configuration import _runtime_conf, set_config from templating import RendererFactory from routing import lookup_controller, NonCanonicalPath from util import _cfg, encode_if_needed @@ -141,6 +140,7 @@ def load_app(config): which represents a (relative) configuration filename. :returns a pecan.Pecan object ''' + from configuration import _runtime_conf, set_config set_config(config, overwrite=True) for package_name in getattr(_runtime_conf.app, 'modules', []):