Hello community,

here is the log from the commit of package python-python-daemon for 
openSUSE:Factory checked in at 2017-10-21 20:21:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-python-daemon (Old)
 and      /work/SRC/openSUSE:Factory/.python-python-daemon.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-python-daemon"

Sat Oct 21 20:21:25 2017 rev:17 rq:533011 version:2.1.2

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-python-daemon/python-python-daemon.changes    
    2016-02-16 09:18:22.000000000 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-python-daemon.new/python-python-daemon.changes
   2017-10-21 20:21:28.179860568 +0200
@@ -1,0 +2,12 @@
+Tue Oct 10 13:18:27 UTC 2017 - [email protected]
+
+- singlespec auto-conversion
+- update requirements
+- use pytest as test runner
+- update to 2.1.2
+  * Ensure custom types are part of the Python type hierarchy.
+  * Raise a warning that the ‘runner’ module is pending deprecation.
+    This has been an unofficial example module from the beginning, and
+    it will be removed in a future version.
+
+-------------------------------------------------------------------
@@ -216,0 +229 @@
+

Old:
----
  python-daemon-2.1.1.tar.gz

New:
----
  python-daemon-2.1.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-python-daemon.spec ++++++
--- /var/tmp/diff_new_pack.oA8F1e/_old  2017-10-21 20:21:28.707835844 +0200
+++ /var/tmp/diff_new_pack.oA8F1e/_new  2017-10-21 20:21:28.711835657 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-python-daemon
 #
-# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,31 +16,35 @@
 #
 
 
+%define oldpython python
+%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-python-daemon
-Version:        2.1.1
+Version:        2.1.2
 Release:        0
-Url:            http://pypi.python.org/pypi/python-daemon/
 Summary:        Library to implement a well-behaved Unix daemon process
 License:        Apache-2.0 and GPL-3.0
 Group:          Development/Languages/Python
-Source:         
https://pypi.python.org/packages/source/p/python-daemon/python-daemon-%{version}.tar.gz
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-BuildRequires:  python-devel >= 2.7
-BuildRequires:  python-docutils
-BuildRequires:  python-lockfile >= 0.10
-BuildRequires:  python-mock >= 1.0
-BuildRequires:  python-setuptools
-BuildRequires:  python-testscenarios >= 0.4
-BuildRequires:  python-testtools
-BuildRequires:  python-unittest2 >= 0.6
+Url:            http://pypi.python.org/pypi/python-daemon/
+Source:         
https://files.pythonhosted.org/packages/source/p/python-daemon/python-daemon-%{version}.tar.gz
+BuildRequires:  %{python_module devel >= 2.7}
+BuildRequires:  %{python_module docutils}
+BuildRequires:  %{python_module lockfile >= 0.10}
+BuildRequires:  %{python_module mock >= 1.0}
+BuildRequires:  %{python_module pytest}
+BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module testscenarios >= 0.4}
+BuildRequires:  %{python_module testtools}
+BuildRequires:  %{python_module unittest2 >= 0.6}
+BuildRequires:  python-rpm-macros
+Requires:       python-docutils
 Requires:       python-lockfile >= 0.10
