Skip to content

Instantly share code, notes, and snippets.

@eberle1080
Created June 7, 2011 20:50
Show Gist options
  • Save eberle1080/1013122 to your computer and use it in GitHub Desktop.
Save eberle1080/1013122 to your computer and use it in GitHub Desktop.
Automatically reload python module / package on file change
#!/usr/bin/env python
# Author: Chris Eberle <eberle1080@gmail.com>
# Watch for any changes in a module or package, and reload it automatically
import pyinotify
import imp
import os
class ModuleWatcher(pyinotify.ProcessEvent):
"""
Automatically reload any modules or packages as they change
"""
def __init__(self):
"El constructor"
self.wm = pyinotify.WatchManager()
self.notifier = None
self.mod_map = {}
def _watch_file(self, file_name, module):
"Add a watch for a specific file, and map said file to a module name"
file_name = os.path.realpath(file_name)
self.mod_map[file_name] = module
self.wm.add_watch(file_name, pyinotify.EventsCodes.IN_MODIFY)
#print 'Watching', file_name
def watch_module(self, name):
"Load a module, determine which files it uses, and watch them"
if imp.is_builtin(name) != 0:
# Pretty pointless to watch built-in modules
return
(fd, pathname, description) = imp.find_module(name)
try:
mod = imp.load_module(name, fd, pathname, description)
if fd:
self._watch_file(fd.name, name)
else:
for root, dirs, files in os.walk(pathname):
for filename in files:
fpath = os.path.join(root, filename)
if fpath.endswith('.py'):
self._watch_file(fpath, name)
finally:
if fd:
fd.close()
def start_watching(self):
"Start the pyinotify watch thread"
if self.notifier is None:
self.notifier = pyinotify.ThreadedNotifier(self.wm, self)
self.notifier.start()
def stop_watching(self):
"Stop the pyinotify watch thread"
if self.notifier is not None:
self.notifier.stop()
def process_IN_MODIFY(self, event):
"A file of interest has changed"
# Is it a file I know about?
if event.path not in self.mod_map:
return
# Find out which module is using that file
modname = self.mod_map[event.path]
# Reload the module
(fd, pathname, description) = imp.find_module(modname)
try:
imp.load_module(modname, fd, pathname, description)
finally:
if fd:
fd.close()
#print 'Reload', modname
if __name__ == '__main__':
# Test everything
import sys
mw = ModuleWatcher()
mw.watch_module('module1')
mw.watch_module('module2')
mw.start_watching()
try:
raw_input('Press ENTER to exit')
finally:
mw.stop_watching()
sys.exit(0)
@eberle1080
Copy link
Author

@Kostanos
Copy link

Hi, can you show examples of using?

@BigBorg
Copy link

BigBorg commented Jun 29, 2017

Cool. But I wonder is there any way to import not just module but everything inside like " from file reload * " ? That would be way nicer to use.

@allan-avatar1
Copy link

@BigBorg If your code says "from module1 import *" ... then the way to reload it is later on is: "import module1; reload(module1); from module import *" ... perhaps you could do that inside of an exec("") call but I havent tested that before

@mparusinski
Copy link

Interesting code, however this has no license. I am no lawyer, but I believe this means no one can use it without your explicit permission. Is this intentional, or are you considering open sourcing this?

@datdinhquoc
Copy link

does it work when the module is a class, and many instances of that class have already been created?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment