Hello community,

here is the log from the commit of package python3-gnupg for openSUSE:Factory 
checked in at 2017-02-09 11:15:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-gnupg (Old)
 and      /work/SRC/openSUSE:Factory/.python3-gnupg.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-gnupg"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-gnupg/python3-gnupg.changes      
2016-09-21 18:49:00.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python3-gnupg.new/python3-gnupg.changes 
2017-02-09 11:15:10.610790801 +0100
@@ -1,0 +2,18 @@
+Fri Feb  3 03:28:05 UTC 2017 - [email protected]
+
+- specfile:
+  * update copyright year
+
+- update to version 0.4.0:
+  * Added support for KEY_CONSIDERED in more places - encryption /
+    decryption, signing, key generation and key import.
+  * Partial fix for #32 (GPG 2.1 compatibility). Unfortunately, better
+    support cannot be provided at this point, unless there are certain
+    changes (relating to pinentry popups) in how GPG 2.1 works.
+  * Fixed #60: An IndexError was being thrown by scan_keys().
+  * Ensured that utf-8 encoding is used when the --with-column mode is
+    used. Thanks to Yann Leboulanger for the patch.
+  * list_keys() now uses --fixed-list-mode. Thanks to Werner Koch for
+    the pointer.
+
+-------------------------------------------------------------------

Old:
----
  python-gnupg-0.3.9.tar.gz

New:
----
  python-gnupg-0.4.0.tar.gz

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

Other differences:
------------------
++++++ python3-gnupg.spec ++++++
--- /var/tmp/diff_new_pack.3187Tp/_old  2017-02-09 11:15:11.230703232 +0100
+++ /var/tmp/diff_new_pack.3187Tp/_new  2017-02-09 11:15:11.234702666 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python3-gnupg
 #
-# Copyright (c) 2016 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
@@ -17,7 +17,7 @@
 
 
 Name:           python3-gnupg
-Version:        0.3.9
+Version:        0.4.0
 Release:        0
 Url:            https://bitbucket.org/vinay.sajip/python-gnupg
 Summary:        A wrapper for the Gnu Privacy Guard (GPG or GnuPG)

++++++ python-gnupg-0.3.9.tar.gz -> python-gnupg-0.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.9/PKG-INFO 
new/python-gnupg-0.4.0/PKG-INFO
--- old/python-gnupg-0.3.9/PKG-INFO     2016-09-10 09:41:21.000000000 +0200
+++ new/python-gnupg-0.4.0/PKG-INFO     2017-01-29 19:30:36.000000000 +0100
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: python-gnupg
-Version: 0.3.9
+Version: 0.4.0
 Summary: A wrapper for the Gnu Privacy Guard (GPG or GnuPG)
-Home-page: http://packages.python.org/python-gnupg/index.html
+Home-page: http://pythonhosted.org/python-gnupg/index.html
 Author: Vinay Sajip
 Author-email: [email protected]
-License: Copyright (C) 2008-2016 by Vinay Sajip. All Rights Reserved. See 
LICENSE.txt for license.
-Download-URL: 
https://pypi.python.org/packages/source/p/python-gnupg/python-gnupg-0.3.9.tar.gz
+License: Copyright (C) 2008-2017 by Vinay Sajip. All Rights Reserved. See 
LICENSE.txt for license.
+Download-URL: 
https://pypi.io/packages/source/p/python-gnupg/python-gnupg-0.4.0.tar.gz
 Description: This module allows easy access to GnuPG's key management, 
encryption and signature functionality from Python programs. It is intended for 
use with Python 2.4 or greater.
 Platform: No particular restrictions
 Classifier: Development Status :: 5 - Production/Stable
@@ -23,5 +23,6 @@
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
 Classifier: Operating System :: OS Independent
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.9/README.rst 
new/python-gnupg-0.4.0/README.rst
--- old/python-gnupg-0.3.9/README.rst   2016-09-10 09:37:53.000000000 +0200
+++ new/python-gnupg-0.4.0/README.rst   2017-01-29 18:15:10.000000000 +0100
@@ -1,353 +1,375 @@
-.. image:: https://travis-ci.org/vsajip/python-gnupg.svg
-   :target: https://travis-ci.org/vsajip/python-gnupg
-
-.. image:: https://coveralls.io/repos/vsajip/python-gnupg/badge.svg
-   :target: https://coveralls.io/github/vsajip/python-gnupg
-
-
-What is it?
-===========
-
-The GNU Privacy Guard (gpg, or gpg.exe on Windows) is a command-line program
-which provides support for programmatic access via spawning a separate process
-to run it and then communicating with that process from your program.
-
-This project, ``python-gnupg``, implements a Python library which takes care
-of the internal details and allows its users to generate and manage keys,
-encrypt and decrypt data, and sign and verify messages.
-
-Installation
-============
-
-Installing from PyPI
---------------------
-
-You can install this package from the Python Package Index (pyPI) by running::
-
-    pip install python-gnupg
-
-
-Installing from a source distribution archive
----------------------------------------------
-To install this package from a source distribution archive, do the following:
-
-1. Extract all the files in the distribution archive to some directory on your
-   system.
-2. In that directory, run ``python setup.py install``.
-3. Optionally, run ``python test_gnupg.py`` to ensure that the package is
-   working as expected.
-
-Credits
-=======
-
-* The developers of the GNU Privacy Guard.
-* The original version of this module was developed by Andrew Kuchling.
-* It was improved by Richard Jones.
-* It was further improved by Steve Traugott.
-
-The present incarnation, based on the earlier versions, uses the ``subprocess``
-module and so works on Windows as well as Unix/Linux platforms. It's not,
-however, 100% backwards-compatible with earlier incarnations.
-
-Change log
-==========
-
-N.B: GCnn refers to an issue nn on Google Code.
-
-0.4.0 (future)
---------------
-
-Released: Not yet
-
-0.3.9
------
-
-Released: 2016-09-10
-
-* Fixed #38: You can now request information about signatures against
-  keys. Thanks to SunDwarf for the suggestion and patch, which was used
-  as a basis for this change.
-
-* Fixed #49: When exporting keys, no attempt is made to decode the output when
-  armor=False is specified.
-
-* Fixed #53: A ``FAILURE`` message caused by passing an incorrect passphrase
-  is handled.
-
-* Handled ``EXPORTED`` and ``EXPORT_RES`` messages while exporting keys. Thanks
-  to Marcel Pörner for the patch.
-
-* Fixed #54: Improved error message shown when gpg is not available.
-
-* Fixed #55: Added support for ``KEY_CONSIDERED`` while verifying.
-
-* Avoided encoding problems with filenames under Windows. Thanks to Kévin
-  Bernard-Allies for the patch.
-
-* Fixed #57: Used a better mechanism for comparing keys.
-
-
-0.3.8
------
-
-Released: 2015-09-24
-
-* Fixed #22: handled ``PROGRESS`` messages during verification and signing.
-
-* Fixed #26: handled ``PINENTRY_LAUNCHED`` messages during verification,
-  decryption and key generation.
-
-* Fixed #28: Allowed a default Name-Email to be computed even when neither of
-  ``LOGNAME`` and ``USERNAME`` are in the environment.
-
-* Fixed #29: Included test files missing from the tarball in previous versions.
-
-* Fixed #39: On Python 3.x, passing a text instead of a binary stream caused
-  file decryption to hang due to a ``UnicodeDecodeError``. This has now been
-  correctly handled: The decryption fails with a "no data" status.
-
-* Fixed #41: Handled Unicode filenames correctly by encoding them on 2.x using
-  the file system encoding.
-
-* Fixed #43: handled ``PINENTRY_LAUNCHED`` messages during key export. Thanks
-  to Ian Denhardt for looking into this.
-
-* Hide the console window which appears on Windows when gpg is spawned.
-  Thanks to Kévin Bernard-Allies for the patch.
-
-* Subkey fingerprints are now captured.
-
-* The returned value from the ``list_keys`` method now has a new attribute,
-  ``key_map``, which is a dictionary mapping key and subkey fingerprints to
-  the corresponding key's dictionary. With this change, you don't need to
-  iterate over the (potentially large) returned list to search for a key with
-  a given fingerprint - the ``key_map`` dict will take you straight to the key
-  info, whether the fingerprint you have is for a key or a subkey. Thanks to
-  Nick Daly for the initial suggestion.
-
-0.3.7
------
-
-Released: 2014-12-07
-
-Signed with PGP key: Vinay Sajip (CODE SIGNING KEY) <[email protected]>
-
-Key Fingerprint    : CA74 9061 914E AC13 8E66 EADB 9147 B477 339A 9B86
-
-* Added an ``output`` keyword parameter to the ``sign`` and
-  ``sign_file`` methods, to allow writing the signature to a file.
-  Thanks to Jannis Leidel for the patch.
-
-* Allowed specifying ``True`` for the ``sign`` keyword parameter,
-  which allows use of the default key for signing and avoids having to
-  specify a key id when it's desired to use the default. Thanks to
-  Fabian Beutel for the patch.
-
-* Used a uniform approach with subprocess on Windows and POSIX: shell=True
-  is not used on either.
-
-* When signing/verifying, the status is updated to reflect any expired or
-  revoked keys or signatures.
-
-* Handled 'NOTATION_NAME' and 'NOTATION_DATA' during verification.
-
-* Fixed #1, #16, #18, #20: Quoting approach changed, since now shell=False.
-
-* Fixed #14: Handled 'NEED_PASSPHRASE_PIN' message.
-
-* Fixed #8: Added a scan_keys method to allow scanning of keys without the
-  need to import into a keyring. Thanks to Venzen Khaosan for the suggestion.
-
-* Fixed #5: Added '0x' prefix when searching for keys. Thanks to Aaron Toponce
-  for the report.
-
-* Fixed #4: Handled 'PROGRESS' message during encryption. Thanks to Daniel
-  Mills for the report.
-
-* Fixed #3: Changed default encoding to Latin-1.
-
-* Fixed #2: Raised ValueError if no recipients were specified
-  for an asymmetric encryption request.
-
-* Handled 'UNEXPECTED' message during verification. Thanks to
-  David Andersen for the patch.
-
-* Replaced old range(len(X)) idiom with enumerate().
-
-* Refactored ``ListKeys`` / ``SearchKeys`` classes to maximise use of common
-  functions.
-
-* Fixed GC94: Added ``export-minimal`` and ``armor`` options when exporting
-  keys. This addition was inadvertently left out of 0.3.6.
-
-0.3.6
------
-
-Released: 2014-02-05
-
-* Fixed GC82: Enabled fast random tests on gpg as well as gpg2.
-* Fixed GC85: Avoided deleting temporary file to preserve its permissions.
-* Fixed GC87: Avoided writing passphrase to log.
-* Fixed GC95: Added ``verify_data()`` method to allow verification of
-  signatures in memory.
-* Fixed GC96: Regularised end-of-line characters.
-* Fixed GC98: Rectified problems with earlier fix for shell injection.
-
-0.3.5
------
-
-Released: 2013-08-30
-
-* Added improved shell quoting to guard against shell injection.
-* Fixed GC76: Added ``search_keys()`` and ``send_keys()`` methods.
-* Fixed GC77: Allowed specifying a symmetric cipher algorithm.
-* Fixed GC78: Fell back to utf-8 encoding when no other could be determined.
-* Fixed GC79: Default key length is now 2048 bits.
-* Fixed GC80: Removed the Name-Comment default in key generation.
-
-0.3.4
------
-
-Released: 2013-06-05
-
-* Fixed GC65: Fixed encoding exception when getting version.
-* Fixed GC66: Now accepts sets and frozensets where appropriate.
-* Fixed GC67: Hash algorithm now captured in sign result.
-* Fixed GC68: Added support for ``--secret-keyring``.
-* Fixed GC70: Added support for multiple keyrings.
-
-0.3.3
------
-
-Released: 2013-03-11
-
-* Fixed GC57: Handled control characters in ``list_keys()``.
-* Fixed GC61: Enabled fast random for testing.
-* Fixed GC62: Handled ``KEYEXPIRED`` status.
-* Fixed GC63: Handled ``NO_SGNR`` status.
-
-0.3.2
------
-
-Released: 2013-01-17
-
-* Fixed GC56: Disallowed blank values in key generation.
-* Fixed GC57: Handled colons and other characters in ``list_keys()``.
-* Fixed GC59/GC60: Handled ``INV_SGNR`` status during verification and removed
-  calls requiring interactive password input from doctests.
-
-0.3.1
------
-
-Released: 2012-09-01
-
-* Fixed GC45: Allowed additional arguments to gpg executable.
-* Fixed GC50: Used latin-1 encoding in tests when it's known to be required.
-* Fixed GC51: Test now returns non-zero exit status on test failure.
-* Fixed GC53: Now handles ``INV_SGNR`` and ``KEY_NOT_CREATED`` statuses.
-* Fixed GC55: Verification and decryption now return trust level of signer in
-  integer and text form.
-
-0.3.0
------
-
-Released: 2012-05-12
-
-* Fixed GC49: Reinstated Yann Leboulanger's change to support subkeys
-  (accidentally left out in 0.2.7).
-
-0.2.9
------
-
-Released: 2012-03-29
-
-* Fixed GC36: Now handles ``CARDCTRL`` and ``POLICY_URL`` messages.
-* Fixed GC40: Now handles ``DECRYPTION_INFO``, ``DECRYPTION_FAILED`` and
-  ``DECRYPTION_OKAY`` messages.
-* The ``random_binary_data file`` is no longer shipped, but constructed by the
-  test suite if needed.
-
-0.2.8
------
-
-Released: 2011-09-02
-
-* Fixed GC29: Now handles ``IMPORT_RES`` while verifying.
-* Fixed GC30: Fixed an encoding problem.
-* Fixed GC33: Quoted arguments for added safety.
-
-0.2.7
------
-
-Released: 2011-04-10
-
-* Fixed GC24: License is clarified as BSD.
-* Fixed GC25: Incorporated Daniel Folkinshteyn's changes.
-* Fixed GC26: Incorporated Yann Leboulanger's subkey change.
-* Fixed GC27: Incorporated hysterix's support for symmetric encryption.
-* Did some internal cleanups of Unicode handling.
-
-0.2.6
------
-
-Released: 2011-01-25
-
-* Fixed GC14: Should be able to accept passphrases from GPG-Agent.
-* Fixed GC19: Should be able to create a detached signature.
-* Fixed GC21/GC23: Better handling of less common responses from GPG.
-
-0.2.5
------
-
-Released: 2010-10-13
-
-* Fixed GC11/GC16: Detached signatures can now be created.
-* Fixed GC3: Detached signatures can be verified.
-* Fixed GC12: Better support for RSA and IDEA.
-* Fixed GC15/GC17: Better support for non-ASCII input.
-
-0.2.4
------
-
-Released: 2010-03-01
-
-* Fixed GC9: Now allows encryption without armor and the ability to encrypt
-  and decrypt directly to/from files.
-
-0.2.3
------
-
-Released: 2010-01-07
-
-* Fixed GC7: Made sending data to process threaded and added a test case.
-  With a test data file used by the test case, the archive size has gone up
-  to 5MB (the size of the test file).
-
-0.2.2
------
-
-Released: 2009-10-06
-
-* Fixed GC5/GC6: Added ``--batch`` when specifying ``--passphrase-fd`` and
-  changed the name of the distribution file to add the ``python-`` prefix.
-
-0.2.1
------
-
-Released: 2009-08-07
-
-* Fixed GC2: Added ``handle_status()`` method to the ``ListKeys`` class.
-
-0.2.0
------
-
-Released: 2009-07-16
-
-* Various changes made to support Python 3.0.
-
-0.1.0
------
-
-Released: 2009-07-04
-
-* Initial release.
+.. image:: https://travis-ci.org/vsajip/python-gnupg.svg
+   :target: https://travis-ci.org/vsajip/python-gnupg
+
+.. image:: https://coveralls.io/repos/vsajip/python-gnupg/badge.svg
+   :target: https://coveralls.io/github/vsajip/python-gnupg
+
+
+What is it?
+===========
+
+The GNU Privacy Guard (gpg, or gpg.exe on Windows) is a command-line program
+which provides support for programmatic access via spawning a separate process
+to run it and then communicating with that process from your program.
+
+This project, ``python-gnupg``, implements a Python library which takes care
+of the internal details and allows its users to generate and manage keys,
+encrypt and decrypt data, and sign and verify messages.
+
+Installation
+============
+
+Installing from PyPI
+--------------------
+
+You can install this package from the Python Package Index (pyPI) by running::
+
+    pip install python-gnupg
+
+
+Installing from a source distribution archive
+---------------------------------------------
+To install this package from a source distribution archive, do the following:
+
+1. Extract all the files in the distribution archive to some directory on your
+   system.
+2. In that directory, run ``python setup.py install``.
+3. Optionally, run ``python test_gnupg.py`` to ensure that the package is
+   working as expected.
+
+Credits
+=======
+
+* The developers of the GNU Privacy Guard.
+* The original version of this module was developed by Andrew Kuchling.
+* It was improved by Richard Jones.
+* It was further improved by Steve Traugott.
+
+The present incarnation, based on the earlier versions, uses the ``subprocess``
+module and so works on Windows as well as Unix/Linux platforms. It's not,
+however, 100% backwards-compatible with earlier incarnations.
+
+Change log
+==========
+
+N.B: GCnn refers to an issue nn on Google Code.
+
+0.4.1 (future)
+--------------
+
+Released: Not yet.
+
+
+0.4.0
+-----
+
+Released: 2017-01-29
+
+* Added support for ``KEY_CONSIDERED`` in more places - encryption /
+  decryption, signing, key generation and key import.
+
+* Partial fix for #32 (GPG 2.1 compatibility). Unfortunately, better
+  support cannot be provided at this point, unless there are certain
+  changes (relating to pinentry popups) in how GPG 2.1 works.
+
+* Fixed #60: An IndexError was being thrown by ``scan_keys()``.
+
+* Ensured that utf-8 encoding is used when the ``--with-column`` mode is
+  used. Thanks to Yann Leboulanger for the patch.
+
+* ``list_keys()`` now uses ``--fixed-list-mode``. Thanks to Werner Koch
+  for the pointer.
+
+
+0.3.9
+-----
+
+Released: 2016-09-10
+
+* Fixed #38: You can now request information about signatures against
+  keys. Thanks to SunDwarf for the suggestion and patch, which was used
+  as a basis for this change.
+
+* Fixed #49: When exporting keys, no attempt is made to decode the output when
+  armor=False is specified.
+
+* Fixed #53: A ``FAILURE`` message caused by passing an incorrect passphrase
+  is handled.
+
+* Handled ``EXPORTED`` and ``EXPORT_RES`` messages while exporting keys. Thanks
+  to Marcel Pörner for the patch.
+
+* Fixed #54: Improved error message shown when gpg is not available.
+
+* Fixed #55: Added support for ``KEY_CONSIDERED`` while verifying.
+
+* Avoided encoding problems with filenames under Windows. Thanks to Kévin
+  Bernard-Allies for the patch.
+
+* Fixed #57: Used a better mechanism for comparing keys.
+
+
+0.3.8
+-----
+
+Released: 2015-09-24
+
+* Fixed #22: handled ``PROGRESS`` messages during verification and signing.
+
+* Fixed #26: handled ``PINENTRY_LAUNCHED`` messages during verification,
+  decryption and key generation.
+
+* Fixed #28: Allowed a default Name-Email to be computed even when neither of
+  ``LOGNAME`` and ``USERNAME`` are in the environment.
+
+* Fixed #29: Included test files missing from the tarball in previous versions.
+
+* Fixed #39: On Python 3.x, passing a text instead of a binary stream caused
+  file decryption to hang due to a ``UnicodeDecodeError``. This has now been
+  correctly handled: The decryption fails with a "no data" status.
+
+* Fixed #41: Handled Unicode filenames correctly by encoding them on 2.x using
+  the file system encoding.
+
+* Fixed #43: handled ``PINENTRY_LAUNCHED`` messages during key export. Thanks
+  to Ian Denhardt for looking into this.
+
+* Hide the console window which appears on Windows when gpg is spawned.
+  Thanks to Kévin Bernard-Allies for the patch.
+
+* Subkey fingerprints are now captured.
+
+* The returned value from the ``list_keys`` method now has a new attribute,
+  ``key_map``, which is a dictionary mapping key and subkey fingerprints to
+  the corresponding key's dictionary. With this change, you don't need to
+  iterate over the (potentially large) returned list to search for a key with
+  a given fingerprint - the ``key_map`` dict will take you straight to the key
+  info, whether the fingerprint you have is for a key or a subkey. Thanks to
+  Nick Daly for the initial suggestion.
+
+0.3.7
+-----
+
+Released: 2014-12-07
+
+Signed with PGP key: Vinay Sajip (CODE SIGNING KEY) <[email protected]>
+
+Key Fingerprint    : CA74 9061 914E AC13 8E66 EADB 9147 B477 339A 9B86
+
+* Added an ``output`` keyword parameter to the ``sign`` and
+  ``sign_file`` methods, to allow writing the signature to a file.
+  Thanks to Jannis Leidel for the patch.
+
+* Allowed specifying ``True`` for the ``sign`` keyword parameter,
+  which allows use of the default key for signing and avoids having to
+  specify a key id when it's desired to use the default. Thanks to
+  Fabian Beutel for the patch.
+
+* Used a uniform approach with subprocess on Windows and POSIX: shell=True
+  is not used on either.
+
+* When signing/verifying, the status is updated to reflect any expired or
+  revoked keys or signatures.
+
+* Handled 'NOTATION_NAME' and 'NOTATION_DATA' during verification.
+
+* Fixed #1, #16, #18, #20: Quoting approach changed, since now shell=False.
+
+* Fixed #14: Handled 'NEED_PASSPHRASE_PIN' message.
+
+* Fixed #8: Added a scan_keys method to allow scanning of keys without the
+  need to import into a keyring. Thanks to Venzen Khaosan for the suggestion.
+
+* Fixed #5: Added '0x' prefix when searching for keys. Thanks to Aaron Toponce
+  for the report.
+
+* Fixed #4: Handled 'PROGRESS' message during encryption. Thanks to Daniel
+  Mills for the report.
+
+* Fixed #3: Changed default encoding to Latin-1.
+
+* Fixed #2: Raised ValueError if no recipients were specified
+  for an asymmetric encryption request.
+
+* Handled 'UNEXPECTED' message during verification. Thanks to
+  David Andersen for the patch.
+
+* Replaced old range(len(X)) idiom with enumerate().
+
+* Refactored ``ListKeys`` / ``SearchKeys`` classes to maximise use of common
+  functions.
+
+* Fixed GC94: Added ``export-minimal`` and ``armor`` options when exporting
+  keys. This addition was inadvertently left out of 0.3.6.
+
+0.3.6
+-----
+
+Released: 2014-02-05
+
+* Fixed GC82: Enabled fast random tests on gpg as well as gpg2.
+* Fixed GC85: Avoided deleting temporary file to preserve its permissions.
+* Fixed GC87: Avoided writing passphrase to log.
+* Fixed GC95: Added ``verify_data()`` method to allow verification of
+  signatures in memory.
+* Fixed GC96: Regularised end-of-line characters.
+* Fixed GC98: Rectified problems with earlier fix for shell injection.
+
+0.3.5
+-----
+
+Released: 2013-08-30
+
+* Added improved shell quoting to guard against shell injection.
+* Fixed GC76: Added ``search_keys()`` and ``send_keys()`` methods.
+* Fixed GC77: Allowed specifying a symmetric cipher algorithm.
+* Fixed GC78: Fell back to utf-8 encoding when no other could be determined.
+* Fixed GC79: Default key length is now 2048 bits.
+* Fixed GC80: Removed the Name-Comment default in key generation.
+
+0.3.4
+-----
+
+Released: 2013-06-05
+
+* Fixed GC65: Fixed encoding exception when getting version.
+* Fixed GC66: Now accepts sets and frozensets where appropriate.
+* Fixed GC67: Hash algorithm now captured in sign result.
+* Fixed GC68: Added support for ``--secret-keyring``.
+* Fixed GC70: Added support for multiple keyrings.
+
+0.3.3
+-----
+
+Released: 2013-03-11
+
+* Fixed GC57: Handled control characters in ``list_keys()``.
+* Fixed GC61: Enabled fast random for testing.
+* Fixed GC62: Handled ``KEYEXPIRED`` status.
+* Fixed GC63: Handled ``NO_SGNR`` status.
+
+0.3.2
+-----
+
+Released: 2013-01-17
+
+* Fixed GC56: Disallowed blank values in key generation.
+* Fixed GC57: Handled colons and other characters in ``list_keys()``.
+* Fixed GC59/GC60: Handled ``INV_SGNR`` status during verification and removed
+  calls requiring interactive password input from doctests.
+
+0.3.1
+-----
+
+Released: 2012-09-01
+
+* Fixed GC45: Allowed additional arguments to gpg executable.
+* Fixed GC50: Used latin-1 encoding in tests when it's known to be required.
+* Fixed GC51: Test now returns non-zero exit status on test failure.
+* Fixed GC53: Now handles ``INV_SGNR`` and ``KEY_NOT_CREATED`` statuses.
+* Fixed GC55: Verification and decryption now return trust level of signer in
+  integer and text form.
+
+0.3.0
+-----
+
+Released: 2012-05-12
+
+* Fixed GC49: Reinstated Yann Leboulanger's change to support subkeys
+  (accidentally left out in 0.2.7).
+
+0.2.9
+-----
+
+Released: 2012-03-29
+
+* Fixed GC36: Now handles ``CARDCTRL`` and ``POLICY_URL`` messages.
+* Fixed GC40: Now handles ``DECRYPTION_INFO``, ``DECRYPTION_FAILED`` and
+  ``DECRYPTION_OKAY`` messages.
+* The ``random_binary_data file`` is no longer shipped, but constructed by the
+  test suite if needed.
+
+0.2.8
+-----
+
+Released: 2011-09-02
+
+* Fixed GC29: Now handles ``IMPORT_RES`` while verifying.
+* Fixed GC30: Fixed an encoding problem.
+* Fixed GC33: Quoted arguments for added safety.
+
+0.2.7
+-----
+
+Released: 2011-04-10
+
+* Fixed GC24: License is clarified as BSD.
+* Fixed GC25: Incorporated Daniel Folkinshteyn's changes.
+* Fixed GC26: Incorporated Yann Leboulanger's subkey change.
+* Fixed GC27: Incorporated hysterix's support for symmetric encryption.
+* Did some internal cleanups of Unicode handling.
+
+0.2.6
+-----
+
+Released: 2011-01-25
+
+* Fixed GC14: Should be able to accept passphrases from GPG-Agent.
+* Fixed GC19: Should be able to create a detached signature.
+* Fixed GC21/GC23: Better handling of less common responses from GPG.
+
+0.2.5
+-----
+
+Released: 2010-10-13
+
+* Fixed GC11/GC16: Detached signatures can now be created.
+* Fixed GC3: Detached signatures can be verified.
+* Fixed GC12: Better support for RSA and IDEA.
+* Fixed GC15/GC17: Better support for non-ASCII input.
+
+0.2.4
+-----
+
+Released: 2010-03-01
+
+* Fixed GC9: Now allows encryption without armor and the ability to encrypt
+  and decrypt directly to/from files.
+
+0.2.3
+-----
+
+Released: 2010-01-07
+
+* Fixed GC7: Made sending data to process threaded and added a test case.
+  With a test data file used by the test case, the archive size has gone up
+  to 5MB (the size of the test file).
+
+0.2.2
+-----
+
+Released: 2009-10-06
+
+* Fixed GC5/GC6: Added ``--batch`` when specifying ``--passphrase-fd`` and
+  changed the name of the distribution file to add the ``python-`` prefix.
+
+0.2.1
+-----
+
+Released: 2009-08-07
+
+* Fixed GC2: Added ``handle_status()`` method to the ``ListKeys`` class.
+
+0.2.0
+-----
+
+Released: 2009-07-16
+
+* Various changes made to support Python 3.0.
+
+0.1.0
+-----
+
+Released: 2009-07-04
+
+* Initial release.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.9/gnupg.py 
new/python-gnupg-0.4.0/gnupg.py
--- old/python-gnupg-0.3.9/gnupg.py     2016-09-10 09:38:35.000000000 +0200
+++ new/python-gnupg-0.4.0/gnupg.py     2017-01-29 18:09:41.000000000 +0100
@@ -27,14 +27,14 @@
 and so does not work on Windows). Renamed to gnupg.py to avoid confusion with
 the previous versions.
 
-Modifications Copyright (C) 2008-2016 Vinay Sajip. All rights reserved.
+Modifications Copyright (C) 2008-2017 Vinay Sajip. All rights reserved.
 
 A unittest harness (test_gnupg.py) has also been added.
 """
 
-__version__ = "0.3.9"
+__version__ = "0.4.0"
 __author__ = "Vinay Sajip"
-__date__  = "$10-Sep-2016 08:38:35$"
+__date__  = "$29-Jan-2017 17:09:41$"
 
 try:
     from io import StringIO
@@ -308,7 +308,8 @@
                 self.status = 'unexpected data'
             else:
                 # N.B. there might be other reasons
-                self.status = 'incorrect passphrase'
+                if not self.status:
+                    self.status = 'incorrect passphrase'
         else:
             raise ValueError("Unknown status message: %r" % key)
 
@@ -351,7 +352,7 @@
     }
 
     def handle_status(self, key, value):
-        if key == "IMPORTED":
+        if key in ("IMPORTED", "KEY_CONSIDERED"):
             # this duplicates info we already see in import_ok & import_problem
             pass
         elif key == "NODATA":  # pragma: no cover
@@ -432,7 +433,10 @@
     def get_fields(self, args):
         result = {}
         for i, var in enumerate(self.FIELDS):
-            result[var] = args[i]
+            if i < len(args):
+                result[var] = args[i]
+            else:
+                result[var] = 'unavailable'
         result['uids'] = []
         result['sigs'] = []
         return result
@@ -555,7 +559,7 @@
         if key in ("ENC_TO", "USERID_HINT", "GOODMDC", "END_DECRYPTION",
                    "BEGIN_SIGNING", "NO_SECKEY", "ERROR", "NODATA", "PROGRESS",
                    "CARDCTRL", "BADMDC", "SC_OP_FAILURE", "SC_OP_SUCCESS",
-                   "PINENTRY_LAUNCHED"):
+                   "PINENTRY_LAUNCHED", "KEY_CONSIDERED"):
             # in the case of ERROR, this is because a more specific error
             # message will have come first
             if key == "NODATA":
@@ -605,7 +609,7 @@
 
     def handle_status(self, key, value):
         if key in ("PROGRESS", "GOOD_PASSPHRASE", "NODATA", "KEY_NOT_CREATED",
-                   "PINENTRY_LAUNCHED"):
+                   "PINENTRY_LAUNCHED", "ERROR", "KEY_CONSIDERED"):
             pass
         elif key == "KEY_CREATED":
             (self.type,self.fingerprint) = value.split()
@@ -643,6 +647,8 @@
         if key == "DELETE_PROBLEM":  # pragma: no cover
             self.status = self.problem_reason.get(value,
                                                   "Unknown error: %r" % value)
+        elif key == "KEY_CONSIDERED":
+            pass
         else:  # pragma: no cover
             raise ValueError("Unknown status message: %r" % key)
 
@@ -670,7 +676,7 @@
                    "GOOD_PASSPHRASE", "BEGIN_SIGNING", "CARDCTRL", "INV_SGNR",
                    "NO_SGNR", "MISSING_PASSPHRASE", "NEED_PASSPHRASE_PIN",
                    "SC_OP_FAILURE", "SC_OP_SUCCESS", "PROGRESS",
-                   "PINENTRY_LAUNCHED"):
+                   "PINENTRY_LAUNCHED", "FAILURE", "ERROR", "KEY_CONSIDERED"):
             pass
         elif key in ("KEYEXPIRED", "SIGEXPIRED"):  # pragma: no cover
             self.status = 'key expired'
@@ -772,6 +778,10 @@
         a passphrase will be sent to GPG, else False.
         """
         cmd = [self.gpgbinary, '--status-fd', '2', '--no-tty']
+        cmd.extend(['--debug', 'ipc'])
+        if passphrase and hasattr(self, 'version'):
+            if self.version >= (2, 1):
+                cmd[1:1] = ['--pinentry-mode', 'loopback']
         if self.gnupghome:
             cmd.extend(['--homedir',  no_quote(self.gnupghome)])
         if self.keyring:
@@ -793,19 +803,35 @@
     def _open_subprocess(self, args, passphrase=False):
         # Internal method: open a pipe to a GPG subprocess and return
         # the file objects for communicating with it.
+
+        # def debug_print(cmd):
+            # result = []
+            # for c in cmd:
+                # if ' ' not in c:
+                    # result.append(c)
+                # else:
+                    # if '"' not in c:
+                        # result.append('"%s"' % c)
+                    # elif "'" not in c:
+                        # result.append("'%s'" % c)
+                    # else:
+                        # result.append(c)  # give up
+            # return ' '.join(cmd)
+        from subprocess import list2cmdline as debug_print
+
         cmd = self.make_args(args, passphrase)
         if self.verbose:  # pragma: no cover
-            pcmd = ' '.join(cmd)
-            print(pcmd)
-        logger.debug("%s", cmd)
+            print(debug_print(cmd))
         if not STARTUPINFO:
             si = None
         else:  # pragma: no cover
             si = STARTUPINFO()
             si.dwFlags = STARTF_USESHOWWINDOW
             si.wShowWindow = SW_HIDE
-        return Popen(cmd, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE,
-                     startupinfo=si)
+        result = Popen(cmd, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE,
+                       startupinfo=si)
+        logger.debug("%s: %s", result.pid, debug_print(cmd))
+        return result
 
     def _read_response(self, stream, result):
         # Internal method: reads all the stderr output from GPG, taking notice
@@ -951,8 +977,9 @@
     def verify(self, data):
         """Verify the signature on the contents of the string 'data'
 
-        >>> gpg = GPG(gnupghome="keys")
-        >>> input = gpg.gen_key_input(Passphrase='foo')
+        >>> GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+        >>> gpg = GPG(gpgbinary=GPGBINARY, gnupghome="keys")
+        >>> input = gpg.gen_key_input(passphrase='foo')
         >>> key = gpg.gen_key(input)
         >>> assert key
         >>> sig = gpg.sign('hello',keyid=key.fingerprint,passphrase='bar')
@@ -1007,49 +1034,8 @@
     #
 
     def import_keys(self, key_data):
-        """ import the key_data into our keyring
-
-        >>> import shutil
-        >>> shutil.rmtree("keys")
-        >>> gpg = GPG(gnupghome="keys")
-        >>> input = gpg.gen_key_input()
-        >>> result = gpg.gen_key(input)
-        >>> print1 = result.fingerprint
-        >>> result = gpg.gen_key(input)
-        >>> print2 = result.fingerprint
-        >>> pubkey1 = gpg.export_keys(print1)
-        >>> seckey1 = gpg.export_keys(print1,secret=True)
-        >>> seckeys = gpg.list_keys(secret=True)
-        >>> pubkeys = gpg.list_keys()
-        >>> assert print1 in seckeys.fingerprints
-        >>> assert print1 in pubkeys.fingerprints
-        >>> str(gpg.delete_keys(print1))
-        'Must delete secret key first'
-        >>> str(gpg.delete_keys(print1,secret=True))
-        'ok'
-        >>> str(gpg.delete_keys(print1))
-        'ok'
-        >>> str(gpg.delete_keys("nosuchkey"))
-        'No such key'
-        >>> seckeys = gpg.list_keys(secret=True)
-        >>> pubkeys = gpg.list_keys()
-        >>> assert not print1 in seckeys.fingerprints
-        >>> assert not print1 in pubkeys.fingerprints
-        >>> result = gpg.import_keys('foo')
-        >>> assert not result
-        >>> result = gpg.import_keys(pubkey1)
-        >>> pubkeys = gpg.list_keys()
-        >>> seckeys = gpg.list_keys(secret=True)
-        >>> assert not print1 in seckeys.fingerprints
-        >>> assert print1 in pubkeys.fingerprints
-        >>> result = gpg.import_keys(seckey1)
-        >>> assert result
-        >>> seckeys = gpg.list_keys(secret=True)
-        >>> pubkeys = gpg.list_keys()
-        >>> assert print1 in seckeys.fingerprints
-        >>> assert print1 in pubkeys.fingerprints
-        >>> assert print2 in pubkeys.fingerprints
-
+        """
+        Import the key_data into our keyring.
         """
         result = self.result_map['import'](self)
         logger.debug('import_keys: %r', key_data[:256])
@@ -1064,9 +1050,10 @@
 
         >>> import shutil
         >>> shutil.rmtree("keys")
-        >>> gpg = GPG(gnupghome="keys")
+        >>> GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+        >>> gpg = GPG(gpgbinary=GPGBINARY, gnupghome="keys")
         >>> os.chmod('keys', 0x1C0)
-        >>> result = gpg.recv_keys('keyserver.ubuntu.com', '92905378')
+        >>> result = gpg.recv_keys('pgp.mit.edu', '92905378')
         >>> assert result
 
         """
@@ -1098,9 +1085,12 @@
         data.close()
         return result
 
-    def delete_keys(self, fingerprints, secret=False):
+    def delete_keys(self, fingerprints, secret=False, passphrase=None):
         which='key'
         if secret:  # pragma: no cover
+            if self.version >= (2, 1) and passphrase is None:
+                raise ValueError('For GnuPG >= 2.1, deleting secret keys '
+                                 'needs a passphrase to be provided')
             which='secret-key'
         if _is_sequence(fingerprints):  # pragma: no cover
             fingerprints = [no_quote(s) for s in fingerprints]
@@ -1109,15 +1099,34 @@
         args = ['--batch', '--delete-%s' % which]
         args.extend(fingerprints)
         result = self.result_map['delete'](self)
-        p = self._open_subprocess(args)
-        self._collect_output(p, result, stdin=p.stdin)
+        if not secret or self.version < (2, 1):
+            p = self._open_subprocess(args)
+            self._collect_output(p, result, stdin=p.stdin)
+        else:
+            # Need to send in a passphrase.
+            f = _make_binary_stream('', self.encoding)
+            try:
+                self._handle_io(args, f, result, passphrase=passphrase,
+                                binary=True)
+            finally:
+                f.close()
         return result
 
-    def export_keys(self, keyids, secret=False, armor=True, minimal=False):
-        "export the indicated keys. 'keyid' is anything gpg accepts"
+    def export_keys(self, keyids, secret=False, armor=True, minimal=False,
+                    passphrase=None):
+        """
+        Export the indicated keys. A 'keyid' is anything gpg accepts.
+
+        Since GnuPG 2.1, you can't export secret keys without providing a
+        passphrase.
+        """
+
         which=''
         if secret:
             which='-secret-key'
+            if self.version >= (2, 1) and passphrase is None:
+                raise ValueError('For GnuPG >= 2.1, exporting secret keys '
+                                 'needs a passphrase to be provided')
         if _is_sequence(keyids):
             keyids = [no_quote(k) for k in keyids]
         else:
@@ -1128,12 +1137,21 @@
         if minimal:  # pragma: no cover
             args.extend(['--export-options','export-minimal'])
         args.extend(keyids)
-        p = self._open_subprocess(args)
         # gpg --export produces no status-fd output; stdout will be
         # empty in case of failure
         #stdout, stderr = p.communicate()
         result = self.result_map['export'](self)
-        self._collect_output(p, result, stdin=p.stdin)
+        if not secret or self.version < (2, 1):
+            p = self._open_subprocess(args)
+            self._collect_output(p, result, stdin=p.stdin)
+        else:
+            # Need to send in a passphrase.
+            f = _make_binary_stream('', self.encoding)
+            try:
+                self._handle_io(args, f, result, passphrase=passphrase,
+                                binary=True)
+            finally:
+                f.close()
         logger.debug('export_keys result: %r', result.data)
         # Issue #49: Return bytes if armor not specified, else text
         result = result.data
@@ -1145,7 +1163,7 @@
         # Get the response information
         result = self.result_map[kind](self)
         self._collect_output(p, result, stdin=p.stdin)
-        lines = result.data.decode(self.encoding,
+        lines = result.data.decode('utf-8',
                                    self.decode_errors).splitlines()
         valid_keywords = 'pub uid sec fpr sub ssb sig'.split()
         for line in lines:
@@ -1167,22 +1185,22 @@
 
         >>> import shutil
         >>> shutil.rmtree("keys")
-        >>> gpg = GPG(gnupghome="keys")
-        >>> input = gpg.gen_key_input()
+        >>> GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+        >>> gpg = GPG(gpgbinary=GPGBINARY, gnupghome="keys")
+        >>> input = gpg.gen_key_input(passphrase='foo')
         >>> result = gpg.gen_key(input)
-        >>> print1 = result.fingerprint
+        >>> fp1 = result.fingerprint
         >>> result = gpg.gen_key(input)
-        >>> print2 = result.fingerprint
+        >>> fp2 = result.fingerprint
         >>> pubkeys = gpg.list_keys()
-        >>> assert print1 in pubkeys.fingerprints
-        >>> assert print2 in pubkeys.fingerprints
+        >>> assert fp1 in pubkeys.fingerprints
+        >>> assert fp2 in pubkeys.fingerprints
 
         """
 
         if sigs:
             which = 'sigs'
