Skip to content

Instantly share code, notes, and snippets.

@Twilight0
Last active July 4, 2022 13:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Twilight0/7021035f2940eaa2084c9547866cd5a1 to your computer and use it in GitHub Desktop.
Save Twilight0/7021035f2940eaa2084c9547866cd5a1 to your computer and use it in GitHub Desktop.
Hot reload a python working script (compatible with both python 2 & 3)
#!/usr/bin/python
from __future__ import print_function
import sys, os, time, threading, subprocess, fnmatch
class SourceChangeMonitor(threading.Thread):
# Remember the process ID of the subprocess for when
# we want to restart it
_process = None
# How often should we check for changes (in seconds)
POLL_INTERVAL = 1
# Which files should be monitored for changes?
# Here, we deliberately exclude files beginning with a dot (.)
FILE_PATTERN = r"[!.]*.py"
# Which directory is the root of the source files?
ROOT_DIRECTORY = r"/type/script/path/here/"
# Entry point program to run
PROGRAM = r"name_of_script.py"
def __init__(self):
threading.Thread.__init__(self)
self.this_script_name = os.path.abspath(sys.argv[0])
self.files = self.get_files()
self.start_program()
def run(self):
while 1:
time.sleep(self.POLL_INTERVAL)
if self.poll():
print("-------------------------------------------------")
print("Noticed a change in program source. Restarting...")
print("-------------------------------------------------")
self.start_program()
def get_files(self):
"""
Get a list of all files along with their timestamps for last modified
"""
files = []
for root, dirnames, filenames in os.walk(self.ROOT_DIRECTORY):
for filename in fnmatch.filter(filenames, self.FILE_PATTERN):
full_filename = os.path.join(root, filename)
files.append(full_filename)
# Attach the last modified dates
files = map(lambda f: (f, os.stat(f).st_mtime), files)
files = [filename_mtime for filename_mtime in files if filename_mtime[0] != self.this_script_name]
return files
def poll(self):
"""Check if any source files have changed since last poll. Returns True if files have changed, False otherwise"""
new_files = self.get_files()
if self.files != new_files:
self.files = new_files
return True
return False
def start_program(self):
"""Start the program. If it was already started, kill it before restarting"""
if self._process != None and self._process.poll() is None:
self._process.kill()
self._process.wait()
self._process = subprocess.Popen([sys.executable, self.PROGRAM])
if __name__ == "__main__":
SourceChangeMonitor().start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment