diff --git a/.travis.yml b/.travis.yml index 5ff1d0035..60ad4719e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ install: # core dependencies - if [[ $RUN == nosetests ]]; then pip install pygments requests; fi # curtsies specific dependencies - - if [[ $RUN == nosetests ]]; then pip install 'curtsies >=0.1.15,<0.2.0' greenlet; fi + - if [[ $RUN == nosetests ]]; then pip install 'curtsies >=0.1.15,<0.2.0' greenlet watchdog; fi # translation specific dependencies - if [[ $RUN == nosetests ]]; then pip install babel; fi # documentation specific dependencies diff --git a/bpython/curtsiesfrontend/filewatch.py b/bpython/curtsiesfrontend/filewatch.py index 57955cbc5..6529f2e1b 100644 --- a/bpython/curtsiesfrontend/filewatch.py +++ b/bpython/curtsiesfrontend/filewatch.py @@ -19,8 +19,9 @@ def __init__(self, paths, on_change): self.observer = Observer() self.old_dirs = defaultdict(set) self.started = False + self.activated = False for path in paths: - self.add_module(path) + self._add_module(path) def reset(self): self.dirs = defaultdict(set) @@ -28,8 +29,10 @@ def reset(self): self.old_dirs = defaultdict(set) self.observer.unschedule_all() - def add_module(self, path): - """Add a python module to track changes to""" + def _add_module(self, path): + """Add a python module to track changes to + + Can""" path = os.path.abspath(path) for suff in importcompletion.SUFFIXES: if path.endswith(suff): @@ -40,24 +43,36 @@ def add_module(self, path): self.observer.schedule(self, dirname, recursive=False) self.dirs[os.path.dirname(path)].add(path) - def add_module_later(self, path): + def _add_module_later(self, path): self.modules_to_add_later.append(path) + + def track_module(self, path): + """ + Begins tracking this if activated, or remembers to track later. + """ + if self.activated: + self._add_module(path) + else: + self._add_module_later(path) def activate(self): + if self.activated: + raise ValueError("%r is already activated." % (self,)) if not self.started: self.started = True self.observer.start() - self.dirs = self.old_dirs for dirname in self.dirs: self.observer.schedule(self, dirname, recursive=False) for module in self.modules_to_add_later: - self.add_module(module) + self._add_module(module) del self.modules_to_add_later[:] + self.activated = True def deactivate(self): + if not self.activated: + raise ValueError("%r is not activated." % (self,)) self.observer.unschedule_all() - self.old_dirs = self.dirs - self.dirs = defaultdict(set) + self.activated = False def on_any_event(self, event): dirpath = os.path.dirname(event.src_path) @@ -66,12 +81,5 @@ def on_any_event(self, event): self.on_change(files_modified=[event.src_path]) if __name__ == '__main__': - m = ModuleChangedEventHandler([]) - m.add_module('./wdtest.py') - try: - while True: - time.sleep(1) - except KeyboardInterrupt: - m.observer.stop() - m.observer.join() + pass diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 1d2b71fdc..3dd9fb0ad 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -366,18 +366,12 @@ def new_import(name, globals={}, locals={}, fromlist=[], level=-1): except: if name in old_module_locations: loc = old_module_locations[name] - if self.watching_files: - self.watcher.add_module(loc) - else: - self.watcher.add_module_later(loc) + self.watcher.track_module(loc) raise else: if hasattr(m, "__file__"): old_module_locations[name] = m.__file__ - if self.watching_files: - self.watcher.add_module(m.__file__) - else: - self.watcher.add_module_later(m.__file__) + self.watcher.track_module(m.__file__) return m __builtins__['__import__'] = new_import diff --git a/bpython/test/test_filewatch.py b/bpython/test/test_filewatch.py new file mode 100644 index 000000000..242a5a153 --- /dev/null +++ b/bpython/test/test_filewatch.py @@ -0,0 +1,30 @@ +import mock +import os + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from bpython.curtsiesfrontend.filewatch import ModuleChangedEventHandler + +class TestModuleChangeEventHandler(unittest.TestCase): + + def setUp(self): + self.module = ModuleChangedEventHandler([], 1) + self.module.observer = mock.Mock() + + def test_create_module_handler(self): + self.assertIsInstance(self.module, ModuleChangedEventHandler) + + def test_add_module(self): + self.module._add_module('something/test.py') + self.assertIn(os.path.abspath('something/test'), + self.module.dirs[os.path.abspath('something')]) + + def test_activate_throws_error_when_already_activated(self): + self.module.activated = True + with self.assertRaises(ValueError): + self.module.activate() + + \ No newline at end of file