[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