New Upstream Release - python-hupper
Ready changes
Summary
Merged new upstream version: 1.12 (was: 1.11).
Resulting package
Built on 2023-06-01T19:34 (took 4m16s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases python3-hupper
Lintian Result
Diff
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..5737055
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+# Set update schedule for GitHub Actions
+
+version: 2
+updates:
+
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ # Check for updates to GitHub Actions every weekday
+ interval: "daily"
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
new file mode 100644
index 0000000..ff8e63c
--- /dev/null
+++ b/.github/workflows/ci-tests.yml
@@ -0,0 +1,97 @@
+name: Build and test
+
+on:
+ # Only on pushes to main or one of the release branches we build on push
+ push:
+ branches:
+ - main
+ - "[0-9].[0-9]+-branch"
+ tags:
+ - "*"
+ # Build pull requests
+ pull_request:
+
+jobs:
+ test:
+ strategy:
+ matrix:
+ py:
+ - "3.7"
+ - "3.8"
+ - "3.9"
+ - "3.10"
+ - "3.11"
+ - "pypy-3.8"
+ os:
+ - "ubuntu-latest"
+ - "windows-2022"
+ - "macos-12"
+ architecture:
+ - x64
+ - x86
+
+ include:
+ # Only run coverage on ubuntu-20.04, except on pypy3
+ - os: "ubuntu-latest"
+ pytest-args: "--cov"
+ - os: "ubuntu-latest"
+ py: "pypy-3.8"
+ pytest-args: ""
+
+ exclude:
+ # Linux and macOS don't have x86 python
+ - os: "ubuntu-latest"
+ architecture: x86
+ - os: "macos-12"
+ architecture: x86
+
+ name: "Python: ${{ matrix.py }}-${{ matrix.architecture }} on ${{ matrix.os }}"
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup python
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.py }}
+ architecture: ${{ matrix.architecture }}
+ - run: pip install tox
+ - run: ulimit -n 4096
+ if: ${{ runner.os == 'macOS' }}
+ - name: Running tox
+ run: tox -e py -- ${{ matrix.pytest-args }}
+ coverage:
+ runs-on: ubuntu-latest
+ name: Validate coverage
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup python
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.9
+ architecture: x64
+ - run: pip install tox
+ - run: tox -e py39,coverage
+ docs:
+ runs-on: ubuntu-latest
+ name: Build the documentation
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup python
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.9
+ architecture: x64
+ - run: pip install tox
+ - run: tox -e docs
+ lint:
+ runs-on: ubuntu-latest
+ name: Lint the package
+ steps:
+ - uses: actions/checkout@v3
+ - name: Setup python
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.9
+ architecture: x64
+ - run: pip install tox
+ - run: tox -e lint
diff --git a/CHANGES.rst b/CHANGES.rst
index 5a9bafc..6b02a04 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,20 @@
+1.12 (2023-04-02)
+=================
+
+- When the reloader is stopped, exit with the same code received from the
+ subprocess.
+ See https://github.com/Pylons/hupper/pull/81
+
+1.11 (2022-01-02)
+=================
+
+- Drop support for Python 2.7, 3.4, 3.5, and 3.6.
+
+- Add support/testing for Python 3.10, and 3.11.
+
+- Explicitly require ``reload_interval`` set greater than ``0`` to avoid
+ spinning the CPU needlessly.
+
1.10.3 (2021-05-13)
===================
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 0176efd..5564ff2 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -102,9 +102,10 @@ Before you submit a pull request, check that it meets these guidelines:
2. If the pull request adds functionality, the docs should be updated. Put
your new functionality into a function with a docstring, and add the
feature to the list in README.rst.
-3. The pull request should work for Python 2.7, 3.4 and 3.5, and for PyPy. Check
- https://travis-ci.org/Pylons/hupper/pull_requests
- and make sure that the tests pass for all supported Python versions.
+3. The pull request should work for Python 3.7 and up and for PyPy 3.8.
+4. When your pull request is posted, a maintainer will click the button to run
+ Github Actions, afterwards validate that your PR is valid for all tested
+ platforms/Python versions
Tips
----
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index fbfeaa6..8cd4bbd 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -110,3 +110,4 @@ Contributors
- Jens Carl (2017-05-22)
- Eric Atkin (2019-02-15)
- Yeray Díaz Díaz (2019-10-03)
+- Marcel Jackwerth (2023-03-23)
diff --git a/MANIFEST.in b/MANIFEST.in
index 39fefc1..73d7730 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,7 @@
graft src/hupper
graft tests
graft docs
+graft .github
prune docs/_build
include README.rst
@@ -11,6 +12,6 @@ include CONTRIBUTORS.txt
include pyproject.toml setup.cfg
include .coveragerc .flake8
-include tox.ini appveyor.yml .travis.yml rtd.txt
+include tox.ini rtd.txt pytest.ini
recursive-exclude * __pycache__ *.py[cod]
diff --git a/PKG-INFO b/PKG-INFO
index a362842..813a47d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,431 +1,96 @@
Metadata-Version: 2.1
Name: hupper
-Version: 1.10.3
+Version: 1.12
Summary: Integrated process monitor for developing and reloading daemons.
Home-page: https://github.com/Pylons/hupper
Author: Michael Merickel
Author-email: pylons-discuss@googlegroups.com
License: MIT
-Description: ======
- hupper
- ======
-
- .. image:: https://img.shields.io/pypi/v/hupper.svg
- :target: https://pypi.python.org/pypi/hupper
-
- .. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20Linux/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+Linux%22
-
- .. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20MacOS/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+MacOS%22
-
- .. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20Windows/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+Windows%22
-
- .. 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``.
-
-
- 1.10.3 (2021-05-13)
- ===================
-
- - Support Python 3.8 and 3.9.
-
- - Fix an issue with bare ``.pyc`` files in the source folder causing unhandled
- exceptions.
- See https://github.com/Pylons/hupper/pull/69
-
- - Fix issues with using the Watchman file monitor on versions newer than
- Watchman 4.9.0. This fix modifies ``hupper`` to use Watchman's
- ``watch-project`` capabilities which also support reading the
- ``.watchmanconfig`` file to control certain properties of the monitoring.
- See https://github.com/Pylons/hupper/pull/70
-
- 1.10.2 (2020-03-02)
- ===================
-
- - Fix a regression that caused SIGINT to not work properly in some situations.
- See https://github.com/Pylons/hupper/pull/67
-
- 1.10.1 (2020-02-18)
- ===================
-
- - Performance improvements when using Watchman.
-
- 1.10 (2020-02-18)
- =================
-
- - Handle a ``SIGTERM`` signal by forwarding it to the child process and
- gracefully waiting for it to exit. This should enable using ``hupper``
- from within docker containers and other systems that want to control
- the reloader process.
-
- Previously the ``SIGTERM`` would shutdown ``hupper`` immediately, stranding
- the worker and relying on it to shutdown on its own.
-
- See https://github.com/Pylons/hupper/pull/65
-
- - Avoid acquiring locks in the reloader process's signal handlers.
- See https://github.com/Pylons/hupper/pull/65
-
- - Fix deprecation warnings caused by using the ``imp`` module on newer
- versions of Python.
- See https://github.com/Pylons/hupper/pull/65
-
- 1.9.1 (2019-11-12)
- ==================
-
- - Support some scenarios in which user code is symlinked ``site-packages``.
- These were previously being ignored by the file monitor but should now
- be tracked.
- See https://github.com/Pylons/hupper/pull/61
-
- 1.9 (2019-10-14)
- ================
-
- - Support ``--shutdown-interval`` on the ``hupper`` CLI.
- See https://github.com/Pylons/hupper/pull/56
-
- - Support ``--reload-interval`` on the ``hupper`` CLI.
- See https://github.com/Pylons/hupper/pull/59
-
- - Do not choke when stdin is not a TTY while waiting for changes after a
- crash. For example, when running in Docker Compose.
- See https://github.com/Pylons/hupper/pull/58
-
- 1.8.1 (2019-06-12)
- ==================
-
- - Do not show the ``KeyboardInterrupt`` stacktrace when killing ``hupper``
- while waiting for a reload.
-
- 1.8 (2019-06-11)
- ================
-
- - If the worker process crashes, ``hupper`` can be forced to reload the worker
- by pressing the ``ENTER`` key in the terminal instead of waiting to change a
- file.
- See https://github.com/Pylons/hupper/pull/53
-
- 1.7 (2019-06-04)
- ================
-
- - On Python 3.5+ support recursive glob syntax in ``reloader.watch_files``.
- See https://github.com/Pylons/hupper/pull/52
-
- 1.6.1 (2019-03-11)
- ==================
-
- - If the worker crashes immediately, sometimes ``hupper`` would go into a
- restart loop instead of waiting for a code change.
- See https://github.com/Pylons/hupper/pull/50
-
- 1.6 (2019-03-06)
- ================
-
- - On systems that support ``SIGKILL`` and ``SIGTERM`` (not Windows), ``hupper``
- will now send a ``SIGKILL`` to the worker process as a last resort. Normally,
- a ``SIGINT`` (Ctrl-C) or ``SIGTERM`` (on reload) will kill the worker. If,
- within ``shutdown_interval`` seconds, the worker doesn't exit, it will
- receive a ``SIGKILL``.
- See https://github.com/Pylons/hupper/pull/48
-
- - Support a ``logger`` argument to ``hupper.start_reloader`` to override
- the default logger that outputs messages to ``sys.stderr``.
- See https://github.com/Pylons/hupper/pull/49
-
- 1.5 (2019-02-16)
- ================
-
- - Add support for ignoring custom patterns via the new ``ignore_files``
- option on ``hupper.start_reloader``. The ``hupper`` cli also supports
- ignoring files via the ``-x`` option.
- See https://github.com/Pylons/hupper/pull/46
-
- 1.4.2 (2018-11-26)
- ==================
-
- - Fix a bug prompting the "ignoring corrupted payload from watchman" message
- and placing the file monitor in an unrecoverable state when a change
- triggered a watchman message > 4096 bytes.
- See https://github.com/Pylons/hupper/pull/44
-
- 1.4.1 (2018-11-11)
- ==================
-
- - Stop ignoring a few paths that may not be system paths in cases where the
- virtualenv is the root of your project.
- See https://github.com/Pylons/hupper/pull/42
-
- 1.4 (2018-10-26)
- ================
-
- - Ignore changes to any system / installed files. This includes mostly
- changes to any files in the stdlib and ``site-packages``. Anything that is
- installed in editable mode or not installed at all will still be monitored.
- This drastically reduces the number of files that ``hupper`` needs to
- monitor.
- See https://github.com/Pylons/hupper/pull/40
-
- 1.3.1 (2018-10-05)
- ==================
-
- - Support Python 3.7.
-
- - Avoid a restart-loop if the app is failing to restart on certain systems.
- There was a race where ``hupper`` failed to detect that the app was
- crashing and thus fell into its restart logic when the user manually
- triggers an immediate reload.
- See https://github.com/Pylons/hupper/pull/37
-
- - Ignore corrupted packets coming from watchman that occur in semi-random
- scenarios. See https://github.com/Pylons/hupper/pull/38
-
- 1.3 (2018-05-21)
- ================
-
- - Added watchman support via ``hupper.watchman.WatchmanFileMonitor``.
- This is the new preferred file monitor on systems supporting unix sockets.
- See https://github.com/Pylons/hupper/pull/32
-
- - The ``hupper.watchdog.WatchdogFileMonitor`` will now output some info
- when it receives ulimit or other errors from ``watchdog``.
- See https://github.com/Pylons/hupper/pull/33
-
- - Allow ``-q`` and ``-v`` cli options to control verbosity.
- See https://github.com/Pylons/hupper/pull/33
-
- - Pass a ``logger`` value to the ``hupper.interfaces.IFileMonitorFactory``.
- This is an instance of ``hupper.interfaces.ILogger`` and can be used by
- file monitors to output errors and debug information.
- See https://github.com/Pylons/hupper/pull/33
-
- 1.2 (2018-05-01)
- ================
-
- - Track only Python source files. Previously ``hupper`` would track all pyc
- and py files. Now, if a pyc file is found then the equivalent source file
- is searched and, if found, the pyc file is ignored.
- See https://github.com/Pylons/hupper/pull/31
-
- - Allow overriding the default monitor lookup by specifying the
- ``HUPPER_DEFAULT_MONITOR`` environment variable as a Python dotted-path
- to a monitor factory. For example,
- ``HUPPER_DEFAULT_MONITOR=hupper.polling.PollingFileMonitor``.
- See https://github.com/Pylons/hupper/pull/29
-
- - Backward-incompatible changes to the
- ``hupper.interfaces.IFileMonitorFactory`` API to pass arbitrary kwargs
- to the factory.
- See https://github.com/Pylons/hupper/pull/29
-
- 1.1 (2018-03-29)
- ================
-
- - Support ``-w`` on the CLI to watch custom file paths.
- See https://github.com/Pylons/hupper/pull/28
-
- 1.0 (2017-05-18)
- ================
-
- - Copy ``sys.path`` to the worker process and ensure ``hupper`` is on the
- ``PYTHONPATH`` so that the subprocess can import it to start the worker.
- This fixes an issue with how ``zc.buildout`` injects dependencies into a
- process which is done entirely by ``sys.path`` manipulation.
- See https://github.com/Pylons/hupper/pull/27
-
- 0.5 (2017-05-10)
- ================
-
- - On non-windows systems ensure an exec occurs so that the worker does not
- share the same process space as the reloader causing certain code that
- is imported in both to not ever be reloaded. Under the hood this was a
- significant rewrite to use subprocess instead of multiprocessing.
- See https://github.com/Pylons/hupper/pull/23
-
- 0.4.4 (2017-03-10)
- ==================
-
- - Fix some versions of Windows which were failing to duplicate stdin to
- the subprocess and crashing.
- https://github.com/Pylons/hupper/pull/16
-
- 0.4.3 (2017-03-07)
- ==================
-
- - Fix pdb and other readline-based programs to operate properly.
- See https://github.com/Pylons/hupper/pull/15
-
- 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
+Project-URL: Documentation, https://docs.pylonsproject.org/projects/hupper/en/latest/
+Project-URL: Changelog, https://docs.pylonsproject.org/projects/hupper/en/latest/changes.html
+Project-URL: Issue Tracker, https://github.com/Pylons/hupper/issues
+Keywords: server,daemon,autoreload,reloader,hup,file,watch,process
Classifier: Development Status :: 5 - Production/Stable
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.5
-Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
-Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
+Requires-Python: >=3.7
+Description-Content-Type: text/x-rst
Provides-Extra: docs
Provides-Extra: testing
+License-File: LICENSE.txt
+
+======
+hupper
+======
+
+.. image:: https://img.shields.io/pypi/v/hupper.svg
+ :target: https://pypi.python.org/pypi/hupper
+
+.. image:: https://github.com/Pylons/hupper/actions/workflows/ci-tests.yml/badge.svg?branch=main
+ :target: https://github.com/Pylons/hupper/actions/workflows/ci-tests.yml?query=branch%3Amain
+
+.. 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``.
diff --git a/README.rst b/README.rst
index 8cc398e..1bc3a5c 100644
--- a/README.rst
+++ b/README.rst
@@ -5,14 +5,8 @@ hupper
.. image:: https://img.shields.io/pypi/v/hupper.svg
:target: https://pypi.python.org/pypi/hupper
-.. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20Linux/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+Linux%22
-
-.. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20MacOS/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+MacOS%22
-
-.. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20Windows/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+Windows%22
+.. image:: https://github.com/Pylons/hupper/actions/workflows/ci-tests.yml/badge.svg?branch=main
+ :target: https://github.com/Pylons/hupper/actions/workflows/ci-tests.yml?query=branch%3Amain
.. image:: https://readthedocs.org/projects/hupper/badge/?version=latest
:target: https://readthedocs.org/projects/hupper/?badge=latest
diff --git a/debian/changelog b/debian/changelog
index 020db05..6388def 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-hupper (1.12-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 01 Jun 2023 19:30:47 -0000
+
python-hupper (1.10.3-1) unstable; urgency=medium
[ Debian Janitor ]
diff --git a/pyproject.toml b/pyproject.toml
index c44ccef..44d53bb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[tool.black]
line-length = 79
skip-string-normalization = true
-py36 = false
+target_version = ["py37", "py38", "py39", "py310", "py311"]
exclude = '''
/(
\.git
@@ -22,11 +22,9 @@ exclude = '''
# This next section only exists for people that have their editors
# automatically call isort, black already sorts entries on its own when run.
[tool.isort]
-multi_line_output = 3
-include_trailing_comma = true
-force_grid_wrap = false
+profile = "black"
+py_version = 3
combine_as_imports = true
-use_parenthesis = true
line_length = 79
force_sort_within_sections = true
no_lines_before = "THIRDPARTY"
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..8ee2cf1
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,5 @@
+[pytest]
+python_files = test_*.py
+testpaths =
+ src/hupper
+ tests
\ No newline at end of file
diff --git a/rtd.txt b/rtd.txt
index e9704b8..142b6ca 100644
--- a/rtd.txt
+++ b/rtd.txt
@@ -1 +1 @@
-.[docs]
+-e .[docs]
diff --git a/setup.cfg b/setup.cfg
index e76b109..8dad93a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,22 +1,75 @@
-[bdist_wheel]
-universal = 1
-
[metadata]
-license_file = LICENSE.txt
+name = hupper
+version = 1.12
+author = Michael Merickel
+author_email = pylons-discuss@googlegroups.com
+license = MIT
+license_files = LICENSE.txt
+description = Integrated process monitor for developing and reloading daemons.
+long_description = file:README.rst
+long_description_content_type = text/x-rst
+keywords =
+ server
+ daemon
+ autoreload
+ reloader
+ hup
+ file
+ watch
+ process
+url = https://github.com/Pylons/hupper
+project_urls =
+ Documentation = https://docs.pylonsproject.org/projects/hupper/en/latest/
+ Changelog = https://docs.pylonsproject.org/projects/hupper/en/latest/changes.html
+ Issue Tracker = https://github.com/Pylons/hupper/issues
+classifiers =
+ Development Status :: 5 - Production/Stable
+ Intended Audience :: Developers
+ License :: OSI Approved :: MIT License
+ Natural Language :: English
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Programming Language :: Python :: 3.10
+ Programming Language :: Python :: 3.11
+ Programming Language :: Python :: Implementation :: CPython
+ Programming Language :: Python :: Implementation :: PyPy
+
+[options]
+package_dir =
+ = src
+packages = find:
+zip_safe = False
+include_package_data = True
+python_requires = >=3.7
+
+[options.packages.find]
+where = src
+
+[options.entry_points]
+console_scripts =
+ hupper = hupper.cli:main
+
+[options.extras_require]
+docs =
+ watchdog
+ setuptools
+ Sphinx
+ pylons-sphinx-themes
+testing =
+ watchdog
+ pytest
+ pytest-cov
+ mock
[check-manifest]
+ignore-default-rules = true
ignore =
.gitignore
PKG-INFO
*.egg-info
*.egg-info/*
-ignore-default-rules = true
-
-[tool:pytest]
-python_files = test_*.py
-testpaths =
- src/hupper
- tests
[egg_info]
tag_build =
diff --git a/setup.py b/setup.py
index 7b254a3..6068493 100644
--- a/setup.py
+++ b/setup.py
@@ -1,51 +1,3 @@
-from setuptools import find_packages, setup
+from setuptools import setup
-
-def readfile(name):
- with open(name) as f:
- return f.read()
-
-
-readme = readfile('README.rst')
-changes = readfile('CHANGES.rst')
-
-docs_require = ['watchdog', 'Sphinx', 'pylons-sphinx-themes']
-
-tests_require = ['watchdog', 'pytest', 'pytest-cov', 'mock']
-
-setup(
- name='hupper',
- version='1.10.3',
- description=(
- 'Integrated process monitor for developing and reloading daemons.'
- ),
- long_description=readme + '\n\n' + changes,
- author='Michael Merickel',
- author_email='pylons-discuss@googlegroups.com',
- url='https://github.com/Pylons/hupper',
- license='MIT',
- packages=find_packages('src', exclude=['tests']),
- package_dir={'': 'src'},
- include_package_data=True,
- python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*',
- extras_require={'docs': docs_require, 'testing': tests_require},
- entry_points={"console_scripts": ["hupper = hupper.cli:main"]},
- zip_safe=False,
- keywords='server daemon autoreload reloader hup file watch process',
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: MIT License',
- 'Natural Language :: English',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- 'Programming Language :: Python :: Implementation :: CPython',
- 'Programming Language :: Python :: Implementation :: PyPy',
- ],
-)
+setup()
diff --git a/src/hupper.egg-info/PKG-INFO b/src/hupper.egg-info/PKG-INFO
index a362842..813a47d 100644
--- a/src/hupper.egg-info/PKG-INFO
+++ b/src/hupper.egg-info/PKG-INFO
@@ -1,431 +1,96 @@
Metadata-Version: 2.1
Name: hupper
-Version: 1.10.3
+Version: 1.12
Summary: Integrated process monitor for developing and reloading daemons.
Home-page: https://github.com/Pylons/hupper
Author: Michael Merickel
Author-email: pylons-discuss@googlegroups.com
License: MIT
-Description: ======
- hupper
- ======
-
- .. image:: https://img.shields.io/pypi/v/hupper.svg
- :target: https://pypi.python.org/pypi/hupper
-
- .. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20Linux/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+Linux%22
-
- .. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20MacOS/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+MacOS%22
-
- .. image:: https://github.com/Pylons/hupper/workflows/Build/test%20on%20Windows/badge.svg?branch=master
- :target: https://github.com/Pylons/hupper/actions?query=workflow%3A%22Build%2Ftest+on+Windows%22
-
- .. 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``.
-
-
- 1.10.3 (2021-05-13)
- ===================
-
- - Support Python 3.8 and 3.9.
-
- - Fix an issue with bare ``.pyc`` files in the source folder causing unhandled
- exceptions.
- See https://github.com/Pylons/hupper/pull/69
-
- - Fix issues with using the Watchman file monitor on versions newer than
- Watchman 4.9.0. This fix modifies ``hupper`` to use Watchman's
- ``watch-project`` capabilities which also support reading the
- ``.watchmanconfig`` file to control certain properties of the monitoring.
- See https://github.com/Pylons/hupper/pull/70
-
- 1.10.2 (2020-03-02)
- ===================
-
- - Fix a regression that caused SIGINT to not work properly in some situations.
- See https://github.com/Pylons/hupper/pull/67
-
- 1.10.1 (2020-02-18)
- ===================
-
- - Performance improvements when using Watchman.
-
- 1.10 (2020-02-18)
- =================
-
- - Handle a ``SIGTERM`` signal by forwarding it to the child process and
- gracefully waiting for it to exit. This should enable using ``hupper``
- from within docker containers and other systems that want to control
- the reloader process.
-
- Previously the ``SIGTERM`` would shutdown ``hupper`` immediately, stranding
- the worker and relying on it to shutdown on its own.
-
- See https://github.com/Pylons/hupper/pull/65
-
- - Avoid acquiring locks in the reloader process's signal handlers.
- See https://github.com/Pylons/hupper/pull/65
-
- - Fix deprecation warnings caused by using the ``imp`` module on newer
- versions of Python.
- See https://github.com/Pylons/hupper/pull/65
-
- 1.9.1 (2019-11-12)
- ==================
-
- - Support some scenarios in which user code is symlinked ``site-packages``.
- These were previously being ignored by the file monitor but should now
- be tracked.
- See https://github.com/Pylons/hupper/pull/61
-
- 1.9 (2019-10-14)
- ================
-
- - Support ``--shutdown-interval`` on the ``hupper`` CLI.
- See https://github.com/Pylons/hupper/pull/56
-
- - Support ``--reload-interval`` on the ``hupper`` CLI.
- See https://github.com/Pylons/hupper/pull/59
-
- - Do not choke when stdin is not a TTY while waiting for changes after a
- crash. For example, when running in Docker Compose.
- See https://github.com/Pylons/hupper/pull/58
-
- 1.8.1 (2019-06-12)
- ==================
-
- - Do not show the ``KeyboardInterrupt`` stacktrace when killing ``hupper``
- while waiting for a reload.
-
- 1.8 (2019-06-11)
- ================
-
- - If the worker process crashes, ``hupper`` can be forced to reload the worker
- by pressing the ``ENTER`` key in the terminal instead of waiting to change a
- file.
- See https://github.com/Pylons/hupper/pull/53
-
- 1.7 (2019-06-04)
- ================
-
- - On Python 3.5+ support recursive glob syntax in ``reloader.watch_files``.
- See https://github.com/Pylons/hupper/pull/52
-
- 1.6.1 (2019-03-11)
- ==================
-
- - If the worker crashes immediately, sometimes ``hupper`` would go into a
- restart loop instead of waiting for a code change.
- See https://github.com/Pylons/hupper/pull/50
-
- 1.6 (2019-03-06)
- ================
-
- - On systems that support ``SIGKILL`` and ``SIGTERM`` (not Windows), ``hupper``
- will now send a ``SIGKILL`` to the worker process as a last resort. Normally,
- a ``SIGINT`` (Ctrl-C) or ``SIGTERM`` (on reload) will kill the worker. If,
- within ``shutdown_interval`` seconds, the worker doesn't exit, it will
- receive a ``SIGKILL``.
- See https://github.com/Pylons/hupper/pull/48
-
- - Support a ``logger`` argument to ``hupper.start_reloader`` to override
- the default logger that outputs messages to ``sys.stderr``.
- See https://github.com/Pylons/hupper/pull/49
-
- 1.5 (2019-02-16)
- ================
-
- - Add support for ignoring custom patterns via the new ``ignore_files``
- option on ``hupper.start_reloader``. The ``hupper`` cli also supports
- ignoring files via the ``-x`` option.
- See https://github.com/Pylons/hupper/pull/46
-
- 1.4.2 (2018-11-26)
- ==================
-
- - Fix a bug prompting the "ignoring corrupted payload from watchman" message
- and placing the file monitor in an unrecoverable state when a change
- triggered a watchman message > 4096 bytes.
- See https://github.com/Pylons/hupper/pull/44
-
- 1.4.1 (2018-11-11)
- ==================
-
- - Stop ignoring a few paths that may not be system paths in cases where the
- virtualenv is the root of your project.
- See https://github.com/Pylons/hupper/pull/42
-
- 1.4 (2018-10-26)
- ================
-
- - Ignore changes to any system / installed files. This includes mostly
- changes to any files in the stdlib and ``site-packages``. Anything that is
- installed in editable mode or not installed at all will still be monitored.
- This drastically reduces the number of files that ``hupper`` needs to
- monitor.
- See https://github.com/Pylons/hupper/pull/40
-
- 1.3.1 (2018-10-05)
- ==================
-
- - Support Python 3.7.
-
- - Avoid a restart-loop if the app is failing to restart on certain systems.
- There was a race where ``hupper`` failed to detect that the app was
- crashing and thus fell into its restart logic when the user manually
- triggers an immediate reload.
- See https://github.com/Pylons/hupper/pull/37
-
- - Ignore corrupted packets coming from watchman that occur in semi-random
- scenarios. See https://github.com/Pylons/hupper/pull/38
-
- 1.3 (2018-05-21)
- ================
-
- - Added watchman support via ``hupper.watchman.WatchmanFileMonitor``.
- This is the new preferred file monitor on systems supporting unix sockets.
- See https://github.com/Pylons/hupper/pull/32
-
- - The ``hupper.watchdog.WatchdogFileMonitor`` will now output some info
- when it receives ulimit or other errors from ``watchdog``.
- See https://github.com/Pylons/hupper/pull/33
-
- - Allow ``-q`` and ``-v`` cli options to control verbosity.
- See https://github.com/Pylons/hupper/pull/33
-
- - Pass a ``logger`` value to the ``hupper.interfaces.IFileMonitorFactory``.
- This is an instance of ``hupper.interfaces.ILogger`` and can be used by
- file monitors to output errors and debug information.
- See https://github.com/Pylons/hupper/pull/33
-
- 1.2 (2018-05-01)
- ================
-
- - Track only Python source files. Previously ``hupper`` would track all pyc
- and py files. Now, if a pyc file is found then the equivalent source file
- is searched and, if found, the pyc file is ignored.
- See https://github.com/Pylons/hupper/pull/31
-
- - Allow overriding the default monitor lookup by specifying the
- ``HUPPER_DEFAULT_MONITOR`` environment variable as a Python dotted-path
- to a monitor factory. For example,
- ``HUPPER_DEFAULT_MONITOR=hupper.polling.PollingFileMonitor``.
- See https://github.com/Pylons/hupper/pull/29
-
- - Backward-incompatible changes to the
- ``hupper.interfaces.IFileMonitorFactory`` API to pass arbitrary kwargs
- to the factory.
- See https://github.com/Pylons/hupper/pull/29
-
- 1.1 (2018-03-29)
- ================
-
- - Support ``-w`` on the CLI to watch custom file paths.
- See https://github.com/Pylons/hupper/pull/28
-
- 1.0 (2017-05-18)
- ================
-
- - Copy ``sys.path`` to the worker process and ensure ``hupper`` is on the
- ``PYTHONPATH`` so that the subprocess can import it to start the worker.
- This fixes an issue with how ``zc.buildout`` injects dependencies into a
- process which is done entirely by ``sys.path`` manipulation.
- See https://github.com/Pylons/hupper/pull/27
-
- 0.5 (2017-05-10)
- ================
-
- - On non-windows systems ensure an exec occurs so that the worker does not
- share the same process space as the reloader causing certain code that
- is imported in both to not ever be reloaded. Under the hood this was a
- significant rewrite to use subprocess instead of multiprocessing.
- See https://github.com/Pylons/hupper/pull/23
-
- 0.4.4 (2017-03-10)
- ==================
-
- - Fix some versions of Windows which were failing to duplicate stdin to
- the subprocess and crashing.
- https://github.com/Pylons/hupper/pull/16
-
- 0.4.3 (2017-03-07)
- ==================
-
- - Fix pdb and other readline-based programs to operate properly.
- See https://github.com/Pylons/hupper/pull/15
-
- 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
+Project-URL: Documentation, https://docs.pylonsproject.org/projects/hupper/en/latest/
+Project-URL: Changelog, https://docs.pylonsproject.org/projects/hupper/en/latest/changes.html
+Project-URL: Issue Tracker, https://github.com/Pylons/hupper/issues
+Keywords: server,daemon,autoreload,reloader,hup,file,watch,process
Classifier: Development Status :: 5 - Production/Stable
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.5
-Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
-Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
+Requires-Python: >=3.7
+Description-Content-Type: text/x-rst
Provides-Extra: docs
Provides-Extra: testing
+License-File: LICENSE.txt
+
+======
+hupper
+======
+
+.. image:: https://img.shields.io/pypi/v/hupper.svg
+ :target: https://pypi.python.org/pypi/hupper
+
+.. image:: https://github.com/Pylons/hupper/actions/workflows/ci-tests.yml/badge.svg?branch=main
+ :target: https://github.com/Pylons/hupper/actions/workflows/ci-tests.yml?query=branch%3Amain
+
+.. 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``.
diff --git a/src/hupper.egg-info/SOURCES.txt b/src/hupper.egg-info/SOURCES.txt
index 0c60591..609a91a 100644
--- a/src/hupper.egg-info/SOURCES.txt
+++ b/src/hupper.egg-info/SOURCES.txt
@@ -7,10 +7,13 @@ LICENSE.txt
MANIFEST.in
README.rst
pyproject.toml
+pytest.ini
rtd.txt
setup.cfg
setup.py
tox.ini
+.github/dependabot.yml
+.github/workflows/ci-tests.yml
docs/Makefile
docs/api.rst
docs/changes.rst
@@ -21,7 +24,6 @@ docs/make.bat
docs/_static/.keep
src/hupper/__init__.py
src/hupper/cli.py
-src/hupper/compat.py
src/hupper/interfaces.py
src/hupper/ipc.py
src/hupper/logger.py
diff --git a/src/hupper.egg-info/entry_points.txt b/src/hupper.egg-info/entry_points.txt
index 024ef7f..732550c 100644
--- a/src/hupper.egg-info/entry_points.txt
+++ b/src/hupper.egg-info/entry_points.txt
@@ -1,3 +1,2 @@
[console_scripts]
hupper = hupper.cli:main
-
diff --git a/src/hupper.egg-info/requires.txt b/src/hupper.egg-info/requires.txt
index 4c88b51..ae7a63f 100644
--- a/src/hupper.egg-info/requires.txt
+++ b/src/hupper.egg-info/requires.txt
@@ -1,6 +1,7 @@
[docs]
watchdog
+setuptools
Sphinx
pylons-sphinx-themes
diff --git a/src/hupper/cli.py b/src/hupper/cli.py
index b6c0f6a..aa7d1e8 100644
--- a/src/hupper/cli.py
+++ b/src/hupper/cli.py
@@ -51,7 +51,7 @@ def main():
"hupper.cli.main",
verbose=level,
ignore_files=args.ignore,
- **reloader_kw
+ **reloader_kw,
)
sys.argv[1:] = unknown_args
diff --git a/src/hupper/compat.py b/src/hupper/compat.py
deleted file mode 100644
index 1e30d8b..0000000
--- a/src/hupper/compat.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# flake8: noqa
-import importlib
-import site
-import subprocess
-import sys
-import time
-
-PY2 = sys.version_info[0] == 2
-WIN = sys.platform == 'win32'
-
-
-try:
- from _thread import interrupt_main
-except ImportError:
- from thread import interrupt_main
-
-
-try:
- from importlib.util import source_from_cache as _source_from_cache
-except ImportError:
- try:
- # fallback on python < 3.5
- from imp import source_from_cache as _source_from_cache
- except ImportError:
- # fallback on python 2.x
- _source_from_cache = None
-
-
-def get_py_path(path):
- if _source_from_cache:
- try:
- return _source_from_cache(path)
- except ValueError:
- # fallback for solitary *.pyc files outside of __pycache__
- pass
-
- return path[:-1]
-
-
-try:
- import cPickle as pickle
-except ImportError:
- import pickle
-
-
-if PY2 or sys.version_info[1] < 5:
- from glob import glob as gg
-
- def glob(pathname, recursive=False):
- return gg(pathname)
-
-
-else:
- from glob import glob
-
-
-def get_site_packages(): # pragma: no cover
- try:
- paths = site.getsitepackages()
- if site.ENABLE_USER_SITE:
- paths.append(site.getusersitepackages())
- return paths
-
- # virtualenv does not ship with a getsitepackages impl so we fallback
- # to using distutils if we can
- # https://github.com/pypa/virtualenv/issues/355
- except Exception:
- try:
- from distutils.sysconfig import get_python_lib
-
- return [get_python_lib()]
-
- # just incase, don't fail here, it's not worth it
- except Exception:
- return []
-
-
-################################################
-# 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,), {})
-
-
-if PY2:
-
- def subprocess_wait_with_timeout(process, timeout):
- max_time = time.time() + timeout
- while process.poll() is None:
- dt = max_time - time.time()
- if dt <= 0:
- break
- if dt > 0.5:
- dt = 0.5
- time.sleep(dt)
- return process.poll()
-
-
-else:
-
- def subprocess_wait_with_timeout(process, timeout):
- try:
- return process.wait(timeout)
- except subprocess.TimeoutExpired:
- pass
diff --git a/src/hupper/interfaces.py b/src/hupper/interfaces.py
index 072e3cb..7803ea0 100644
--- a/src/hupper/interfaces.py
+++ b/src/hupper/interfaces.py
@@ -1,21 +1,20 @@
-import abc
+from abc import ABC, abstractmethod
-from .compat import with_metaclass
-
-class IReloaderProxy(with_metaclass(abc.ABCMeta)):
- @abc.abstractmethod
+class IReloaderProxy(ABC):
+ @abstractmethod
def watch_files(self, files):
- """ Signal to the monitor to track some custom paths."""
+ """Signal to the monitor to track some custom paths."""
- @abc.abstractmethod
+ @abstractmethod
def trigger_reload(self):
- """ Signal the monitor to execute a reload."""
+ """Signal the monitor to execute a reload."""
-class IFileMonitorFactory(with_metaclass(abc.ABCMeta)):
+class IFileMonitorFactory(ABC):
+ @abstractmethod
def __call__(self, callback, **kw):
- """ Return an :class:`.IFileMonitor` instance.
+ """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
@@ -32,37 +31,37 @@ class IFileMonitorFactory(with_metaclass(abc.ABCMeta)):
"""
-class IFileMonitor(with_metaclass(abc.ABCMeta)):
- @abc.abstractmethod
+class IFileMonitor(ABC):
+ @abstractmethod
def add_path(self, path):
- """ Start monitoring a new path."""
+ """Start monitoring a new path."""
- @abc.abstractmethod
+ @abstractmethod
def start(self):
- """ Start the monitor. This method should not block."""
+ """Start the monitor. This method should not block."""
- @abc.abstractmethod
+ @abstractmethod
def stop(self):
- """ Trigger the monitor to stop.
+ """Trigger the monitor to stop.
This should be called before invoking ``join``.
"""
- @abc.abstractmethod
+ @abstractmethod
def join(self):
- """ Block until the monitor has stopped."""
+ """Block until the monitor has stopped."""
-class ILogger(with_metaclass(abc.ABCMeta)):
- @abc.abstractmethod
+class ILogger(ABC):
+ @abstractmethod
def error(self, msg):
- """ Record an error message."""
+ """Record an error message."""
- @abc.abstractmethod
+ @abstractmethod
def info(self, msg):
- """ Record an informational message."""
+ """Record an informational message."""
- @abc.abstractmethod
+ @abstractmethod
def debug(self, msg):
- """ Record a debug-only message."""
+ """Record a debug-only message."""
diff --git a/src/hupper/ipc.py b/src/hupper/ipc.py
index 97e457b..cec1a85 100644
--- a/src/hupper/ipc.py
+++ b/src/hupper/ipc.py
@@ -1,15 +1,16 @@
import io
import os
+import pickle
import struct
import subprocess
import sys
import threading
-from .compat import WIN, pickle, subprocess_wait_with_timeout
-from .utils import is_stream_interactive, resolve_spec
+from .utils import WIN, is_stream_interactive, resolve_spec
if WIN: # pragma: no cover
import msvcrt
+
from . import winapi
class ProcessGroup(object):
@@ -33,7 +34,7 @@ if WIN: # pragma: no cover
try:
return winapi.AssignProcessToJobObject(self.h_job, hp)
except OSError as ex:
- if getattr(ex, 'winerror') == 5:
+ if getattr(ex, 'winerror', None) == 5:
# skip ACCESS_DENIED_ERROR on windows < 8 which occurs when
# the process is already attached to another job
pass
@@ -59,7 +60,6 @@ if WIN: # pragma: no cover
flags |= os.O_APPEND
return msvcrt.open_osfhandle(handle, flags)
-
else:
import fcntl
import termios
@@ -327,7 +327,10 @@ def wait(process, timeout=None):
if timeout == 0:
return process.poll()
- return subprocess_wait_with_timeout(process, timeout)
+ try:
+ return process.wait(timeout)
+ except subprocess.TimeoutExpired:
+ pass
def kill(process, soft=False):
diff --git a/src/hupper/polling.py b/src/hupper/polling.py
index ef36e89..6973fc2 100644
--- a/src/hupper/polling.py
+++ b/src/hupper/polling.py
@@ -58,6 +58,6 @@ def get_mtime(path):
stat = os.stat(path)
if stat:
return stat.st_mtime
- except (OSError, IOError): # pragma: no cover
+ except OSError: # pragma: no cover
pass
return 0
diff --git a/src/hupper/reloader.py b/src/hupper/reloader.py
index 558cbfc..bb38f13 100644
--- a/src/hupper/reloader.py
+++ b/src/hupper/reloader.py
@@ -1,6 +1,7 @@
from collections import deque
from contextlib import contextmanager
import fnmatch
+from glob import glob
import os
import re
import signal
@@ -8,10 +9,10 @@ import sys
import threading
import time
-from .compat import WIN, glob
from .ipc import ProcessGroup
from .logger import DefaultLogger, SilentLogger
from .utils import (
+ WIN,
default,
is_stream_interactive,
is_watchdog_supported,
@@ -132,21 +133,26 @@ class Reloader(object):
"""
Execute the reloader forever, blocking the current thread.
- This will invoke ``sys.exit(1)`` if interrupted.
+ This will invoke ``sys.exit`` with the return code from the
+ subprocess. If interrupted before the process starts then
+ it'll exit with ``-1``.
"""
+ exitcode = -1
with self._setup_runtime():
while True:
- result = self._run_worker()
- start = time.time()
- if result == WorkerResult.WAIT:
- result = self._wait_for_changes()
+ result, exitcode = self._run_worker()
if result == WorkerResult.EXIT:
break
+ start = time.time()
+ if result == WorkerResult.WAIT:
+ result, _ = self._wait_for_changes()
+ if result == WorkerResult.EXIT:
+ break
dt = self.reload_interval - (time.time() - start)
if dt > 0:
time.sleep(dt)
- sys.exit(1)
+ sys.exit(exitcode)
def run_once(self):
"""
@@ -154,9 +160,12 @@ class Reloader(object):
This method will return after the worker exits.
+ Returns the exit code from the worker process.
+
"""
with self._setup_runtime():
- self._run_worker()
+ _, exitcode = self._run_worker()
+ return exitcode
def _run_worker(self):
worker = Worker(
@@ -289,7 +298,8 @@ def _run_worker(self, worker, logger=None, shutdown_interval=None):
if worker.is_alive:
logger.info(
- 'Worker pipe died unexpectedly, triggering a reload.'
+ 'Worker pipe died unexpectedly, triggering a '
+ 'reload.'
)
result = WorkerResult.RELOAD
break
@@ -368,7 +378,7 @@ def _run_worker(self, worker, logger=None, shutdown_interval=None):
worker.join()
logger.debug('Server exited with code %d.' % worker.exitcode)
- return result
+ return result, worker.exitcode
def wait_main():
@@ -476,6 +486,11 @@ def start_reloader(
if shutdown_interval is default:
shutdown_interval = reload_interval
+ if reload_interval <= 0:
+ raise ValueError(
+ 'reload_interval must be greater than 0 to avoid spinning'
+ )
+
reloader = Reloader(
worker_path=worker_path,
worker_args=worker_args,
diff --git a/src/hupper/utils.py b/src/hupper/utils.py
index d8ccfb2..581ecd2 100644
--- a/src/hupper/utils.py
+++ b/src/hupper/utils.py
@@ -2,8 +2,9 @@ import importlib
import json
import os
import subprocess
+import sys
-from .compat import WIN
+WIN = sys.platform == 'win32'
class Sentinel(object):
@@ -25,7 +26,7 @@ def resolve_spec(spec):
def is_watchdog_supported():
- """ Return ``True`` if watchdog is available."""
+ """Return ``True`` if watchdog is available."""
try:
import watchdog # noqa: F401
except ImportError:
@@ -34,7 +35,7 @@ def is_watchdog_supported():
def is_watchman_supported():
- """ Return ``True`` if watchman is available."""
+ """Return ``True`` if watchman is available."""
if WIN:
# for now we aren't bothering with windows sockets
return False
@@ -47,7 +48,7 @@ def is_watchman_supported():
def get_watchman_sockpath(binpath='watchman'):
- """ Find the watchman socket or raise."""
+ """Find the watchman socket or raise."""
path = os.getenv('WATCHMAN_SOCK')
if path:
return path
diff --git a/src/hupper/watchdog.py b/src/hupper/watchdog.py
index 6511f6d..4c05305 100644
--- a/src/hupper/watchdog.py
+++ b/src/hupper/watchdog.py
@@ -33,7 +33,7 @@ class WatchdogFileMonitor(FileSystemEventHandler, Observer, IFileMonitor):
if dirpath not in self.dirpaths:
try:
self.schedule(self, dirpath)
- except (OSError, IOError) as ex: # pragma: no cover
+ except OSError as ex: # pragma: no cover
# watchdog raises exceptions if folders are missing
# or if the ulimit is passed
self.logger.error('watchdog error: ' + str(ex))
diff --git a/src/hupper/watchman.py b/src/hupper/watchman.py
index 12f9de9..858f0ef 100644
--- a/src/hupper/watchman.py
+++ b/src/hupper/watchman.py
@@ -6,7 +6,6 @@ import socket
import threading
import time
-from .compat import PY2
from .interfaces import IFileMonitor
from .utils import get_watchman_sockpath
@@ -27,7 +26,7 @@ class WatchmanFileMonitor(threading.Thread, IFileMonitor):
sockpath=None,
binpath='watchman',
timeout=1.0,
- **kw
+ **kw,
):
super(WatchmanFileMonitor, self).__init__()
self.callback = callback
@@ -158,9 +157,7 @@ class WatchmanFileMonitor(threading.Thread, IFileMonitor):
self._recvbufs.append(b)
def _recv(self):
- line = self._readline()
- if not PY2:
- line = line.decode('utf8')
+ line = self._readline().decode('utf8')
try:
return json.loads(line)
except Exception: # pragma: no cover
@@ -168,9 +165,7 @@ class WatchmanFileMonitor(threading.Thread, IFileMonitor):
return {}
def _send(self, msg):
- cmd = json.dumps(msg)
- if not PY2:
- cmd = cmd.encode('ascii')
+ cmd = json.dumps(msg).encode('ascii')
self._sock.sendall(cmd + b'\n')
def _query(self, msg, timeout=None):
diff --git a/src/hupper/worker.py b/src/hupper/worker.py
index 271e95b..3ce5d11 100644
--- a/src/hupper/worker.py
+++ b/src/hupper/worker.py
@@ -1,5 +1,8 @@
+from _thread import interrupt_main
+from importlib.util import source_from_cache
import os
import signal
+import site
import sys
import sysconfig
import threading
@@ -7,13 +10,12 @@ import time
import traceback
from . import ipc
-from .compat import get_py_path, get_site_packages, interrupt_main
from .interfaces import IReloaderProxy
from .utils import resolve_spec
class WatchSysModules(threading.Thread):
- """ Poll ``sys.modules`` for imported modules."""
+ """Poll ``sys.modules`` for imported modules."""
poll_interval = 1
ignore_system_paths = True
@@ -35,7 +37,7 @@ class WatchSysModules(threading.Thread):
self.stopped = True
def update_paths(self):
- """ Check sys.modules for paths to add to our path set."""
+ """Check sys.modules for paths to add to our path set."""
new_paths = []
with self.lock:
for path in expand_source_paths(iter_module_paths()):
@@ -46,10 +48,10 @@ class WatchSysModules(threading.Thread):
self.watch_paths(new_paths)
def search_traceback(self, tb):
- """ Inspect a traceback for new paths to add to our path set."""
+ """Inspect a traceback for new paths to add to our path set."""
new_paths = []
with self.lock:
- for filename, line, funcname, txt in traceback.extract_tb(tb):
+ for filename, *_ in traceback.extract_tb(tb):
path = os.path.abspath(filename)
if path not in self.paths:
self.paths.add(path)
@@ -73,6 +75,35 @@ class WatchSysModules(threading.Thread):
return False
+def get_py_path(path):
+ try:
+ return source_from_cache(path)
+ except ValueError:
+ # fallback for solitary *.pyc files outside of __pycache__
+ return path[:-1]
+
+
+def get_site_packages(): # pragma: no cover
+ try:
+ paths = site.getsitepackages()
+ if site.ENABLE_USER_SITE:
+ paths.append(site.getusersitepackages())
+ return paths
+
+ # virtualenv does not ship with a getsitepackages impl so we fallback
+ # to using distutils if we can
+ # https://github.com/pypa/virtualenv/issues/355
+ except Exception:
+ try:
+ from distutils.sysconfig import get_python_lib
+
+ return [get_python_lib()]
+
+ # just incase, don't fail here, it's not worth it
+ except Exception:
+ return []
+
+
def get_system_paths():
paths = get_site_packages()
for name in {'stdlib', 'platstdlib', 'platlib', 'purelib'}:
@@ -83,7 +114,7 @@ def get_system_paths():
def expand_source_paths(paths):
- """ Convert pyc files into their source equivalents."""
+ """Convert pyc files into their source equivalents."""
for src_path in paths:
# only track the source path if we can find it to avoid double-reloads
# when the source and the compiled path change because on some
@@ -96,7 +127,7 @@ def expand_source_paths(paths):
def iter_module_paths(modules=None):
- """ Yield paths of all imported modules."""
+ """Yield paths of all imported modules."""
modules = modules or list(sys.modules.values())
for module in modules:
try:
@@ -110,7 +141,7 @@ def iter_module_paths(modules=None):
class Worker(object):
- """ A helper object for managing a worker process lifecycle. """
+ """A helper object for managing a worker process lifecycle."""
def __init__(self, spec, args=None, kwargs=None):
super(Worker, self).__init__()
@@ -259,7 +290,8 @@ def worker_main(spec, pipe, spec_args=None, spec_kwargs=None):
raise
finally:
try:
- # attempt to send imported paths to the master prior to closing
+ # attempt to send imported paths to the reloader process prior to
+ # closing
poller.update_paths()
poller.stop()
poller.join()
diff --git a/tox.ini b/tox.ini
index 3807da5..833e93d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
[tox]
envlist =
lint,
- py27,py34,py35,py36,py37,py38,py39,pypy,pypy3,
+ py37,py38,py39,py310,py311,pypy3,
docs,coverage
isolated_build = true
@@ -30,7 +30,7 @@ setenv =
COVERAGE_FILE=.coverage
[testenv:docs]
-whitelist_externals =
+allowlist_externals =
make
commands =
make -C docs html BUILDDIR={envdir} SPHINXOPTS="-W -E"
@@ -38,24 +38,29 @@ extras =
docs
[testenv:lint]
-skip_install = true
+skip_install = True
commands =
- flake8 src/hupper/
- isort --check -rc src/hupper tests setup.py
+ isort --check-only --df src/hupper tests setup.py
black --check --diff src/hupper tests setup.py
- python setup.py check -r -s -m
+ flake8 src/hupper tests setup.py
check-manifest
+ # build sdist/wheel
+ python -m build .
+ twine check dist/*
deps =
black
+ build
check-manifest
flake8
+ flake8-bugbear
isort
readme_renderer
+ twine
[testenv:format]
skip_install = true
commands =
- isort -rc src/hupper tests setup.py
+ isort src/hupper tests setup.py
black src/hupper tests setup.py
deps =
black
@@ -65,12 +70,16 @@ deps =
skip_install = true
commands =
# clean up build/ and dist/ folders
- python -c 'import shutil; shutil.rmtree("dist", ignore_errors=True)'
- python setup.py clean --all
- # build sdist
- python setup.py sdist --dist-dir {toxinidir}/dist
- # build wheel from sdist
- pip wheel -v --no-deps --no-index --no-build-isolation --wheel-dir {toxinidir}/dist --find-links {toxinidir}/dist hupper
+ python -c 'import shutil; shutil.rmtree("build", ignore_errors=True)'
+ # Make sure we aren't forgetting anything
+ check-manifest
+ # build sdist/wheel
+ python -m build .
+ # Verify all is well
+ twine check dist/*
+
deps =
- setuptools
- wheel
+ build
+ check-manifest
+ readme_renderer
+ twine
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.12.egg-info/PKG-INFO -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.12.egg-info/dependency_links.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.12.egg-info/entry_points.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.12.egg-info/not-zip-safe -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.12.egg-info/requires.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.12.egg-info/top_level.txt
Files in first set of .debs but not in second
-rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.10.3.egg-info/PKG-INFO -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.10.3.egg-info/dependency_links.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.10.3.egg-info/entry_points.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.10.3.egg-info/not-zip-safe -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.10.3.egg-info/requires.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper-1.10.3.egg-info/top_level.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/hupper/compat.py
No differences were encountered in the control files