PageRenderTime 43ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/silverlining/paste-reloader.py

https://bitbucket.org/ianb/silverlining/
Python | 133 lines | 123 code | 0 blank | 10 comment | 1 complexity | 49574b54c92ef9b43ab3eb0abc986fc5 MD5 | raw file
Possible License(s): GPL-2.0
  1. # Copied from paste.reloader:
  2. """
  3. Use this like::
  4. import reloader
  5. reloader.install()
  6. Then make sure your server is installed with a shell script like::
  7. err=3
  8. while test "$err" -eq 3 ; do
  9. python server.py
  10. err="$?"
  11. done
  12. or restart in Python (server.py does this). Use the watch_file(filename)
  13. function to cause a reload/restart for other other non-Python files (e.g.,
  14. configuration files).
  15. """
  16. import os
  17. import sys
  18. import time
  19. import threading
  20. import atexit
  21. # Copied from paste.util.classinstance:
  22. class classinstancemethod(object):
  23. """
  24. Acts like a class method when called from a class, like an
  25. instance method when called by an instance. The method should
  26. take two arguments, 'self' and 'cls'; one of these will be None
  27. depending on how the method was called.
  28. """
  29. def __init__(self, func):
  30. self.func = func
  31. def __get__(self, obj, type=None):
  32. return _methodwrapper(self.func, obj=obj, type=type)
  33. class _methodwrapper(object):
  34. def __init__(self, func, obj, type):
  35. self.func = func
  36. self.obj = obj
  37. self.type = type
  38. def __call__(self, *args, **kw):
  39. assert not kw.has_key('self') and not kw.has_key('cls'), (
  40. "You cannot use 'self' or 'cls' arguments to a "
  41. "classinstancemethod")
  42. return self.func(*((self.obj, self.type) + args), **kw)
  43. def __repr__(self):
  44. if self.obj is None:
  45. return ('<bound class method %s.%s>'
  46. % (self.type.__name__, self.func.func_name))
  47. else:
  48. return ('<bound method %s.%s of %r>'
  49. % (self.type.__name__, self.func.func_name, self.obj))
  50. def install(poll_interval=1, raise_keyboard_interrupt=True):
  51. mon = Monitor(poll_interval=poll_interval,
  52. raise_keyboard_interrupt=raise_keyboard_interrupt)
  53. t = threading.Thread(target=mon.periodic_reload)
  54. t.start()
  55. class Monitor:
  56. instances = []
  57. global_extra_files = []
  58. def __init__(self, poll_interval, raise_keyboard_interrupt):
  59. self.module_mtimes = {}
  60. atexit.register(self.atexit)
  61. self.keep_running = True
  62. self.poll_interval = poll_interval
  63. self.raise_keyboard_interrupt = raise_keyboard_interrupt
  64. self.extra_files = self.global_extra_files[:]
  65. self.instances.append(self)
  66. def atexit(self):
  67. self.keep_running = False
  68. if self.raise_keyboard_interrupt:
  69. # This exception is somehow magic, because it applies
  70. # to more threads and situations (like socket.accept)
  71. # that a mere SystemExit will not.
  72. raise KeyboardInterrupt("Exiting process")
  73. def periodic_reload(self):
  74. while 1:
  75. if not self.keep_running:
  76. break
  77. if not self.check_reload():
  78. os._exit(3)
  79. break
  80. time.sleep(self.poll_interval)
  81. def check_reload(self):
  82. filenames = self.extra_files[:]
  83. for module in sys.modules.values():
  84. try:
  85. filenames.append(module.__file__)
  86. except AttributeError:
  87. continue
  88. for filename in filenames:
  89. try:
  90. mtime = os.stat(filename).st_mtime
  91. except (OSError, IOError):
  92. continue
  93. if filename.endswith('.pyc') and os.path.exists(filename[:-1]):
  94. mtime = max(os.stat(filename[:-1]).st_mtime, mtime)
  95. if not self.module_mtimes.has_key(filename):
  96. self.module_mtimes[filename] = mtime
  97. elif self.module_mtimes[filename] < mtime:
  98. print >> sys.stderr, (
  99. "%s changed; reloading..." % filename)
  100. return False
  101. return True
  102. def watch_file(self, cls, filename):
  103. filename = os.path.abspath(filename)
  104. if self is None:
  105. for instance in cls.instances:
  106. instance.watch_file(filename)
  107. cls.global_extra_files.append(filename)
  108. else:
  109. self.extra_files.append(filename)
  110. watch_file = classinstancemethod(watch_file)
  111. watch_file = Monitor.watch_file