-        else:
-            which='keys'
+        else:            which='keys'
         if secret:
             which='secret-keys'
         args = ['--list-%s' % which, '--fixed-list-mode',
@@ -1203,7 +1221,7 @@
         The function achieves this by running:
         $ gpg --with-fingerprint --with-colons filename
         """
-        args = ['--with-fingerprint', '--with-colons']
+        args = ['--with-fingerprint', '--with-colons', '--fixed-list-mode']
         args.append(no_quote(filename))
         p = self._open_subprocess(args)
         return self._get_list_output(p, 'scan')
@@ -1213,13 +1231,14 @@
 
         >>> import shutil
         >>> shutil.rmtree('keys')
-        >>> gpg = GPG(gnupghome='keys')
+        >>> GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+        >>> gpg = GPG(gpgbinary=GPGBINARY, gnupghome='keys')
         >>> os.chmod('keys', 0x1C0)
         >>> result = gpg.search_keys('<[email protected]>')
         >>> assert result, 'Failed using default keyserver'
-        >>> keyserver = 'keyserver.ubuntu.com'
-        >>> result = gpg.search_keys('<[email protected]>', keyserver)
-        >>> assert result, 'Failed using keyserver.ubuntu.com'
+        >>> #keyserver = 'keyserver.ubuntu.com'
+        >>> #result = gpg.search_keys('<[email protected]>', keyserver)
+        >>> #assert result, 'Failed using keyserver.ubuntu.com'
 
         """
         query = query.strip()
@@ -1233,7 +1252,7 @@
         # Get the response information
         result = self.result_map['search'](self)
         self._collect_output(p, result, stdin=p.stdin)
-        lines = result.data.decode(self.encoding,
+        lines = result.data.decode('utf-8',
                                    self.decode_errors).splitlines()
         valid_keywords = ['pub', 'uid']
         for line in lines:
@@ -1254,8 +1273,9 @@
         """Generate a key; you might use gen_key_input() to create the
         control input.
 
-        >>> gpg = GPG(gnupghome="keys")
-        >>> input = gpg.gen_key_input()
+        >>> GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+        >>> gpg = GPG(gpgbinary=GPGBINARY, gnupghome="keys")
+        >>> input = gpg.gen_key_input(passphrase='foo')
         >>> result = gpg.gen_key(input)
         >>> assert result
         >>> result = gpg.gen_key('foo')
@@ -1358,39 +1378,40 @@
         >>> import shutil
         >>> if os.path.exists("keys"):
         ...     shutil.rmtree("keys")
-        >>> gpg = GPG(gnupghome="keys")
-        >>> input = gpg.gen_key_input(passphrase='foo')
+        >>> GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+        >>> gpg = GPG(gpgbinary=GPGBINARY, gnupghome="keys")
+        >>> input = gpg.gen_key_input(name_email='user1@test', 
passphrase='pp1')
         >>> result = gpg.gen_key(input)
-        >>> print1 = result.fingerprint
-        >>> input = gpg.gen_key_input()
+        >>> fp1 = result.fingerprint
+        >>> input = gpg.gen_key_input(name_email='user2@test', 
passphrase='pp2')
         >>> result = gpg.gen_key(input)
-        >>> print2 = result.fingerprint
-        >>> result = gpg.encrypt("hello",print2)
+        >>> fp2 = result.fingerprint
+        >>> result = gpg.encrypt("hello",fp2)
         >>> message = str(result)
         >>> assert message != 'hello'
-        >>> result = gpg.decrypt(message)
+        >>> result = gpg.decrypt(message, passphrase='pp2')
         >>> assert result
         >>> str(result)
         'hello'
-        >>> result = gpg.encrypt("hello again",print1)
+        >>> result = gpg.encrypt("hello again", fp1)
         >>> message = str(result)
-        >>> result = gpg.decrypt(message,passphrase='bar')
+        >>> result = gpg.decrypt(message, passphrase='bar')
         >>> result.status in ('decryption failed', 'bad passphrase')
         True
         >>> assert not result
-        >>> result = gpg.decrypt(message,passphrase='foo')
+        >>> result = gpg.decrypt(message, passphrase='pp1')
         >>> result.status == 'decryption ok'
         True
         >>> str(result)
         'hello again'
-        >>> result = gpg.encrypt("signed 
hello",print2,sign=print1,passphrase='foo')
+        >>> result = gpg.encrypt("signed hello", fp2, sign=fp1, 
passphrase='pp1')
         >>> result.status == 'encryption ok'
         True
         >>> message = str(result)
-        >>> result = gpg.decrypt(message)
+        >>> result = gpg.decrypt(message, passphrase='pp2')
         >>> result.status == 'decryption ok'
         True
-        >>> assert result.fingerprint == print1
+        >>> assert result.fingerprint == fp1
 
         """
         data = _make_binary_stream(data, self.encoding)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.9/setup.py 
new/python-gnupg-0.4.0/setup.py
--- old/python-gnupg-0.3.9/setup.py     2016-09-09 00:28:05.000000000 +0200
+++ new/python-gnupg-0.4.0/setup.py     2017-01-29 19:30:28.000000000 +0100
@@ -7,16 +7,16 @@
     long_description = "This module allows easy access to GnuPG's key \
 management, encryption and signature functionality from Python programs. \
 It is intended for use with Python 2.4 or greater.",
-    license="""Copyright (C) 2008-2016 by Vinay Sajip. All Rights Reserved. 
See LICENSE.txt for license.""",
+    license="""Copyright (C) 2008-2017 by Vinay Sajip. All Rights Reserved. 
See LICENSE.txt for license.""",
     version=version,
     author="Vinay Sajip",
     author_email="[email protected]",
     maintainer="Vinay Sajip",
     maintainer_email="[email protected]",
-    url="http://packages.python.org/python-gnupg/index.html";,
+    url="http://pythonhosted.org/python-gnupg/index.html";,
     py_modules=["gnupg"],
     platforms="No particular restrictions",
-    
download_url="https://pypi.python.org/packages/source/p/python-gnupg/python-gnupg-%s.tar.gz";
 % version,
+    
download_url="https://pypi.io/packages/source/p/python-gnupg/python-gnupg-%s.tar.gz";
 % version,
     classifiers=[
         'Development Status :: 5 - Production/Stable',
         "Intended Audience :: Developers",
@@ -32,6 +32,7 @@
         "Programming Language :: Python :: 3.3",
         "Programming Language :: Python :: 3.4",
         "Programming Language :: Python :: 3.5",
+        "Programming Language :: Python :: 3.6",
         "Operating System :: OS Independent",
         "Topic :: Software Development :: Libraries :: Python Modules"
     ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.9/test_gnupg.py 
new/python-gnupg-0.4.0/test_gnupg.py
--- old/python-gnupg-0.3.9/test_gnupg.py        2016-09-10 09:38:57.000000000 
+0200
+++ new/python-gnupg-0.4.0/test_gnupg.py        2017-01-29 18:09:59.000000000 
+0100
@@ -2,7 +2,7 @@
 """
 A test harness for gnupg.py.
 
-Copyright (C) 2008-2016 Vinay Sajip. All rights reserved.
+Copyright (C) 2008-2017 Vinay Sajip. All rights reserved.
 """
 import doctest
 import logging
@@ -15,10 +15,20 @@
 import tempfile
 import unittest
 
+try:
+    from unittest import skipIf
+except ImportError:
+    # For now, for Python < 2.7
+    def skipIf(condition, message):
+        if not condition:
+            return lambda x: x
+        else:
+            return lambda x: None
+
 import gnupg
 
 __author__ = "Vinay Sajip"
-__date__  = "$10-Sep-2016 08:38:57$"
+__date__  = "$29-Jan-2017 17:09:59$"
 
 ALL_TESTS = True
 
@@ -147,6 +157,20 @@
     # ignoring things like spurious blank lines
     return get_key_data(k1) != get_key_data(k2)
 
+AGENT_CONFIG = b'''allow-loopback-pinentry
+log-file socket:///tmp/S.my-gnupg-log
+verbose
+debug ipc
+'''
+
+def prepare_homedir(hd):
+    if not os.path.isdir(hd):
+        os.makedirs(hd)
+    os.chmod(hd, 0x1C0)
+    fn = os.path.join(hd, 'gpg-agent.conf')
+    with open(fn, 'wb') as f:
+        f.write(AGENT_CONFIG)
+
 class GPGTestCase(unittest.TestCase):
     def setUp(self):
         hd = os.path.join(os.getcwd(), 'keys')
@@ -154,6 +178,7 @@
             self.assertTrue(os.path.isdir(hd),
                             "Not a directory: %s" % hd)
             shutil.rmtree(hd)
+        prepare_homedir(hd)
         self.homedir = hd
         self.gpg = gpg = gnupg.GPG(gnupghome=hd, gpgbinary=GPGBINARY)
         v = gpg.version
@@ -240,6 +265,8 @@
             'name_comment': 'dummy comment',
             'name_email': '[email protected]',
         }
+        if self.gpg.version >= (2, 1):
+            params['passphrase'] = 'foo'
         cmd = self.gpg.gen_key_input(**params)
         result = self.gpg.gen_key(cmd)
         keys = self.gpg.list_keys()
@@ -253,10 +280,14 @@
 
     def test_key_generation_with_escapes(self):
         "Test that key generation handles escape characters"
-        cmd = self.gpg.gen_key_input(name_comment='Funny chars: '
-                                                  '\\r\\n\\f\\v\\0\\b',
-                                     name_real='Test Name',
-                                     name_email='[email protected]')
+        params = {
+            'name_real': 'Test Name',
+            'name_comment': 'Funny chars: \\r\\n\\f\\v\\0\\b',
+            'name_email': '[email protected]',
+        }
+        if self.gpg.version >= (2, 1):
+            params['passphrase'] = 'foo'
+        cmd = self.gpg.gen_key_input(**params)
         result = self.gpg.gen_key(cmd)
         keys = self.gpg.list_keys()
         self.assertEqual(len(keys), 1)
@@ -314,12 +345,19 @@
                         "1-element list expected")
         self.assertEqual(len(private_keys.fingerprints), 1)
         # Now do the same test, but using keyring and secret_keyring arguments
-        pkn = 'pubring.gpg'
-        skn = 'secring.gpg'
+        if self.gpg.version < (2, 1):
+            pkn = 'pubring.gpg'
+            skn = 'secring.gpg'
+        else:
+            # On GnuPG >= 2.1, --secret-keyring is obsolete and ignored,
+            # and the keyring file name has changed.
+            pkn = 'pubring.kbx'
+            skn = None
         hd = os.path.join(os.getcwd(), 'keys')
         if os.name == 'posix':
             pkn = os.path.join(hd, pkn)
-            skn = os.path.join(hd, skn)
+            if skn:
+                skn = os.path.join(hd, skn)
         gpg = gnupg.GPG(gnupghome=hd, gpgbinary=GPGBINARY,
                         keyring=pkn, secret_keyring=skn)
         logger.debug('Using keyring and secret_keyring arguments')
@@ -377,17 +415,20 @@
 
     def test_scan_keys(self):
         "Test that external key files can be scanned"
-        expected = set([
-            'Andrew Able (A test user) <[email protected]>',
-            'Barbara Brown (A test user) <[email protected]>',
-            'Charlie Clark (A test user) <[email protected]>',
-        ])
-        for fn in ('test_pubring.gpg', 'test_secring.gpg'):
-            data = self.gpg.scan_keys(fn)
-            uids = set()
-            for d in data:
-                uids.add(d['uids'][0])
-            self.assertEqual(uids, expected)
+        # Don't use SkipTest for now, as not available for Python < 2.7
+        if self.gpg.version < (2, 1):
+            expected = set([
+                'Andrew Able (A test user) <[email protected]>',
+                'Barbara Brown (A test user) <[email protected]>',
+                'Charlie Clark (A test user) <[email protected]>',
+            ])
+            for fn in ('test_pubring.gpg', 'test_secring.gpg'):
+                logger.debug('scanning keys in %s', fn)
+                data = self.gpg.scan_keys(fn)
+                uids = set()
+                for d in data:
+                    uids.add(d['uids'][0])
+                self.assertEqual(uids, expected)
 
     def test_encryption_and_decryption(self):
         "Test that encryption and decryption works"
@@ -455,11 +496,16 @@
         self.assertEqual(0, match, "Keys must match")
         #Generate a key so we can test exporting private keys
         key = self.do_key_generation()
-        ascii = gpg.export_keys(key.fingerprint, True)
+        if self.gpg.version < (2, 1):
+            passphrase = None
+        else:
+            passphrase = 'bbrown'
+        ascii = gpg.export_keys(key.fingerprint, True, passphrase=passphrase)
         self.assertTrue(isinstance(ascii, gnupg.text_type))
         self.assertTrue(ascii.find("PGP PRIVATE KEY BLOCK") >= 0,
                         "Exported key should be private")
-        binary = gpg.export_keys(key.fingerprint, True, armor=False)
+        binary = gpg.export_keys(key.fingerprint, True, armor=False,
+                                 passphrase=passphrase)
         self.assertFalse(isinstance(binary, gnupg.text_type))
         logger.debug("test_import_and_export ends")
 
@@ -616,7 +662,7 @@
         self.assertEqual(args[-4:], ['--foo', '--bar', 'a', 'b'])
 
     def do_file_encryption_and_decryption(self, encfname, decfname):
-        "Do the actual encryption.decryptin test using given filenames"
+        "Do the actual encryption/decryption test using given filenames"
         mode = None
         if os.name == 'posix':
             # pick a mode that won't be already in effect via umask
@@ -644,6 +690,7 @@
             efile.seek(0, 0) # can't use os.SEEK_SET in 2.4
             edata = efile.read()
             efile.close()
+            self.assertTrue(os.path.exists(decfname))
             dfile = open(decfname, 'rb')
             ddata = dfile.read()
             dfile.close()
@@ -694,6 +741,7 @@
             shutil.rmtree(d)
         logger.debug("test_filename_with_spaces ends")
 
+    #@skipIf(os.name == 'nt', 'Test not suitable for Windows')
     def test_search_keys(self):
         "Test that searching for keys works"
         r = self.gpg.search_keys('<[email protected]>')
@@ -743,6 +791,94 @@
         self.assertTrue(signed.data)
         logger.debug("test_signing_with_uid ends")
 
+    def test_doctest_import_keys(self):
+        """
+        Because GnuPG 2.1 requires passphrases for exporting and deleting
+        secret keys, and because console-mode passphrase entry requires
+        configuration changes, doctests can't always be used. This test
+        replicates the original doctest for import_keys as a regular test.
+
+        >>> import shutil
+        >>> shutil.rmtree("keys")
+        >>> GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+        >>> gpg = GPG(gpgbinary=GPGBINARY, gnupghome="keys")
+        >>> input = gpg.gen_key_input(name_email='user1@test', 
passphrase='pp1')
+        >>> result = gpg.gen_key(input)
+        >>> fp1 = result.fingerprint
+        >>> result = gpg.gen_key(input)
+        >>> fp2 = result.fingerprint
+        >>> pubkey1 = gpg.export_keys(fp1)
+        >>> seckey1 = gpg.export_keys(fp1, secret=True, passphrase='pp1')
+        >>> seckeys = gpg.list_keys(secret=True)
+        >>> pubkeys = gpg.list_keys()
+        >>> assert fp1 in seckeys.fingerprints
+        >>> assert fp1 in pubkeys.fingerprints
+        >>> str(gpg.delete_keys(fp1))
+        'Must delete secret key first'
+        >>> str(gpg.delete_keys(fp1, secret=True, passphrase='pp1'))
+        'ok'
+        >>> str(gpg.delete_keys(fp1))
+        'ok'
+        >>> str(gpg.delete_keys("nosuchkey"))
+        'No such key'
+        >>> seckeys = gpg.list_keys(secret=True)
+        >>> pubkeys = gpg.list_keys()
+        >>> assert not fp1 in seckeys.fingerprints
+        >>> assert not fp1 in pubkeys.fingerprints
+        >>> result = gpg.import_keys('foo')
+        >>> assert not result
+        >>> result = gpg.import_keys(pubkey1)
+        >>> pubkeys = gpg.list_keys()
+        >>> seckeys = gpg.list_keys(secret=True)
+        >>> assert not fp1 in seckeys.fingerprints
+        >>> assert fp1 in pubkeys.fingerprints
+        >>> result = gpg.import_keys(seckey1)
+        >>> assert result
+        >>> seckeys = gpg.list_keys(secret=True)
+        >>> pubkeys = gpg.list_keys()
+        >>> assert fp1 in seckeys.fingerprints
+        >>> assert fp1 in pubkeys.fingerprints
+        >>> assert fp2 in pubkeys.fingerprints
+        """
+        logger.debug("test_doctest_import_keys begins")
+        gpg = self.gpg
+        inp = gpg.gen_key_input(name_email='user1@test', passphrase='pp1')
+        result = gpg.gen_key(inp)
+        fp1 = result.fingerprint
+        inp = gpg.gen_key_input(name_email='user2@test', passphrase='pp2')
+        result = gpg.gen_key(inp)
+        fp2 = result.fingerprint
+        pubkey1 = gpg.export_keys(fp1)
+        if gpg.version >= (2, 1):
+            passphrase = 'pp1'
+        else:
+            passphrase = None
+        seckey1 = gpg.export_keys(fp1, secret=True, passphrase=passphrase)
+        seckeys = gpg.list_keys(secret=True)
+        pubkeys = gpg.list_keys()
+        # avoid assertIn, etc. as absent in older Python versions
+        self.assertTrue(fp1 in seckeys.fingerprints)
+        self.assertTrue(fp1 in pubkeys.fingerprints)
+        result = gpg.delete_keys(fp1)
+        self.assertEqual(str(result), 'Must delete secret key first')
+        if gpg.version < (2, 1):
+            # Doesn't work on 2.1, and can't use SkipTest due to having
+            # to support older Pythons
+            result = gpg.delete_keys(fp1, secret=True, passphrase=passphrase)
+            self.assertEqual(str(result), 'ok')
+            result = gpg.delete_keys(fp1)
+            self.assertEqual(str(result), 'ok')
+            result = gpg.delete_keys('nosuchkey')
+            self.assertEqual(str(result), 'No such key')
+            seckeys = gpg.list_keys(secret=True)
+            pubkeys = gpg.list_keys()
+            self.assertFalse(fp1 in seckeys.fingerprints)
+            self.assertFalse(fp1 in pubkeys.fingerprints)
+            result = gpg.import_keys('foo')
+            self.assertFalse(result)
+        logger.debug("test_doctest_import_keys ends")
+
+
 TEST_GROUPS = {
     'sign' : set(['test_signature_verification']),
     'crypt' : set(['test_encryption_and_decryption',
@@ -756,11 +892,11 @@
                  'test_key_generation_with_empty_value',
                  'test_key_generation_with_colons',
                  'test_search_keys', 'test_scan_keys']),
-    'import' : set(['test_import_only']),
+    'import' : set(['test_import_only', 'test_doctest_import_keys']),
     'basic' : set(['test_environment', 'test_list_keys_initial',
                    'test_nogpg', 'test_make_args',
                    'test_quote_with_shell']),
-    'test': set(['test_search_keys']),
+    'test': set(['test_doctest_import_keys']),
 }
 
 def suite(args=None):
@@ -791,7 +927,7 @@
 def main():
     init_logging()
     tests = suite()
-    results = unittest.TextTestRunner(verbosity=2).run(tests)
+    results = unittest.TextTestRunner(verbosity=1).run(tests)
     return not results.wasSuccessful()
 
 


Reply via email to