-Provides:       python-daemon = %{version}
-Obsoletes:      python-daemon < %{version}
-%if 0%{?suse_version} && 0%{?suse_version} <= 1110
-%{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%else
+BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildArch:      noarch
+%ifpython2
+Provides:       %{oldpython}-daemon = %{version}
+Obsoletes:      %{oldpython}-daemon < %{version}
 %endif
+%python_subpackages
 
 %description
 This library implements the well-behaved daemon specification of PEP 3143, 
"Standard daemon
@@ -54,15 +58,15 @@
 %setup -q -n python-daemon-%{version}
 
 %build
-python setup.py build
+%python_build
 
 %install
-python setup.py install --prefix=%{_prefix} --root=%{buildroot}
+%python_install
 
 %check
-python setup.py -q test
+%python_exec -m pytest test
 
-%files
+%files %{python_files}
 %defattr(-,root,root,-)
 %doc ChangeLog LICENSE.ASF-2 doc
 %{python_sitelib}/*

++++++ python-daemon-2.1.1.tar.gz -> python-daemon-2.1.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/ChangeLog 
new/python-daemon-2.1.2/ChangeLog
--- old/python-daemon-2.1.1/ChangeLog   2016-01-30 03:04:46.000000000 +0100
+++ new/python-daemon-2.1.2/ChangeLog   2016-10-26 12:08:37.000000000 +0200
@@ -1,9 +1,46 @@
+This document is the `change log`_ for this distribution. It is a
+record of all notable changes in each version released.
+
+Version strings conform to the `Semantic Versioning`_ specification,
+`version 2.0.0 <http://semver.org/spec/v2.0.0.html>`__.
+
+..  _change log: http://keepachangelog.com/
+..  _Semantic Versioning: https://semver.org/
+
+
+Version 2.1.2
+=============
+
+:Released: 2016-10-26
+:Maintainer: Ben Finney <[email protected]>
+
+Additions:
+
+* Add a README document for the code base.
+
+Changes:
+
+* Migrate code project hosting to Pagure.
+  Record the change of homepage URL in PyPI metadata.
+* Raise a warning that the ‘runner’ module is pending deprecation.
+  This has been an unofficial example module from the beginning, and
+  it will be removed in a future version.
+
+Bug Fixes:
+
+* Ensure custom types are part of the Python type hierarchy.
+* Avoid a circular dependency for the version string at install time.
+  Thanks to Maarten van Gompel for the reproducible test case.
+
+
 Version 2.1.1
 =============
 
 :Released: 2016-01-30
 :Maintainer: Ben Finney <[email protected]>
 
+Bug Fixes:
+
 * Default ‘initgroups’ option to False. Using ‘os.initgroups’ requires
   permission to set process GID, so this now needs to be explicitly
   requested.
@@ -15,6 +52,8 @@
 :Released: 2015-11-26
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
 * Add a DaemonContext option, ‘initgroups’, which specifies whether to
   set the daemon process's supplementary groups.
 * Set the process groups using ‘os.initgroups’.
@@ -28,9 +67,14 @@
 :Released: 2015-08-30
 :Maintainer: Ben Finney <[email protected]>
 
+Changes:
+
 * Lower dependency for ‘unittest2’, we can work with an earlier version.
 * Specify development status “Production/Stable” in Trove classifiers.
 * Migrate to ‘mock’ version 1.3 with corresponding API changes.
+
+Bug Fixes:
+
 * Use current Python concept of “basestring” to test for an attribute name.
   Thanks to Arthur de Jong for the bug report.
 
@@ -41,6 +85,8 @@
 :Released: 2015-02-02
 :Maintainer: Ben Finney <[email protected]>
 
+Bug Fixes:
+
 * Refine compatibility of exceptions for file operations.
 * Specify the text encoding when opening the changelog file.
 
@@ -51,7 +97,12 @@
 :Released: 2015-01-23
 :Maintainer: Ben Finney <[email protected]>
 
+Changes:
+
 * Record version info via Setuptools commands.
+
+Removals:
+
 * Remove the custom Setuptools entry points.
   This closes Alioth bug#314948.
 
@@ -62,11 +113,19 @@
 :Released: 2015-01-14
 :Maintainer: Ben Finney <[email protected]>
 
-* Break circular import dependency for ‘setup.py’.
+Changes:
+
 * Refactor all initial metadata functionality to ‘daemon._metadata’.
-* Distribute ‘version’ (and its tests) only in source, not install.
 * Build a “universal” (Python 2 and Python 3) wheel.
 
+Removals:
+
+* Distribute ‘version’ (and its tests) only in source, not install.
+
+Bug Fixes:
+
+* Break circular import dependency for ‘setup.py’.
+
 
 Version 2.0.2
 =============
@@ -74,11 +133,16 @@
 :Released: 2015-01-13
 :Maintainer: Ben Finney <[email protected]>
 
-* Declare test-time dependency on recent ‘unittest2’.
-* Declare packaging-time dependency on ‘docutils’ library.
+Additions:
+
 * Include unit tests for ‘version’ module with source distribution.
 * Record version info consistent with distribution metadata.
 
+Bug Fixes:
+
+* Declare test-time dependency on recent ‘unittest2’.
+* Declare packaging-time dependency on ‘docutils’ library.
+
 
 Version 2.0.1
 =============
@@ -86,6 +150,8 @@
 :Released: 2015-01-11
 :Maintainer: Ben Finney <[email protected]>
 
+Bug Fixes:
+
 * Include the ‘version’ module with source distribution.
 
 
@@ -95,6 +161,8 @@
 :Released: 2015-01-10
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
 * Support both Python 3 (version 3.2 or later) and Python 2 (version
   2.7 or later).
 * Document the API of all functions comprehensively in docstrings.
@@ -106,22 +174,19 @@
 * Preserve exception context in custom exceptions.
 
 * Declare compatibility with current Python versions.
-* Depend on Python 3 compatible libraries.
-* Update package homepage to Alioth hosted project page.
 * Use ‘pydoc.splitdoc’ to get package description text.
-* Remove ASCII translation of package description, not needed now the
-  docstring is a proper Unicode text value.
 * Include test suite with source distribution.
-* Move package metadata to ‘daemon/_metadata.py’.
-* Migrate to JSON (instead of Python) for serialised version info.
 * Add unit tests for metadata.
 * Store and retrieve version info in Setuptools metadata.
 
+Changes:
+
+* Depend on Python 3 compatible libraries.
+* Update package homepage to Alioth hosted project page.
 * Migrate to ‘str.format’ for interpolation of values into text.
 * Migrate to ‘mock’ library for mock objects in tests.
 * Migrate to ‘testscenarios’ library for unit test scenarios.
 * Migrate to ‘unittest2’ library for back-ported improvements.
-  Remove custom test suite creation.
 * Discriminate Python 2-and-3 compatible usage of dict methods.
 * Discriminate Python 2-and-3 compatible bytes versus text.
 * Declare explicit absolute and relative imports.
@@ -132,6 +197,14 @@
   compatibility.
 * Wrap function introspection for Python 3 compatibility.
 * Wrap standard library imports where names changed in Python 3.
+* Move package metadata to ‘daemon/_metadata.py’.
+* Migrate to JSON (instead of Python) for serialised version info.
+
+Removals:
+
+* Remove ASCII translation of package description, not needed now the
+  docstring is a proper Unicode text value.
+* Remove custom test suite creation.
 
 
 Version 1.6.1
@@ -140,17 +213,13 @@
 :Released: 2014-08-04
 :Maintainer: Ben Finney <[email protected]>
 
-* Use unambiguous “except FooType as foo” syntax.
-  This is to ease the port to Python 3, where the ambiguous comma
-  usage is an error.
-* Ensure a ‘basestring’ name bound to the base type for strings.
-  This is to allow checks to work on Python 2 and 3.
-* Specify versions of Python supported, as trove classifiers.
+Additions:
 
-* Update copyright notices.
 * Add editor hints for most files.
-* Distinguish continuation-line indentation versus block indentation.
 
+Changes:
+
+* Distinguish continuation-line indentation versus block indentation.
 * Use unicode literals by default, specifying bytes where necessary.
   This is to ease the port to Python 3, where the default string type
   is unicode.
@@ -161,6 +230,15 @@
 * Change license of library code to Apache License 2.0. Rationale at
   
<URL:http://wiki.python.org/moin/PythonSoftwareFoundationLicenseFaq#Contributing_Code_to_Python>.
 
+Bug Fixes:
+
+* Use unambiguous “except FooType as foo” syntax.
+  This is to ease the port to Python 3, where the ambiguous comma
+  usage is an error.
+* Ensure a ‘basestring’ name bound to the base type for strings.
+  This is to allow checks to work on Python 2 and 3.
+* Specify versions of Python supported, as trove classifiers.
+
 
 Version 1.6
 ===========
@@ -168,8 +246,21 @@
 :Released: 2010-05-10
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
+* FAQ: Add some entries and re-structure the document.
+* MANIFEST.in: Include the documentation in the distribution.
+
+Changes:
+
 * Use absolute imports to disambiguate provenance of names.
 * setup.py: Require ‘lockfile >=0.9’.
+
+* Use ‘unicode’ data type for all text values.
+* Prepare for Python 3 upgrade by tweaking some names and imports.
+
+Removals:
+
 * daemon/pidfile.py: Renamed from ‘daemon/pidlockfile.py’. Change
   references elsewhere to use this new name.
 * test/test_pidfile.py: Renamed from ‘test/test_pidlockfile.py’.
@@ -177,13 +268,6 @@
 * daemon/pidfile.py: Remove functionality now migrated to ‘lockfile’
   library.
 
-* FAQ: Add some entries and re-structure the document.
-
-* Use ‘unicode’ data type for all text values.
-* Prepare for Python 3 upgrade by tweaking some names and imports.
-
-* MANIFEST.in: Include the documentation in the distribution.
-
 
 Version 1.5.5
 =============
@@ -191,6 +275,8 @@
 :Released: 2010-03-02
 :Maintainer: Ben Finney <[email protected]>
 
+Bug Fixes:
+
 * Stop using ‘pkg_resources’ and revert to pre-1.5.3 version-string
   handling, until a better way that doesn't break everyone else's
   installation can be found.
@@ -202,6 +288,8 @@
 :Released: 2010-02-27
 :Maintainer: Ben Finney <[email protected]>
 
+Bug Fixes:
+
 * MANIFEST.in: Explicitly include version data file, otherwise
   everything breaks for users of the sdist.
 
@@ -212,17 +300,25 @@
 :Released: 2010-02-26
 :Maintainer: Ben Finney <[email protected]>
 
-* daemon/daemon.py: Invoke the pidfile context manager's ‘__exit__’
-  method with the correct arguments (as per
-  <URL:http://docs.python.org/library/stdtypes.html#typecontextmanager>).
-  Thanks to Ludvig Ericson for the bug report.
+Additions:
+
 * version: New plain-text data file to store project version string.
+* Add ‘pylint’ configuration for this project.
+
+Changes:
+
 * setup.py: Read version string from data file.
 * daemon/version/__init__.py: Query version string with ‘pkg_resources’.
 
-* Add ‘pylint’ configuration for this project.
 * Update copyright notices.
 
+Bug Fixes:
+
+* daemon/daemon.py: Invoke the pidfile context manager's ‘__exit__’
+  method with the correct arguments (as per
+  <URL:http://docs.python.org/library/stdtypes.html#typecontextmanager>).
+  Thanks to Ludvig Ericson for the bug report.
+
 
 Version 1.5.2
 =============
@@ -230,12 +326,16 @@
 :Released: 2009-10-24
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
+* Add initial Frequently Asked Questions document.
+
+Bug Fixes:
+
 * Ensure we only prevent core dumps if ‘prevent_core’ is true.
   Thanks to Denis Bilenko for reporting the lacking implementation of
   this documented option.
 
-* Add initial Frequently Asked Questions document.
-
 
 Version 1.5.1
 =============
@@ -243,6 +343,8 @@
 :Released: 2009-09-26
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
 * Make a separate collection of DaemonRunner test scenarios.
 * Handle a start request with a timeout on the PID file lock acquire.
 
@@ -257,19 +359,26 @@
 :Released: 2009-09-24
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
 * Make a separate collection of PIDLockFile test scenarios.
 
-* Raise specific errors on ‘DaemonRunner’ failures.
-* Distinguish different conditions on reading and parsing PID file.
+Changes:
+
 * Refactor code to ‘_terminate_daemon_process’ method.
 * Improve explanations in comments and docstrings.
 * Don't set pidfile at all if no path specified to constructor.
-* Write the PID file using correct OS locking and permissions.
-* Close the PID file after writing.
 * Implement ‘PIDLockFile’ as subclass of ‘lockfile.LinkFileLock’.
 * Remove redundant checks for file existence.
 
 * Manage the excluded file descriptors as a set (not a list).
+
+Bug Fixes:
+
+* Raise specific errors on ‘DaemonRunner’ failures.
+* Distinguish different conditions on reading and parsing PID file.
+* Write the PID file using correct OS locking and permissions.
+* Close the PID file after writing.
 * Only inspect the file descriptor of streams if they actually have
   one (via a ‘fileno’ method) when determining which file descriptors
   to close. Thanks to Ask Solem for revealing this bug.
@@ -281,15 +390,26 @@
 :Released: 2009-09-17
 :Maintainer: Ben Finney <[email protected]>
 
-* Remove child-exit signal (‘SIGCLD’, ‘SIGCHLD’) from default signal
-  map. Thanks to Joel Martin for pinpointing this issue.
+Additions:
+
 * Document requirement for ensuring any operating-system specific
   signal handlers are considered.
+* Add specific license terms for unit test suite scaffold.
+
+Changes:
+
 * Refactor ‘fork_then_exit_parent’ functionality to avoid duplicate
   code.
+
+Removals:
+
 * Remove redundant imports.
 * Remove unused code from unit test suite scaffold.
-* Add specific license terms for unit test suite scaffold.
+
+Bug Fixes:
+
+* Remove child-exit signal (‘SIGCLD’, ‘SIGCHLD’) from default signal
+  map. Thanks to Joel Martin for pinpointing this issue.
 
 
 Version 1.4.7
@@ -298,9 +418,14 @@
 :Released: 2009-09-03
 :Maintainer: Ben Finney <[email protected]>
 
-* Fix keywords argument for distribution setup.
+Removals:
+
 * Exclude ‘test’ package from distribution installation.
 
+Bug Fixes:
+
+* Fix keywords argument for distribution setup.
+
 
 Version 1.4.6
 =============
@@ -308,6 +433,8 @@
 :Released: 2009-06-21
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
 * Update documentation for changes from latest PEP 3143 revision.
 * Implement DaemonContext.is_open method.
 
@@ -318,13 +445,18 @@
 :Released: 2009-05-17
 :Maintainer: Ben Finney <[email protected]>
 
-* Register DaemonContext.close method for atexit processing.
-* Move PID file cleanup to close method.
+Additions:
+
 * Improve docstrings by reference to, and copy from, PEP 3143.
 * Use mock checking capabilities of newer ‘MiniMock’ library.
 * Automate building a versioned distribution tarball.
 * Include developer documentation files in source distribution.
 
+Bug Fixes:
+
+* Register DaemonContext.close method for atexit processing.
+* Move PID file cleanup to close method.
+
 
 Version 1.4.4
 =============
@@ -332,12 +464,17 @@
 :Released: 2009-03-26
 :Maintainer: Ben Finney <[email protected]>
 
+Changes:
+
 * Conform to current PEP version, now released as PEP 3143 “Standard
   daemon process library”.
+* Redirect standard streams to null device by default.
+
+Bug Fixes:
+
 * Ensure UID and GID are set in correct order.
 * Delay closing all open files until just before re-binding standard
   streams.
-* Redirect standard streams to null device by default.
 
 
 Version 1.4.3
@@ -346,6 +483,8 @@
 :Released: 2009-03-19
 :Maintainer: Ben Finney <[email protected]>
 
+Bug Fixes:
+
 * Close the PID file context on exit.
 
 
@@ -355,6 +494,8 @@
 :Released: 2009-03-18
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
 * Context manager methods for DaemonContext.
 
 
@@ -364,6 +505,8 @@
 :Released: 2009-03-18
 :Maintainer: Ben Finney <[email protected]>
 
+Changes:
+
 * Improvements to docstrings.
 * Further conformance with draft PEP.
 
@@ -374,9 +517,14 @@
 :Released: 2009-03-17
 :Maintainer: Ben Finney <[email protected]>
 
-* Implement the interface from a draft PEP for process daemonisation.
+Additions:
+
 * Complete statement coverage from unit test suite.
 
+Changes:
+
+* Implement the interface from a draft PEP for process daemonisation.
+
 
 Version 1.3
 ===========
@@ -384,10 +532,18 @@
 :Released: 2009-03-12
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
+* Huge increase in unit test suite.
+
+Changes:
+
 * Separate controller (now ‘DaemonRunner’) from daemon process
   context (now ‘DaemonContext’).
+
+Bug Fixes:
+
 * Fix many corner cases and bugs.
-* Huge increase in unit test suite.
 
 
 Version 1.2
@@ -396,13 +552,25 @@
 :Released: 2009-01-27
 :Maintainer: Ben Finney <[email protected]>
 
+Additions:
+
+* Begin unit test suite.
+
+Changes:
+
 * Initial release of this project forked from ‘bda.daemon’. Thanks,
   Robert Niederreiter.
 * Refactor some functionality out to helper functions.
-* Begin unit test suite.
 
 
 ..
+    This document is written using `reStructuredText`_ markup, and can
+    be rendered with `Docutils`_ to other formats.
+
+    ..  _Docutils: http://docutils.sourceforge.net/
+    ..  _reStructuredText: http://docutils.sourceforge.net/rst.html
+
+..
     This is free software: you may copy, modify, and/or distribute this work
     under the terms of the Apache License version 2.0 as published by the
     Apache Software Foundation.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/PKG-INFO 
new/python-daemon-2.1.2/PKG-INFO
--- old/python-daemon-2.1.1/PKG-INFO    2016-01-30 03:06:58.000000000 +0100
+++ new/python-daemon-2.1.2/PKG-INFO    2016-10-26 12:09:22.000000000 +0200
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: python-daemon
-Version: 2.1.1
+Version: 2.1.2
 Summary: Library to implement a well-behaved Unix daemon process.
-Home-page: https://alioth.debian.org/projects/python-daemon/
+Home-page: https://pagure.io/python-daemon/
 Author: Ben Finney
 Author-email: [email protected]
 License: Apache-2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/README 
new/python-daemon-2.1.2/README
--- old/python-daemon-2.1.1/README      1970-01-01 01:00:00.000000000 +0100
+++ new/python-daemon-2.1.2/README      2016-10-22 06:32:04.000000000 +0200
@@ -0,0 +1,61 @@
+#############
+python-daemon
+#############
+
+Library to implement a well-behaved Unix daemon process
+#######################################################
+
+This library implements the well-behaved daemon specification of
+:pep:`3143`, “Standard daemon process library”.
+
+A well-behaved Unix daemon process is tricky to get right, but the
+required steps are much the same for every daemon program. A
+`DaemonContext` instance holds the behaviour and configured process
+environment for the program; use the instance as a context manager to
+enter a daemon state.
+
+Simple example of usage::
+
+    import daemon
+
+    from spam import do_main_program
+
+    with daemon.DaemonContext():
+        do_main_program()
+
+Customisation of the steps to become a daemon is available by setting
+options on the `DaemonContext` instance; see the documentation for
+that class for each option.
+
+
+Copying
+=======
+
+This work, ‘python-daemon’, is free software: you may copy, modify,
+and/or distribute this work under certain conditions; see the relevant
+files for specific grant of license. No warranty expressed or implied.
+
+* Parts of this work are licensed to you under the terms of the GNU
+  General Public License as published by the Free Software Foundation;
+  version 3 of that license or any later version.
+  See the file ‘LICENSE.GPL-3’ for details.
+
+* Parts of this work are licensed to you under the terms of the Apache
+  License, version 2.0 as published by the Apache Software Foundation.
+  See the file ‘LICENSE.ASF-2’ for details.
+
+
+..
+    This document is written using `reStructuredText`_ markup, and can
+    be rendered with `Docutils`_ to other formats.
+
+    ..  _Docutils: http://docutils.sourceforge.net/
+    ..  _reStructuredText: http://docutils.sourceforge.net/rst.html
+
+..
+    Local variables:
+    coding: utf-8
+    mode: text
+    mode: rst
+    End:
+    vim: fileencoding=utf-8 filetype=rst :
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/daemon/_metadata.py 
new/python-daemon-2.1.2/daemon/_metadata.py
--- old/python-daemon-2.1.1/daemon/_metadata.py 2016-01-30 03:01:02.000000000 
+0100
+++ new/python-daemon-2.1.2/daemon/_metadata.py 2016-10-21 14:57:20.000000000 
+0200
@@ -15,16 +15,17 @@
 from __future__ import (absolute_import, unicode_literals)
 
 import json
-import re
-import collections
 import datetime
 
 import pkg_resources
 
+__metaclass__ = type
+
 
 distribution_name = "python-daemon"
 version_info_filename = "version_info.json"
 
+
 def get_distribution_version_info(filename=version_info_filename):
     """ Get the version info from the installed distribution.
 
@@ -48,8 +49,8 @@
         distribution = None
 
     if distribution is not None:
-        if distribution.has_metadata(version_info_filename):
-            content = distribution.get_metadata(version_info_filename)
+        if distribution.has_metadata(filename):
+            content = distribution.get_metadata(filename)
             version_info = json.loads(content)
 
     return version_info
@@ -59,34 +60,6 @@
 version_installed = version_info['version']
 
 
-rfc822_person_regex = re.compile(
-        "^(?P<name>[^<]+) <(?P<email>[^>]+)>$")
-
-ParsedPerson = collections.namedtuple('ParsedPerson', ['name', 'email'])
-
-def parse_person_field(value):
-    """ Parse a person field into name and email address.
-
-        :param value: The text value specifying a person.
-        :return: A 2-tuple (name, email) for the person's details.
-
-        If the `value` does not match a standard person with email
-        address, the `email` item is ``None``.
-
-        """
-    result = (None, None)
-
-    match = rfc822_person_regex.match(value)
-    if len(value):
-        if match is not None:
-            result = ParsedPerson(
-                    name=match.group('name'),
-                    email=match.group('email'))
-        else:
-            result = ParsedPerson(name=value, email=None)
-
-    return result    
-
 author_name = "Ben Finney"
 author_email = "[email protected]"
 author = "{name} <{email}>".format(name=author_name, email=author_email)
@@ -142,7 +115,7 @@
 copyright = "Copyright © {year_range} {author} and others".format(
         year_range=copyright_year_range, author=author)
 license = "Apache-2"
-url = "https://alioth.debian.org/projects/python-daemon/";
+url = "https://pagure.io/python-daemon/";
 
 
 # Local variables:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/daemon/daemon.py 
new/python-daemon-2.1.2/daemon/daemon.py
--- old/python-daemon-2.1.1/daemon/daemon.py    2016-01-30 03:02:20.000000000 
+0100
+++ new/python-daemon-2.1.2/daemon/daemon.py    2016-10-26 12:08:06.000000000 
+0200
@@ -37,6 +37,8 @@
     basestring = str
     unicode = str
 
+__metaclass__ = type
+
 
 class DaemonError(Exception):
     """ Base exception class for errors from this module. """
@@ -238,8 +240,6 @@
 
         """
 
-    __metaclass__ = type
-
     def __init__(
             self,
             chroot_directory=None,
@@ -840,14 +840,16 @@
         of ``MAXFD`` is returned.
 
         """
-    limits = resource.getrlimit(resource.RLIMIT_NOFILE)
-    result = limits[1]
-    if result == resource.RLIM_INFINITY:
+    (__, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE)
+
+    result = hard_limit
+    if hard_limit == resource.RLIM_INFINITY:
         result = MAXFD
+
     return result
 
 
-def close_all_open_files(exclude=set()):
+def close_all_open_files(exclude=None):
     """ Close all open file descriptors.
 
         :param exclude: Collection of file descriptors to skip when closing
@@ -859,6 +861,8 @@
         close.
 
         """
+    if exclude is None:
+        exclude = set()
     maxfd = get_maximum_file_descriptors()
     for fd in reversed(range(maxfd)):
         if fd not in exclude:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/daemon/runner.py 
new/python-daemon-2.1.2/daemon/runner.py
--- old/python-daemon-2.1.1/daemon/runner.py    2016-01-30 03:01:02.000000000 
+0100
+++ new/python-daemon-2.1.2/daemon/runner.py    2016-10-26 11:55:44.000000000 
+0200
@@ -19,10 +19,19 @@
 
 from __future__ import (absolute_import, unicode_literals)
 
-import sys
+import errno
 import os
 import signal
-import errno
+import sys
+import warnings
+
+import lockfile
+
+from . import pidfile
+from .daemon import (basestring, unicode)
+from .daemon import DaemonContext
+from .daemon import _chain_exception_from_existing_exception_context
+
 try:
     # Python 3 standard library.
     ProcessLookupError
@@ -30,12 +39,12 @@
     # No such class in Python 2.
     ProcessLookupError = NotImplemented
 
-import lockfile
+__metaclass__ = type
 
-from . import pidfile
-from .daemon import (basestring, unicode)
-from .daemon import DaemonContext
-from .daemon import _chain_exception_from_existing_exception_context
+
+warnings.warn(
+        "The ‘runner’ module is not a supported API for this library.",
+        PendingDeprecationWarning)
 
 
 class DaemonRunnerError(Exception):
@@ -77,8 +86,6 @@
 
         """
 
-    __metaclass__ = type
-
     start_message = "started with pid {pid:d}"
 
     def __init__(self, app):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/doc/hacking.txt 
new/python-daemon-2.1.2/doc/hacking.txt
--- old/python-daemon-2.1.1/doc/hacking.txt     2015-09-27 03:14:46.000000000 
+0200
+++ new/python-daemon-2.1.2/doc/hacking.txt     2016-10-22 04:03:18.000000000 
+0200
@@ -2,7 +2,26 @@
 #################
 
 :Author: Ben Finney <[email protected]>
-:Updated: 2015-09-27
+:Updated: 2016-10-21
+
+
+VCS repository
+==============
+
+The official Version Control System (VCS) for this code base is the
+Git repository at `the ‘python-daemon’ Pagure project`_.
+
+You can submit your proposed changes as merge requests:
+
+* Use your Pagure account and use the “pull request” feature.
+
+* Subscribe to `the ‘python-daemon-devel’ discussion forum`_ and
+  direct us to a branch in your published fork.
+
+
+..  _the ‘python-daemon’ Pagure project: https://pagure.io/python-daemon/
+..  _the ‘python-daemon-devel’ discussion forum:
+    https://lists.alioth.debian.org/mailman/listinfo/python-daemon-devel
 
 
 Project layout
@@ -84,7 +103,7 @@
   * The first line is a one-line synopsis of the object. This summary
     line appears on the same line as the opening triple-quote,
     separated by a single space.
-  
+
   * Further lines, if needed, are separated from the first by one
     blank line.
 
@@ -97,7 +116,7 @@
     field names are: “param foo” for each parameter (where “foo” is
     the parameter name), and “return” for the return value. The field
     values describe the purpose of each.
-  
+
   * The closing triple-quote appears on a separate line.
 
   Example::
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/python_daemon.egg-info/PKG-INFO 
new/python-daemon-2.1.2/python_daemon.egg-info/PKG-INFO
--- old/python-daemon-2.1.1/python_daemon.egg-info/PKG-INFO     2016-01-30 
03:06:44.000000000 +0100
+++ new/python-daemon-2.1.2/python_daemon.egg-info/PKG-INFO     2016-10-26 
12:09:22.000000000 +0200
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: python-daemon
-Version: 2.1.1
+Version: 2.1.2
 Summary: Library to implement a well-behaved Unix daemon process.
-Home-page: https://alioth.debian.org/projects/python-daemon/
+Home-page: https://pagure.io/python-daemon/
 Author: Ben Finney
 Author-email: [email protected]
 License: Apache-2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-daemon-2.1.1/python_daemon.egg-info/SOURCES.txt 
new/python-daemon-2.1.2/python_daemon.egg-info/SOURCES.txt
--- old/python-daemon-2.1.1/python_daemon.egg-info/SOURCES.txt  2016-01-30 
03:06:44.000000000 +0100
+++ new/python-daemon-2.1.2/python_daemon.egg-info/SOURCES.txt  2016-10-26 
12:09:22.000000000 +0200
@@ -2,6 +2,7 @@
 LICENSE.ASF-2
 LICENSE.GPL-3
 MANIFEST.in
+README
 setup.cfg
 setup.py
 test_version.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-daemon-2.1.1/python_daemon.egg-info/version_info.json 
new/python-daemon-2.1.2/python_daemon.egg-info/version_info.json
--- old/python-daemon-2.1.1/python_daemon.egg-info/version_info.json    
2016-01-30 03:06:44.000000000 +0100
+++ new/python-daemon-2.1.2/python_daemon.egg-info/version_info.json    
2016-10-26 12:09:22.000000000 +0200
@@ -1,6 +1,6 @@
 {
-    "release_date": "2016-01-30",
-    "version": "2.1.1",
+    "release_date": "2016-10-26",
+    "version": "2.1.2",
     "maintainer": "Ben Finney <[email protected]>",
-    "body": "* Default \u2018initgroups\u2019 option to False. Using 
\u2018os.initgroups\u2019 requires\n  permission to set process GID, so this 
now needs to be explicitly requested.\n"
+    "body": "Additions:* Add a README document for the code base.\nChanges:* 
Migrate code project hosting to Pagure. Record the change of homepage URL in\n  
PyPI metadata.\n* Raise a warning that the \u2018runner\u2019 module is pending 
deprecation. This has been\n  an unofficial example module from the beginning, 
and it will be removed in a\n  future version.\nBug Fixes:* Ensure custom types 
are part of the Python type hierarchy.\n* Avoid a circular dependency for the 
version string at install time. Thanks to\n  Maarten van Gompel for the 
reproducible test case.\n"
 }
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/setup.cfg 
new/python-daemon-2.1.2/setup.cfg
--- old/python-daemon-2.1.1/setup.cfg   2016-01-30 03:06:58.000000000 +0100
+++ new/python-daemon-2.1.2/setup.cfg   2016-10-26 12:09:22.000000000 +0200
@@ -8,7 +8,7 @@
 sign = true
 
 [egg_info]
-tag_svn_revision = 0
-tag_date = 0
 tag_build = 
+tag_date = 0
+tag_svn_revision = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/setup.py 
new/python-daemon-2.1.2/setup.py
--- old/python-daemon-2.1.1/setup.py    2016-01-30 03:01:02.000000000 +0100
+++ new/python-daemon-2.1.2/setup.py    2016-10-22 07:03:04.000000000 +0200
@@ -16,10 +16,7 @@
 from __future__ import (absolute_import, unicode_literals)
 
 import sys
-import os
-import os.path
 import pydoc
-import distutils.util
 
 from setuptools import (setup, find_packages)
 
@@ -41,16 +38,10 @@
 
 (synopsis, long_description) = pydoc.splitdoc(pydoc.getdoc(main_module))
 
-version_info = metadata.get_distribution_version_info()
-version_string = version_info['version']
-
-(maintainer_name, maintainer_email) = metadata.parse_person_field(
-        version_info['maintainer'])
-
 
 setup(
+        distclass=version.ChangelogAwareDistribution,
         name=metadata.distribution_name,
-        version=version_string,
         packages=find_packages(exclude=["test"]),
         cmdclass={
             "write_version_info": version.WriteVersionInfoCommand,
@@ -58,8 +49,6 @@
             },
 
         # Setuptools metadata.
-        maintainer=maintainer_name,
-        maintainer_email=maintainer_email,
         zip_safe=False,
         setup_requires=[
             "docutils",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/test/test_daemon.py 
new/python-daemon-2.1.2/test/test_daemon.py
--- old/python-daemon-2.1.1/test/test_daemon.py 2016-01-30 03:02:20.000000000 
+0100
+++ new/python-daemon-2.1.2/test/test_daemon.py 2016-10-21 14:57:20.000000000 
+0200
@@ -20,18 +20,13 @@
 import pwd
 import tempfile
 import resource
+import io
 import errno
 import signal
 import socket
 from types import ModuleType
 import collections
 import functools
-try:
-    # Standard library of Python 2.7 and later.
-    from io import StringIO
-except ImportError:
-    # Standard library of Python 2.6 and earlier.
-    from StringIO import StringIO
 
 import mock
 
@@ -744,16 +739,9 @@
         instance = self.test_instance
         instance.files_preserve = list(self.test_files.values())
         stream_files = self.stream_files_by_name
-        mock_fileno_method = mock.MagicMock(
-                spec=sys.__stdin__.fileno,
-                side_effect=ValueError)
         expected_result = self.test_file_descriptors.copy()
         for (pseudo_stream_name, pseudo_stream) in stream_files.items():
-            test_non_fd_stream = StringIO()
-            if not hasattr(test_non_fd_stream, 'fileno'):
-                # Python < 3 StringIO doesn't have ‘fileno’ at all.
-                # Add a method which raises an exception.
-                test_non_fd_stream.fileno = mock_fileno_method
+            test_non_fd_stream = io.StringIO()
             setattr(instance, pseudo_stream_name, test_non_fd_stream)
             stream_fd = pseudo_stream.fileno()
             expected_result.discard(stream_fd)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/test/test_metadata.py 
new/python-daemon-2.1.2/test/test_metadata.py
--- old/python-daemon-2.1.1/test/test_metadata.py       2016-01-30 
03:01:02.000000000 +0100
+++ new/python-daemon-2.1.2/test/test_metadata.py       2016-10-21 
14:57:20.000000000 +0200
@@ -15,7 +15,6 @@
 
 from __future__ import (absolute_import, unicode_literals)
 
-import sys
 import errno
 import re
 try:
@@ -32,10 +31,9 @@
 import mock
 import testtools.helpers
 import testtools.matchers
-import testscenarios
 
 from . import scaffold
-from .scaffold import (basestring, unicode)
+from .scaffold import unicode
 
 import daemon._metadata as metadata
 
@@ -106,40 +104,6 @@
                 instance, HasAttribute(self.ducktype_attribute_name))
 
 
-class parse_person_field_TestCase(
-        testscenarios.WithScenarios, testtools.TestCase):
-    """ Test cases for ‘get_latest_version’ function. """
-
-    scenarios = [
-            ('simple', {
-                'test_person': "Foo Bar <[email protected]>",
-                'expected_result': ("Foo Bar", "[email protected]"),
-                }),
-            ('empty', {
-                'test_person': "",
-                'expected_result': (None, None),
-                }),
-            ('none', {
-                'test_person': None,
-                'expected_error': TypeError,
-                }),
-            ('no email', {
-                'test_person': "Foo Bar",
-                'expected_result': ("Foo Bar", None),
-                }),
-            ]
-
-    def test_returns_expected_result(self):
-        """ Should return expected result. """
-        if hasattr(self, 'expected_error'):
-            self.assertRaises(
-                    self.expected_error,
-                    metadata.parse_person_field, self.test_person)
-        else:
-            result = metadata.parse_person_field(self.test_person)
-            self.assertEqual(self.expected_result, result)
-
-
 class YearRange_TestCase(scaffold.TestCaseWithScenarios):
     """ Test cases for ‘YearRange’ class. """
 
@@ -266,7 +230,7 @@
 def fake_func_has_metadata(testcase, resource_name):
     """ Fake the behaviour of ‘pkg_resources.Distribution.has_metadata’. """
     if (
-            resource_name != testcase.expected_resource_name
+            resource_name != testcase.version_info_filename
             or not hasattr(testcase, 'test_version_info')):
         return False
     return True
@@ -319,10 +283,12 @@
                 'expected_version_info': {'version': "1.0"},
                 }),
             ('file lorem_ipsum.json', {
+                'test_filename': "lorem_ipsum.json",
                 'version_info_filename': "lorem_ipsum.json",
                 'test_version_info': json.dumps({
                     'version': "1.0",
                     }),
+                'expected_resource_name': "lorem_ipsum.json",
                 'expected_version_info': {'version': "1.0"},
                 }),
             ('not installed', {
@@ -332,16 +298,28 @@
             ('no version_info', {
                 'expected_version_info': default_version_info,
                 }),
+            ('wrong filename', {
+                'test_filename': "lorem_ipsum.json",
+                'test_version_info': json.dumps({
+                    'version': "1.0",
+                    }),
+                'expected_resource_name': "lorem_ipsum.json",
+                'expected_version_info': default_version_info,
+                }),
             ]
 
     def setUp(self):
         """ Set up test fixtures. """
         super(get_distribution_version_info_TestCase, self).setUp()
 
-        if hasattr(self, 'expected_resource_name'):
-            self.test_args = {'filename': self.expected_resource_name}
-        else:
-            self.test_args = {}
+        self.test_args = {}
+        if hasattr(self, 'test_filename'):
+            self.test_args['filename'] = self.test_filename
+
+        if not hasattr(self, 'version_info_filename'):
+            self.version_info_filename = version_info_filename
+
+        if not hasattr(self, 'expected_resource_name'):
             self.expected_resource_name = version_info_filename
 
         self.mock_distribution = mock.MagicMock()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/test/test_pidfile.py 
new/python-daemon-2.1.2/test/test_pidfile.py
--- old/python-daemon-2.1.1/test/test_pidfile.py        2016-01-30 
03:01:02.000000000 +0100
+++ new/python-daemon-2.1.2/test/test_pidfile.py        2016-10-21 
14:57:20.000000000 +0200
@@ -24,14 +24,9 @@
 import os
 import itertools
 import tempfile
+import io
 import errno
 import functools
-try:
-    # Standard library of Python 2.7 and later.
-    from io import StringIO
-except ImportError:
-    # Standard library of Python 2.6 and earlier.
-    from StringIO import StringIO
 
 import mock
 import lockfile
@@ -41,7 +36,7 @@
 import daemon.pidfile
 
 
-class FakeFileDescriptorStringIO(StringIO, object):
+class FakeFileDescriptorStringIO(io.StringIO, object):
     """ A StringIO class that fakes a file descriptor. """
 
     _fileno_generator = itertools.count()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/test_version.py 
new/python-daemon-2.1.2/test_version.py
--- old/python-daemon-2.1.1/test_version.py     2016-01-30 03:01:02.000000000 
+0100
+++ new/python-daemon-2.1.2/test_version.py     2016-10-22 07:09:24.000000000 
+0200
@@ -19,7 +19,6 @@
 import io
 import errno
 import functools
-import contextlib
 import collections
 import textwrap
 import json
@@ -28,12 +27,6 @@
 import distutils.cmd
 import distutils.errors
 import distutils.fancy_getopt
-try:
-    # Standard library of Python 2.7 and later.
-    from io import StringIO
-except ImportError:
-    # Standard library of Python 2.6 and earlier.
-    from StringIO import StringIO
 
 import mock
 import testtools
@@ -52,6 +45,8 @@
         version.__dict__, str('VersionInfoTranslator'),
         docutils.nodes.SparseNodeVisitor)
 
+__metaclass__ = type
+
 
 def make_test_classes_for_ensure_class_bases_begin_with():
     """ Make test classes for use with ‘ensure_class_bases_begin_with’.
@@ -250,6 +245,40 @@
         self.assertEqual(expected_output, instance.output)
 
 
+class parse_person_field_TestCase(
+        testscenarios.WithScenarios, testtools.TestCase):
+    """ Test cases for ‘get_latest_version’ function. """
+
+    scenarios = [
+            ('simple', {
+                'test_person': "Foo Bar <[email protected]>",
+                'expected_result': ("Foo Bar", "[email protected]"),
+                }),
+            ('empty', {
+                'test_person': "",
+                'expected_result': (None, None),
+                }),
+            ('none', {
+                'test_person': None,
+                'expected_error': TypeError,
+                }),
+            ('no email', {
+                'test_person': "Foo Bar",
+                'expected_result': ("Foo Bar", None),
+                }),
+            ]
+
+    def test_returns_expected_result(self):
+        """ Should return expected result. """
+        if hasattr(self, 'expected_error'):
+            self.assertRaises(
+                    self.expected_error,
+                    version.parse_person_field, self.test_person)
+        else:
+            result = version.parse_person_field(self.test_person)
+            self.assertEqual(self.expected_result, result)
+
+
 class NoOpContextManager:
     """ A context manager with no effect. """
     def __enter__(self): pass
@@ -753,7 +782,7 @@
 
     def test_returns_expected_version_info(self):
         """ Should return expected version info mapping. """
-        infile = StringIO(self.test_input)
+        infile = io.StringIO(self.test_input)
         with self.expected_error_context():
             result = version.changelog_to_version_info_collection(infile)
         if hasattr(self, 'expected_version_info'):
@@ -781,7 +810,7 @@
 
     fake_open_side_effects = {
             'success': (
-                lambda *args, **kwargs: StringIO()),
+                lambda *args, **kwargs: io.StringIO()),
             'file not found': FileNotFoundError(),
             'permission denied': PermissionError(),
             }
@@ -816,7 +845,7 @@
                 else:
                     raise side_effect
             else:
-                result = StringIO()
+                result = io.StringIO()
             return result
 
         func_patcher_io_open = mock.patch.object(
@@ -1244,7 +1273,7 @@
         if hasattr(self, 'changelog_path'):
             self.fake_changelog_file_path = self.changelog_path
         version.get_changelog_path.return_value = self.fake_changelog_file_path
-        self.fake_changelog_file = StringIO()
+        self.fake_changelog_file = io.StringIO()
 
         def fake_os_path_exists(path):
             if path == self.fake_changelog_file_path:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-daemon-2.1.1/version.py 
new/python-daemon-2.1.2/version.py
--- old/python-daemon-2.1.1/version.py  2016-01-30 03:01:02.000000000 +0100
+++ new/python-daemon-2.1.2/version.py  2016-10-22 07:09:24.000000000 +0200
@@ -32,7 +32,6 @@
 import sys
 import os
 import io
-import errno
 import json
 import datetime
 import textwrap
@@ -42,7 +41,12 @@
 import distutils
 import distutils.errors
 import distutils.cmd
+import distutils.dist
 import distutils.version
+
+import setuptools
+import setuptools.command.egg_info
+
 try:
     # Python 2 has both ‘str’ (bytes) and ‘unicode’ (text).
     basestring = basestring
@@ -52,8 +56,7 @@
     basestring = str
     unicode = str
 
-import setuptools
-import setuptools.command.egg_info
+__metaclass__ = type
 
 
 def ensure_class_bases_begin_with(namespace, class_name, base_class):
@@ -117,10 +120,36 @@
         self.document.walkabout(visitor)
         self.output = visitor.astext()
 
-
+
 rfc822_person_regex = re.compile(
         "^(?P<name>[^<]+) <(?P<email>[^>]+)>$")
 
+ParsedPerson = collections.namedtuple('ParsedPerson', ['name', 'email'])
+
+def parse_person_field(value):
+    """ Parse a person field into name and email address.
+
+        :param value: The text value specifying a person.
+        :return: A 2-tuple (name, email) for the person's details.
+
+        If the `value` does not match a standard person with email
+        address, the `email` item is ``None``.
+
+        """
+    result = ParsedPerson(None, None)
+
+    match = rfc822_person_regex.match(value)
+    if len(value):
+        if match is not None:
+            result = ParsedPerson(
+                    name=match.group('name'),
+                    email=match.group('email'))
+        else:
+            result = ParsedPerson(name=value, email=None)
+
+    return result
+
+
 class ChangeLogEntry:
     """ An individual entry from the ‘ChangeLog’ document. """
 
@@ -228,6 +257,22 @@
 class InvalidFormatError(ValueError):
     """ Raised when the document is not a valid ‘ChangeLog’ document. """
 
+    def __init__(self, node, message=None):
+        self.node = node
+        self.message = message
+
+    def __str__(self):
+        text = "{message}: {source} line {line:d}".format(
+                message=(
+                    getattr(self, 'message', "(no message)")),
+                source=(
+                    getattr(self.node, 'source', "(source unknown)")),
+                line=(
+                    getattr(self.node, 'line', "(unknown)")),
+                )
+
+        return text
+
 
 class VersionInfoTranslator(object):
     """ Translator from document nodes to a version info stream. """
@@ -254,7 +299,6 @@
     def __init__(self, document):
         super(VersionInfoTranslator, self).__init__(document)
         self.settings = document.settings
-        self.current_section_level = 0
         self.current_field_name = None
         self.content = []
         self.indent_width = 0
@@ -295,8 +339,18 @@
         field_list_node = node.parent.parent
         if not isinstance(field_list_node, self._docutils.nodes.field_list):
             raise InvalidFormatError(
+                    node,
                     "Unexpected field within {node!r}".format(
                         node=field_list_node))
+        if not isinstance(
+                field_list_node.parent, self._docutils.nodes.section):
+            # Field list is not in a section.
+            raise self._docutils.nodes.SkipNode
+        if not self.current_field_name in self.attr_convert_funcs_by_attr_name:
+            raise InvalidFormatError(
+                    node,
+                    "Unexpected field name {name!r}".format(
+                        name=self.current_field_name))
         (attr_name, convert_func) = self.attr_convert_funcs_by_attr_name[
                 self.current_field_name]
         attr_value = convert_func(node.astext())
@@ -314,12 +368,20 @@
 
     def visit_field_name(self, node):
         field_name = node.astext()
-        if self.current_section_level == 1:
-            # At a top-level section.
-            if field_name.lower() not in ["released", "maintainer"]:
-                raise InvalidFormatError(
-                        "Unexpected field name 
{name!r}".format(name=field_name))
-            self.current_field_name = field_name.lower()
+        self.current_field_name = field_name.lower()
+        field_list_node = node.parent
+        if not isinstance(
+                field_list_node.parent, self._docutils.nodes.section):
+            # Field list is not in a section.
+            raise self._docutils.nodes.SkipNode
+        if not isinstance(
+                field_list_node.parent.parent, self._docutils.nodes.Root):
+            # The section is not top-level.
+            raise self._docutils.nodes.SkipNode
+        if field_name.lower() not in ["released", "maintainer"]:
+            raise InvalidFormatError(
+                    node,
+                    "Unexpected field name {name!r}".format(name=field_name))
 
     def depart_field_name(self, node):
         pass
@@ -348,16 +410,12 @@
         self.append_to_current_entry("\n")
 
     def visit_section(self, node):
-        self.current_section_level += 1
-        if self.current_section_level == 1:
-            # At a top-level section.
-            self.current_entry = ChangeLogEntry()
-        else:
+        if not isinstance(node.parent, self._docutils.nodes.Root):
             raise InvalidFormatError(
-                    "Subsections not implemented for this writer")
+                    node, "Subsections not implemented for this writer")
+        self.current_entry = ChangeLogEntry()
 
     def depart_section(self, node):
-        self.current_section_level -= 1
         self.content.append(
                 self.current_entry.as_version_info_entry())
         self.current_entry = None
@@ -366,14 +424,15 @@
 
     def depart_title(self, node):
         title_text = node.astext()
-        # At a top-level section.
         words = title_text.split(" ")
         version = None
         if len(words) != self._expected_title_word_length:
             raise InvalidFormatError(
+                    node,
                     "Unexpected title text {text!r}".format(text=title_text))
         if words[0].lower() not in ["version"]:
             raise InvalidFormatError(
+                    node,
                     "Unexpected title text {text!r}".format(text=title_text))
         version = words[-1]
         self.current_entry.version = version
@@ -563,6 +622,52 @@
         self.write_file("version info", self.outfile_path, content)
 
 
+class ChangelogAwareDistribution(distutils.dist.Distribution, object):
+    """ A distribution of Python code for installation.
+
+        This class gets the following attributes instead from the
+        ‘ChangeLog’ document:
+
+        * version
+        * maintainer
+        * maintainer_email
+
+        """
+
+    __metaclass__ = type
+
+    def __init__(self, *args, **kwargs):
+        super(ChangelogAwareDistribution, self).__init__(*args, **kwargs)
+
+        # Undo the per-instance delegation for these methods.
+        del (
+                self.get_version,
+                self.get_maintainer,
+                self.get_maintainer_email,
+                )
+
+    @lru_cache(maxsize=128)
+    def get_version_info(self):
+        changelog_path = get_changelog_path(self)
+        version_info = generate_version_info_from_changelog(changelog_path)
+        return version_info
+
+    def get_version(self):
+        version_info = self.get_version_info()
+        version_string = version_info['version']
+        return version_string
+
+    def get_maintainer(self):
+        version_info = self.get_version_info()
+        person = parse_person_field(version_info['maintainer'])
+        return person.name
+
+    def get_maintainer_email(self):
+        version_info = self.get_version_info()
+        person = parse_person_field(version_info['maintainer'])
+        return person.email
+
+
 # Local variables:
 # coding: utf-8
 # mode: python


Reply via email to