Commits

Anonymous committed 51ad18c

Fix for ticket #917, Autoreload gets confused if app performs an os.chdir()

  • Participants
  • Parent commits 57e3818

Comments (0)

Files changed (2)

cherrypy/process/plugins.py

 import time
 import threading
 
+# _module__file__base is used by Autoreload to make
+# absolute any filenames retrieved from sys.modules which are not
+# already absolute paths.  This is to work around Python's quirk
+# of importing the startup script and using a relative filename
+# for it in sys.modules.
+#
+# Autoreload examines sys.modules afresh every time it runs. If an application
+# changes the current directory by executing os.chdir(), then the next time
+# Autoreload runs, it will not be able to find any filenames which are
+# not absolute paths, because the current directory is not the same as when the
+# module was first imported.  Autoreload will then wrongly conclude the file has
+# "changed", and initiate the shutdown/re-exec sequence.
+# See ticket #917.
+# For this workaround to have a decent probability of success, this module
+# needs to be imported as early as possible, before the app has much chance
+# to change the working directory.
+_module__file__base = os.getcwd()
+
 
 class SimplePlugin(object):
     """Plugin base class which auto-subscribes methods for known channels."""
                     f = m.__loader__.archive
                 else:
                     f = getattr(m, '__file__', None)
+                    if f is not None and not os.path.isabs(f):
+                        # ensure absolute paths so a os.chdir() in the app doesn't break me
+                        f = os.path.normpath(os.path.join(_module__file__base, f))
                 files.add(f)
         return files
     

cherrypy/process/wspbus.py

 import warnings
 
 
+# Here I save the value of os.getcwd(), which, if I am imported early enough,
+# will be the directory from which the startup script was run.  This is needed
+# by _do_execv(), to change back to the original directory before execv()ing a
+# new process.  This is a defense against the application having changed the
+# current working directory (which could make sys.executable "not found" if
+# sys.executable is a relative-path, and/or cause other problems).
+_startup_cwd = os.getcwd()
+
 # Use a flag to indicate the state of the bus.
 class _StateEnum(object):
     class State(object):
         args.insert(0, sys.executable)
         if sys.platform == 'win32':
             args = ['"%s"' % arg for arg in args]
-        
+
+        os.chdir(_startup_cwd)
         os.execv(sys.executable, args)
     
     def stop(self):