[Python-modules-commits] [python-hupper] 02/02: Import Debian changes 0.4.2-1
Takaki Taniguchi
takaki at moszumanska.debian.org
Fri Feb 3 03:15:53 UTC 2017
This is an automated email from the git hooks/post-receive script.
takaki pushed a commit to branch master
in repository python-hupper.
commit ffcbbba689d69e8cb5596cb57f4a2253cd3e42b6
Author: TANIGUCHI Takaki <takaki at debian.org>
Date: Fri Feb 3 11:03:29 2017 +0900
Import Debian changes 0.4.2-1
python-hupper (0.4.2-1) unstable; urgency=medium
* Initial release. (Closes: #854015)
---
debian/changelog | 5 +
debian/compat | 1 +
debian/control | 41 +++
debian/copyright | 30 +++
debian/python-python-hupper/usr/bin/hupper | 12 +
.../dist-packages/hupper-0.4.2.egg-info/PKG-INFO | 188 +++++++++++++
.../hupper-0.4.2.egg-info/dependency_links.txt | 1 +
.../hupper-0.4.2.egg-info/entry_points.txt | 3 +
.../hupper-0.4.2.egg-info/not-zip-safe | 1 +
.../hupper-0.4.2.egg-info/requires.txt | 11 +
.../hupper-0.4.2.egg-info/top_level.txt | 1 +
.../lib/python2.7/dist-packages/hupper/__init__.py | 12 +
.../usr/lib/python2.7/dist-packages/hupper/cli.py | 21 ++
.../lib/python2.7/dist-packages/hupper/compat.py | 55 ++++
.../python2.7/dist-packages/hupper/interfaces.py | 46 ++++
.../usr/lib/python2.7/dist-packages/hupper/ipc.py | 62 +++++
.../lib/python2.7/dist-packages/hupper/polling.py | 62 +++++
.../lib/python2.7/dist-packages/hupper/reloader.py | 290 +++++++++++++++++++++
.../lib/python2.7/dist-packages/hupper/watchdog.py | 47 ++++
.../lib/python2.7/dist-packages/hupper/winapi.py | 154 +++++++++++
.../lib/python2.7/dist-packages/hupper/worker.py | 263 +++++++++++++++++++
debian/python3-python-hupper/usr/bin/hupper | 12 +
.../dist-packages/hupper-0.4.2.egg-info/PKG-INFO | 188 +++++++++++++
.../hupper-0.4.2.egg-info/dependency_links.txt | 1 +
.../hupper-0.4.2.egg-info/entry_points.txt | 3 +
.../hupper-0.4.2.egg-info/not-zip-safe | 1 +
.../hupper-0.4.2.egg-info/requires.txt | 11 +
.../hupper-0.4.2.egg-info/top_level.txt | 1 +
.../lib/python3.5/dist-packages/hupper/__init__.py | 12 +
.../usr/lib/python3.5/dist-packages/hupper/cli.py | 21 ++
.../lib/python3.5/dist-packages/hupper/compat.py | 55 ++++
.../python3.5/dist-packages/hupper/interfaces.py | 46 ++++
.../usr/lib/python3.5/dist-packages/hupper/ipc.py | 62 +++++
.../lib/python3.5/dist-packages/hupper/polling.py | 62 +++++
.../lib/python3.5/dist-packages/hupper/reloader.py | 290 +++++++++++++++++++++
.../lib/python3.5/dist-packages/hupper/watchdog.py | 47 ++++
.../lib/python3.5/dist-packages/hupper/winapi.py | 154 +++++++++++
.../lib/python3.5/dist-packages/hupper/worker.py | 263 +++++++++++++++++++
debian/rules | 22 ++
debian/source/format | 1 +
debian/source/options | 1 +
debian/watch | 2 +
42 files changed, 2561 insertions(+)
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..ffabf31
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+python-hupper (0.4.2-1) unstable; urgency=medium
+
+ * Initial release. (Closes: #854015)
+
+ -- TANIGUCHI Takaki <takaki at debian.org> Fri, 03 Feb 2017 11:03:29 +0900
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..17671c9
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,41 @@
+Source: python-hupper
+Section: python
+Priority: optional
+Maintainer: Debian Python Modules Team <python-modules-team at lists.alioth.debian.org>
+Uploaders: TANIGUCHI Takaki <takaki at debian.org>
+Build-Depends: debhelper (>= 9)
+ , dh-python
+ , python-all
+ , python-setuptools
+ , python3-all
+ , python3-setuptools
+Standards-Version: 3.9.8
+Homepage: https://github.com/Pylons/hupper
+X-Python-Version: >= 2.6
+X-Python3-Version: >= 3.2
+Vcs-Git: https://anonscm.debian.org/git/python-modules/packages/python-hupper.git
+Vcs-Browser: https://anonscm.debian.org/cgit/python-modules/packages/python-hupper.git/
+#Testsuite: autopkgtest-pkg-python
+
+Package: python-hupper
+Architecture: all
+Depends: ${python:Depends}, ${misc:Depends}
+Suggests: python-python-hupper-doc
+Description: Integrated process monitor for developing servers (Python 2)
+ hupper is an integrated process monitor that will track changes to any
+ imported Python files in sys.modules as well as custom paths. When files
+ are changed the process is restarted.
+ .
+ This package installs the library for Python 2.
+
+Package: python3-hupper
+Architecture: all
+Depends: ${python3:Depends}, ${misc:Depends}
+Suggests: python-python-hupper-doc
+Description: Integrated process monitor for developing servers. (Python 3)
+ hupper is an integrated process monitor that will track changes to any
+ imported Python files in sys.modules as well as custom paths. When files
+ are changed the process is restarted.
+ .
+ This package installs the library for Python 3.
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..a11ed04
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,30 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: python-hupper
+Source: https://github.com/Pylons/hupper
+
+Files: *
+Copyright: 2017 Michael Merickel
+License: MIT
+
+Files: debian/*
+Copyright: 2017 TANIGUCHI Takaki <takaki at debian.org>
+License: MIT
+
+License: MIT
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/debian/python-python-hupper/usr/bin/hupper b/debian/python-python-hupper/usr/bin/hupper
new file mode 100755
index 0000000..504758f
--- /dev/null
+++ b/debian/python-python-hupper/usr/bin/hupper
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+# EASY-INSTALL-ENTRY-SCRIPT: 'hupper==0.4.2','console_scripts','hupper'
+__requires__ = 'hupper==0.4.2'
+import re
+import sys
+from pkg_resources import load_entry_point
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+ sys.exit(
+ load_entry_point('hupper==0.4.2', 'console_scripts', 'hupper')()
+ )
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/PKG-INFO b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/PKG-INFO
new file mode 100644
index 0000000..89cf2d8
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/PKG-INFO
@@ -0,0 +1,188 @@
+Metadata-Version: 1.1
+Name: hupper
+Version: 0.4.2
+Summary: Integrated process monitor for developing servers.
+Home-page: https://github.com/Pylons/hupper
+Author: Michael Merickel
+Author-email: michael at merickel.org
+License: UNKNOWN
+Description: ======
+ hupper
+ ======
+
+ .. image:: https://img.shields.io/pypi/v/hupper.svg
+ :target: https://pypi.python.org/pypi/hupper
+
+ .. image:: https://img.shields.io/travis/Pylons/hupper.svg
+ :target: https://travis-ci.org/Pylons/hupper
+
+ .. image:: https://readthedocs.org/projects/hupper/badge/?version=latest
+ :target: https://readthedocs.org/projects/hupper/?badge=latest
+ :alt: Documentation Status
+
+ ``hupper`` is an integrated process monitor that will track changes to
+ any imported Python files in ``sys.modules`` as well as custom paths. When
+ files are changed the process is restarted.
+
+ Command-line Usage
+ ==================
+
+ Hupper can load any Python code similar to ``python -m <module>`` by using the
+ ``hupper -m <module>`` program.
+
+ .. code-block:: console
+
+ $ hupper -m myapp
+ Starting monitor for PID 23982.
+
+ API Usage
+ =========
+
+ Start by defining an entry point for your process. This must be an importable
+ path in string format. For example, ``myapp.scripts.serve.main``.
+
+ .. code-block:: python
+
+ # myapp/scripts/serve.py
+
+ import sys
+ import hupper
+ import waitress
+
+ def wsgi_app(environ, start_response):
+ start_response('200 OK', [('Content-Type', 'text/plain'])
+ yield [b'hello']
+
+ def main(args=sys.argv[1:]):
+ if '--reload' in args:
+ # start_reloader will only return in a monitored subprocess
+ reloader = hupper.start_reloader('myapp.scripts.serve.main')
+
+ # monitor an extra file
+ reloader.watch_files(['foo.ini'])
+
+ waitress.serve(wsgi_app)
+
+ Acknowledgments
+ ===============
+
+ ``hupper`` is inspired by initial work done by Carl J Meyer and David Glick
+ during a Pycon sprint and is built to be a more robust and generic version of
+ Ian Bicking's excellent PasteScript ``paste serve --reload`` and Pyramid's
+ ``pserve --reload``.
+
+
+ 0.4.2 (2017-01-24)
+ ==================
+
+ - Pause briefly after receiving a SIGINT to allow the worker to kill itself.
+ If it does not die then it is terminated.
+ See https://github.com/Pylons/hupper/issues/11
+
+ - Python 3.6 compatibility.
+
+ 0.4.1 (2017-01-03)
+ ==================
+
+ - Handle errors that may occur when using watchdog to observe non-existent
+ folders.
+
+ 0.4.0 (2017-01-02)
+ ==================
+
+ - Support running any Python module via ``hupper -m <module>``. This is
+ equivalent to ``python -m`` except will fully reload the process when files
+ change. See https://github.com/Pylons/hupper/pull/8
+
+ 0.3.6 (2016-12-18)
+ ==================
+
+ - Read the traceback for unknown files prior to crashing. If an import
+ crashes due to a module-scope exception the file that caused the crash would
+ not be tracked but this should help.
+
+ 0.3.5 (2016-12-17)
+ ==================
+
+ - Attempt to send imported paths to the monitor process before crashing to
+ avoid cases where the master is waiting for changes in files that it never
+ started monitoring.
+
+ 0.3.4 (2016-11-21)
+ ==================
+
+ - Add support for globbing using the stdlib ``glob`` module. On Python 3.5+
+ this allows recursive globs using ``**``. Prior to this, the globbing is
+ more limited.
+
+ 0.3.3 (2016-11-19)
+ ==================
+
+ - Fixed a runtime failure on Windows 32-bit systems.
+
+ 0.3.2 (2016-11-15)
+ ==================
+
+ - Support triggering reloads via SIGHUP when hupper detected a crash and is
+ waiting for a file to change.
+
+ - Setup the reloader proxy prior to importing the worker's module. This
+ should allow some work to be done at module-scope instead of in the
+ callable.
+
+ 0.3.1 (2016-11-06)
+ ==================
+
+ - Fix package long description on PyPI.
+
+ - Ensure that the stdin file handle is inheritable incase the "spawn" variant
+ of multiprocessing is enabled.
+
+ 0.3 (2016-11-06)
+ ================
+
+ - Disable bytecode compiling of files imported by the worker process. This
+ should not be necessary when developing and it was causing the process to
+ restart twice on Windows due to how it handles pyc timestamps.
+
+ - Fix hupper's support for forwarding stdin to the worker processes on
+ Python < 3.5 on Windows.
+
+ - Fix some possible file descriptor leakage.
+
+ - Simplify the ``hupper.interfaces.IFileMonitor`` interface by internalizing
+ some of the hupper-specific integrations. They can now focus on just
+ looking for changes.
+
+ - Add the ``hupper.interfaces.IFileMonitorFactory`` interface to improve
+ the documentation for the ``callback`` argument required by
+ ``hupper.interfaces.IFileMonitor``.
+
+ 0.2 (2016-10-26)
+ ================
+
+ - Windows support!
+
+ - Added support for `watchdog <https://pypi.org/project/watchdog/>`_ if it's
+ installed to do inotify-style file monitoring. This is an optional dependency
+ and ``hupper`` will fallback to using polling if it's not available.
+
+ 0.1 (2016-10-21)
+ ================
+
+ - Initial release.
+
+Keywords: server daemon autoreload reloader hup file watch process
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/dependency_links.txt b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/entry_points.txt b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/entry_points.txt
new file mode 100644
index 0000000..024ef7f
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/entry_points.txt
@@ -0,0 +1,3 @@
+[console_scripts]
+hupper = hupper.cli:main
+
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/not-zip-safe b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/requires.txt b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/requires.txt
new file mode 100644
index 0000000..0b371a6
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/requires.txt
@@ -0,0 +1,11 @@
+
+[docs]
+Sphinx
+pylons-sphinx-themes
+watchdog
+
+[testing]
+mock
+pytest
+pytest-cov
+watchdog
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/top_level.txt b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/top_level.txt
new file mode 100644
index 0000000..f73cf66
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper-0.4.2.egg-info/top_level.txt
@@ -0,0 +1 @@
+hupper
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/__init__.py b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/__init__.py
new file mode 100644
index 0000000..2511abb
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/__init__.py
@@ -0,0 +1,12 @@
+# public api
+# flake8: noqa
+
+from .compat import is_watchdog_supported
+
+from .reloader import (
+ start_reloader,
+)
+from .worker import (
+ is_active,
+ get_reloader,
+)
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/cli.py b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/cli.py
new file mode 100644
index 0000000..3cb90b1
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/cli.py
@@ -0,0 +1,21 @@
+from __future__ import print_function
+
+import argparse
+import sys
+
+from .reloader import start_reloader
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-m", dest="module", required=True)
+
+ args, unknown_args = parser.parse_known_args()
+
+ sys.argv[1:] = unknown_args
+ sys.path.insert(0, "")
+
+ start_reloader(
+ "runpy.run_module",
+ worker_args=[args.module],
+ worker_kwargs={"alter_sys": True, "run_name": "__main__"})
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/compat.py b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/compat.py
new file mode 100644
index 0000000..c1dc23f
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/compat.py
@@ -0,0 +1,55 @@
+# flake8: noqa
+import imp
+import importlib
+import sys
+
+PY2 = sys.version_info[0] == 2
+WIN = sys.platform == 'win32'
+
+if PY2:
+ long = long
+else:
+ long = int
+
+try:
+ import queue
+except ImportError:
+ import Queue as queue
+
+try:
+ from _thread import interrupt_main
+except ImportError:
+ from thread import interrupt_main
+
+
+try:
+ from importlib.util import (
+ cache_from_source as get_pyc_path,
+ source_from_cache as get_py_path,
+ )
+except ImportError:
+ if PY2:
+ get_pyc_path = lambda path: path + 'c'
+ get_py_path = lambda path: path[:-1]
+
+ # fallback on python < 3.5
+ else:
+ get_pyc_path = imp.cache_from_source
+ get_py_path = imp.source_from_cache
+
+
+def is_watchdog_supported():
+ """ Return ``True`` if watchdog is available."""
+ try:
+ import watchdog
+ except ImportError:
+ return False
+ return True
+
+
+################################################
+# cross-compatible metaclass implementation
+# Copyright (c) 2010-2012 Benjamin Peterson
+def with_metaclass(meta, base=object):
+ """Create a base class with a metaclass."""
+ return meta("%sBase" % meta.__name__, (base,), {})
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/interfaces.py b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/interfaces.py
new file mode 100644
index 0000000..eca0a64
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/interfaces.py
@@ -0,0 +1,46 @@
+import abc
+
+from .compat import with_metaclass
+
+
+class IReloaderProxy(with_metaclass(abc.ABCMeta)):
+ @abc.abstractmethod
+ def watch_files(self, files):
+ """ Signal to the monitor to track some custom paths."""
+
+ @abc.abstractmethod
+ def trigger_reload(self):
+ """ Signal the monitor to execute a reload."""
+
+
+class IFileMonitorFactory(with_metaclass(abc.ABCMeta)):
+ def __call__(self, callback):
+ """ Return an :class:`.IFileMonitor` instance.
+
+ ``callback`` is a callable to be invoked by the ``IFileMonitor``
+ when file changes are detected. It should accept the path of
+ the changed file as its only parameter.
+
+ """
+
+
+class IFileMonitor(with_metaclass(abc.ABCMeta)):
+ @abc.abstractmethod
+ def add_path(self, path):
+ """ Start monitoring a new path."""
+
+ @abc.abstractmethod
+ def start(self):
+ """ Start the monitor. This method should not block."""
+
+ @abc.abstractmethod
+ def stop(self):
+ """ Trigger the monitor to stop.
+
+ This should be called before invoking :meth:`.join`.
+
+ """
+
+ @abc.abstractmethod
+ def join(self):
+ """ Block until the monitor has stopped."""
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/ipc.py b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/ipc.py
new file mode 100644
index 0000000..6f3890f
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/ipc.py
@@ -0,0 +1,62 @@
+import os
+
+from .compat import WIN
+
+
+if WIN: # pragma: no cover
+ import msvcrt
+ from . import winapi
+
+ class ProcessGroup(object):
+ def __init__(self):
+ self.h_job = winapi.CreateJobObject(None, None)
+
+ info = winapi.JOBOBJECT_BASIC_LIMIT_INFORMATION()
+ info.LimitFlags = winapi.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
+
+ extended_info = winapi.JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
+ extended_info.BasicLimitInformation = info
+
+ winapi.SetInformationJobObject(
+ self.h_job,
+ winapi.JobObjectExtendedLimitInformation,
+ extended_info,
+ )
+
+ def add_child(self, pid):
+ hp = winapi.OpenProcess(winapi.PROCESS_ALL_ACCESS, False, pid)
+ return winapi.AssignProcessToJobObject(self.h_job, hp)
+
+ def send_fd(pipe, fd, pid):
+ hf = msvcrt.get_osfhandle(fd)
+ hp = winapi.OpenProcess(winapi.PROCESS_ALL_ACCESS, False, pid)
+ tp = winapi.DuplicateHandle(
+ winapi.GetCurrentProcess(), hf, hp,
+ 0, False, winapi.DUPLICATE_SAME_ACCESS,
+ ).Detach() # do not close the handle
+ pipe.send(tp)
+
+ def recv_fd(pipe, mode):
+ handle = pipe.recv()
+ flags = 0
+ if 'w' not in mode and '+' not in mode:
+ flags |= os.O_RDONLY
+ if 'b' not in mode:
+ flags |= os.O_TEXT
+ if 'a' in mode:
+ flags |= os.O_APPEND
+ fd = msvcrt.open_osfhandle(handle, flags)
+ return os.fdopen(fd, mode)
+
+else:
+ class ProcessGroup(object):
+ def add_child(self, pid):
+ # nothing to do on *nix
+ pass
+
+ def send_fd(pipe, fd, pid):
+ pipe.send(fd)
+
+ def recv_fd(pipe, mode):
+ fd = pipe.recv()
+ return os.fdopen(fd, mode)
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/polling.py b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/polling.py
new file mode 100644
index 0000000..c9413ef
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/polling.py
@@ -0,0 +1,62 @@
+import os
+import threading
+import time
+
+from .interfaces import IFileMonitor
+
+
+class PollingFileMonitor(threading.Thread, IFileMonitor):
+ """
+ An :class:`hupper.interfaces.IFileMonitor` that stats the files
+ at periodic intervals.
+
+ ``callback`` is a callable that accepts a path to a changed file.
+
+ ``poll_interval`` is a value in seconds between scans of the files on
+ disk. Do not set this too low or it will eat your CPU and kill your drive.
+
+ """
+ def __init__(self, callback, poll_interval=1):
+ super(PollingFileMonitor, self).__init__()
+ self.callback = callback
+ self.poll_interval = poll_interval
+ self.paths = set()
+ self.mtimes = {}
+ self.lock = threading.Lock()
+
+ def add_path(self, path):
+ with self.lock:
+ self.paths.add(path)
+
+ def run(self):
+ self.enabled = True
+ while self.enabled:
+ with self.lock:
+ paths = list(self.paths)
+ self.check_reload(paths)
+ time.sleep(self.poll_interval)
+
+ def stop(self):
+ self.enabled = False
+
+ def check_reload(self, paths):
+ changes = set()
+ for path in paths:
+ mtime = get_mtime(path)
+ if path not in self.mtimes:
+ self.mtimes[path] = mtime
+ elif self.mtimes[path] < mtime:
+ self.mtimes[path] = mtime
+ changes.add(path)
+ for path in sorted(changes):
+ self.callback(path)
+
+
+def get_mtime(path):
+ try:
+ stat = os.stat(path)
+ if stat:
+ return stat.st_mtime
+ except (OSError, IOError): # pragma: no cover
+ pass
+ return 0
diff --git a/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/reloader.py b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/reloader.py
new file mode 100644
index 0000000..8e3625e
--- /dev/null
+++ b/debian/python-python-hupper/usr/lib/python2.7/dist-packages/hupper/reloader.py
@@ -0,0 +1,290 @@
+from __future__ import print_function
+
+from glob import glob
+import signal
+import sys
+import threading
+import time
+
+from .compat import (
+ is_watchdog_supported,
+ queue,
+)
+from .ipc import ProcessGroup
+from .worker import (
+ Worker,
+ is_active,
+ get_reloader,
+)
+
+
+class FileMonitorProxy(object):
+ """
+ Wrap an :class:`hupper.interfaces.IFileMonitor` into an object that
+ exposes a thread-safe interface back to the reloader to detect
+ when it should reload.
+
+ """
+ def __init__(self, monitor_factory, verbose=1):
+ self.monitor = monitor_factory(self.file_changed)
+ self.verbose = verbose
+ self.change_event = threading.Event()
+ self.changed_paths = set()
+
+ def out(self, msg):
+ if self.verbose > 0:
+ print(msg)
+
+ def add_path(self, path):
+ # if the glob does not match any files then go ahead and pass
+ # the pattern to the monitor anyway incase it is just a file that
+ # is currently missing
+ for p in glob(path) or [path]:
+ self.monitor.add_path(p)
+
+ def start(self):
+ self.monitor.start()
+
+ def stop(self):
+ self.monitor.stop()
+ self.monitor.join()
+
+ def file_changed(self, path):
+ if path not in self.changed_paths:
+ self.changed_paths.add(path)
+ self.out('%s changed; reloading ...' % (path,))
+ self.set_changed()
+
+ def is_changed(self):
+ return self.change_event.is_set()
+
+ def wait_for_change(self, timeout=None):
+ return self.change_event.wait(timeout)
+
+ def clear_changes(self):
+ self.change_event.clear()
+ self.changed_paths.clear()
+
+ def set_changed(self):
+ self.change_event.set()
+
+
+class Reloader(object):
+ """
+ A wrapper class around a file monitor which will handle changes by
+ restarting a new worker process.
+
+ """
+ def __init__(self,
+ worker_path,
+ monitor_factory,
+ reload_interval=1,
+ verbose=1,
+ worker_args=None,
+ worker_kwargs=None,
+ ):
+ self.worker_path = worker_path
+ self.worker_args = worker_args
+ self.worker_kwargs = worker_kwargs
+ self.monitor_factory = monitor_factory
+ self.reload_interval = reload_interval
+ self.verbose = verbose
+ self.monitor = None
+ self.worker = None
+ self.group = ProcessGroup()
+
+ def out(self, msg):
+ if self.verbose > 0:
+ print(msg)
+
+ def run(self):
+ """
+ Execute the reloader forever, blocking the current thread.
+
+ This will invoke ``sys.exit(1)`` if interrupted.
+
+ """
+ self._capture_signals()
+ self._start_monitor()
+ try:
+ while True:
+ if not self._run_worker():
+ self._wait_for_changes()
+ time.sleep(self.reload_interval)
+ except KeyboardInterrupt:
+ pass
+ finally:
+ self._stop_monitor()
+ self._restore_signals()
+ sys.exit(1)
+
+ def run_once(self):
+ """
+ Execute the worker once.
+
+ This method will return after a file change is detected.
+
+ """
+ self._capture_signals()
+ self._start_monitor()
+ try:
+ self._run_worker()
+ except KeyboardInterrupt:
+ return
+ finally:
+ self._stop_monitor()
+ self._restore_signals()
+
+ def _run_worker(self):
+ self.worker = Worker(
+ self.worker_path,
+ args=self.worker_args,
+ kwargs=self.worker_kwargs,
+ )
+ self.worker.start()
+
+ try:
+ # register the worker with the process group
+ self.group.add_child(self.worker.pid)
+
+ self.out("Starting monitor for PID %s." % self.worker.pid)
+ self.monitor.clear_changes()
+
+ while not self.monitor.is_changed() and self.worker.is_alive():
+ try:
+ # if the child has sent any data then restart
+ if self.worker.pipe.poll(0):
+ # do not read, the pipe is closed after the break
+ break
+ except EOFError: # pragma: nocover
+ pass
+
+ try:
+ path = self.worker.files_queue.get(
+ timeout=self.reload_interval,
+ )
+ except queue.Empty:
+ pass
+ else:
+ self.monitor.add_path(path)
+ except KeyboardInterrupt:
+ if self.worker.is_alive():
+ self.out('Waiting for server to exit ...')
+ time.sleep(self.reload_interval)
+ raise
+ finally:
+ if self.worker.is_alive():
+ self.out('Killing server with PID %s.' % self.worker.pid)
+ self.worker.terminate()
+ self.worker.join()
+
+ else:
+ self.worker.join()
+ self.out('Server with PID %s exited with code %d.' %
+ (self.worker.pid, self.worker.exitcode))
+
+ self.monitor.clear_changes()
+
+ force_restart = self.worker.terminated
+ self.worker = None
+ return force_restart
+
+ def _wait_for_changes(self):
+ self.out('Waiting for changes before reloading.')
+ while (
+ not self.monitor.wait_for_change(self.reload_interval)
+ ): # pragma: nocover
+ pass
+
+ self.monitor.clear_changes()
+
+ def _start_monitor(self):
+ self.monitor = FileMonitorProxy(self.monitor_factory, self.verbose)
+ self.monitor.start()
+
+ def _stop_monitor(self):
+ if self.monitor:
+ self.monitor.stop()
+ self.monitor = None
+
+ def _capture_signals(self):
+ # SIGHUP is not supported on windows
+ if hasattr(signal, 'SIGHUP'):
+ signal.signal(signal.SIGHUP, self._signal_sighup)
+
+ def _signal_sighup(self, signum, frame):
+ self.out('Received SIGHUP, triggering a reload.')
+ self.monitor.set_changed()
+
+ def _restore_signals(self):
+ if hasattr(signal, 'SIGHUP'):
+ signal.signal(signal.SIGHUP, signal.SIG_DFL)
+
+
+def start_reloader(
+ worker_path,
+ reload_interval=1,
+ verbose=1,
+ monitor_factory=None,
+ worker_args=None,
+ worker_kwargs=None,
+):
+ """
+ Start a monitor and then fork a worker process which starts by executing
+ the importable function at ``worker_path``.
+
+ If this function is called from a worker process that is already being
+ monitored then it will return a reference to the current
+ :class:`hupper.interfaces.IReloaderProxy` which can be used to
+ communicate with the monitor.
+
+ ``worker_path`` must be a dotted string pointing to a globally importable
+ function that will be executed to start the worker. An example could be
+ ``myapp.cli.main``. In most cases it will point at the same function that
+ is invoking ``start_reloader`` in the first place.
+
+ ``reload_interval`` is a value in seconds and will be used to throttle
+ restarts.
+
+ ``verbose`` controls the output. Set to ``0`` to turn off any logging
+ of activity and turn up to ``2`` for extra output.
+
+ ``monitor_factory`` is an instance of
+ :class:`hupper.interfaces.IFileMonitorFactory`. If left unspecified, this
+ will try to create a :class:`hupper.watchdog.WatchdogFileMonitor` if
+ `watchdog <https://pypi.org/project/watchdog/>`_ is installed and will
+ fallback to the less efficient
+ :class:`hupper.polling.PollingFileMonitor` otherwise.
+
+ """
+ if is_active():
+ return get_reloader()
+
+ if monitor_factory is None:
+ if is_watchdog_supported():
+ from .watchdog import WatchdogFileMonitor
+
+ def monitor_factory(callback):
+ return WatchdogFileMonitor(callback)
+
+ if verbose > 1:
+ print('File monitor backend: watchdog')
+
+ else:
+ from .polling import PollingFileMonitor
+
+ def monitor_factory(callback):
+ return PollingFileMonitor(callback, reload_interval)
+
+ if verbose > 1:
+ print('File monitor backend: polling')
+
+ reloader = Reloader(
+ worker_path=worker_path,
+ worker_args=worker_args,
+ worker_kwargs=worker_kwargs,
+ reload_interval=reload_interval,
... 1867 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-hupper.git
More information about the Python-modules-commits
mailing list