_reload_hooks = []
_reload_attempted = False
_io_loops = weakref.WeakKeyDictionary() # type: ignore
+_autoreload_is_main = False
+_original_argv = None
def start(check_time=500):
if spec:
argv = ['-m', spec.name] + sys.argv[1:]
else:
- argv = sys.argv
+ argv = _original_argv if _autoreload_is_main else sys.argv
path_prefix = '.' + os.pathsep
if (sys.path[0] == '' and
not os.environ.get("PYTHONPATH", "").startswith(path_prefix)):
can catch import-time problems like syntax errors that would otherwise
prevent the script from reaching its call to `wait`.
"""
+ # Remember that we were launched with autoreload as main.
+ # The main module can be tricky; set the variables both in our globals
+ # (which may be __main__) and the real importable version.
+ import tornado.autoreload
+ global _autoreload_is_main
+ global _original_argv
+ tornado.autoreload._autoreload_is_main = _autoreload_is_main = True
original_argv = sys.argv
+ tornado.autoreload._original_argv = _original_argv = original_argv
sys.argv = sys.argv[:]
if len(sys.argv) >= 3 and sys.argv[1] == "-m":
mode = "module"
if __name__ == "__main__":
# See also the other __main__ block at the top of the file, which modifies
# sys.path before our imports
- main()
+ # Ensure that any global variables accessed by main() are in the module namespace
+ # instead of the __main__ namespace
+ import tornado.autoreload
+ tornado.autoreload.main()
+
from tempfile import mkdtemp
from tornado.test.util import unittest
+import tornado.autoreload
-MAIN = """\
+class AutoreloadTest(unittest.TestCase):
+
+ def test_reload_module(self):
+ main = """\
import os
import sys
autoreload._reload()
"""
-
-class AutoreloadTest(unittest.TestCase):
- def test_reload_module(self):
# Create temporary test application
path = mkdtemp()
os.mkdir(os.path.join(path, 'testapp'))
open(os.path.join(path, 'testapp/__init__.py'), 'w').close()
with open(os.path.join(path, 'testapp/__main__.py'), 'w') as f:
- f.write(MAIN)
+ f.write(main)
# Make sure the tornado module under test is available to the test
# application
universal_newlines=True)
out = p.communicate()[0]
self.assertEqual(out, 'Starting\nStarting\n')
+
+ def test_reload_module_with_argv_preservation(self):
+ main = """\
+import os
+import sys
+from tornado import autoreload
+
+# This import will fail if path is not set up correctly
+import testapp
+
+print(autoreload._original_argv)
+sys.stdout.flush()
+if 'TESTAPP_STARTED' not in os.environ:
+ os.environ['TESTAPP_STARTED'] = '1'
+else:
+ # Force the autoreload to exit
+ autoreload.add_reload_hook(lambda: os._exit(0))
+ autoreload._reload()
+"""
+
+ touch = """\
+import os
+import time
+import sys
+import stat
+for i in range(50):
+ time.sleep(0.1)
+
+ # Update the access time and modification time of file
+ st = os.stat(sys.argv[1])
+ os.utime(sys.argv[1], (st[stat.ST_ATIME] + i, st[stat.ST_MTIME] + i))
+ """
+
+ # Create temporary test application
+ path = mkdtemp()
+ os.mkdir(os.path.join(path, 'testapp'))
+ open(os.path.join(path, 'testapp/__init__.py'), 'w').close()
+ with open(os.path.join(path, 'testapp/__main__.py'), 'w') as f:
+ f.write(main)
+ with open(os.path.join(path, 'testapp/touch.py'), 'w') as f:
+ f.write(touch)
+
+ # Make sure the tornado module under test is available to the test
+ # application
+ pythonpath = os.getcwd()
+ if 'PYTHONPATH' in os.environ:
+ pythonpath += os.pathsep + os.environ['PYTHONPATH']
+
+ autoreload_proc = Popen(
+ [sys.executable, '-m', 'tornado.autoreload', '-m', 'testapp'],
+ stdout=subprocess.PIPE, cwd=path,
+ env=dict(os.environ, PYTHONPATH=pythonpath),
+ universal_newlines=True)
+ touch_proc = Popen(
+ [sys.executable, os.path.join(path, 'testapp/touch.py'),
+ os.path.join(path, 'testapp/__init__.py')]
+ , stdout=subprocess.PIPE, cwd=path,
+ env=dict(os.environ, PYTHONPATH=pythonpath),
+ universal_newlines=True)
+
+ # Once the autoreload process is done, we kill the touching process
+ autoreload_proc.wait()
+ touch_proc.kill()
+
+ out = autoreload_proc.communicate()[0]
+ autoreload_module = os.path.join(os.path.dirname(os.path.abspath(
+ tornado.autoreload.__file__)), 'autoreload.py')
+ self.assertEqual(out, (str([autoreload_module, '-m', 'testapp']) + '\n') * 2)