Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-python-gnupg for
openSUSE:Factory checked in at 2025-08-15 21:51:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-python-gnupg (Old)
and /work/SRC/openSUSE:Factory/.python-python-gnupg.new.1085 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-python-gnupg"
Fri Aug 15 21:51:51 2025 rev:19 rq:1299387 version:0.5.5
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-python-gnupg/python-python-gnupg.changes
2025-02-17 20:55:02.653770064 +0100
+++
/work/SRC/openSUSE:Factory/.python-python-gnupg.new.1085/python-python-gnupg.changes
2025-08-15 21:52:47.633949827 +0200
@@ -1,0 +2,8 @@
+Thu Aug 14 09:54:33 UTC 2025 - John Paul Adrian Glaubitz
<[email protected]>
+
+- Update to 0.5.5
+ * Fix #249: Handle fetching GPG version when not the first item in the
configuration.
+ * Fix #250: Capture uid info in a uid_map attribute of ScanKeys/ListKeys.
+ * Fix #255: Improve handling of exceptions raised in background threads.
+
+-------------------------------------------------------------------
Old:
----
python-gnupg-0.5.4.tar.gz
New:
----
python-gnupg-0.5.5.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-python-gnupg.spec ++++++
--- /var/tmp/diff_new_pack.EVSsrt/_old 2025-08-15 21:52:48.225974444 +0200
+++ /var/tmp/diff_new_pack.EVSsrt/_new 2025-08-15 21:52:48.225974444 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-python-gnupg
-Version: 0.5.4
+Version: 0.5.5
Release: 0
Summary: A wrapper for the GNU Privacy Guard (GPG or GnuPG)
License: BSD-3-Clause
++++++ python-gnupg-0.5.4.tar.gz -> python-gnupg-0.5.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-gnupg-0.5.4/PKG-INFO
new/python-gnupg-0.5.5/PKG-INFO
--- old/python-gnupg-0.5.4/PKG-INFO 2025-01-07 12:57:56.000000000 +0100
+++ new/python-gnupg-0.5.5/PKG-INFO 2025-08-04 21:16:46.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-gnupg
-Version: 0.5.4
+Version: 0.5.5
Summary: A wrapper for the Gnu Privacy Guard (GPG or GnuPG)
Home-page: https://github.com/vsajip/python-gnupg
Author: Vinay Sajip
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-gnupg-0.5.4/README.rst
new/python-gnupg-0.5.5/README.rst
--- old/python-gnupg-0.5.4/README.rst 2024-10-25 15:49:15.000000000 +0200
+++ new/python-gnupg-0.5.5/README.rst 2025-08-04 20:48:16.000000000 +0200
@@ -72,13 +72,32 @@
.. note:: GCnn refers to an issue nn on Google Code.
-0.5.4 (future)
+0.5.6 (future)
--------------
Released: Not yet
+
+0.5.5
+-----
+
+Released: 2025-08-04
+
+* Fix #249: Handle fetching GPG version when not the first item in the
configuration.
+
+* Fix #250: Capture uid info in a uid_map attribute of ScanKeys/ListKeys.
+
+* Fix #255: Improve handling of exceptions raised in background threads.
+
+
+0.5.4
+-----
+
+Released: 2025-01-07
+
* Fix #242: Handle exceptions in ``on_data`` callable.
+
0.5.3
-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-gnupg-0.5.4/gnupg.py
new/python-gnupg-0.5.5/gnupg.py
--- old/python-gnupg-0.5.4/gnupg.py 2025-01-07 11:13:17.000000000 +0100
+++ new/python-gnupg-0.5.5/gnupg.py 2025-08-04 20:49:23.000000000 +0200
@@ -27,7 +27,7 @@
and so does not work on Windows). Renamed to gnupg.py to avoid confusion with
the previous versions.
-Modifications Copyright (C) 2008-2024 Vinay Sajip. All rights reserved.
+Modifications Copyright (C) 2008-2025 Vinay Sajip. All rights reserved.
For the full documentation, see https://docs.red-dove.com/python-gnupg/ or
https://gnupg.readthedocs.io/
@@ -39,15 +39,19 @@
from io import StringIO
import logging
import os
+try:
+ from queue import Queue, Empty
+except ImportError:
+ from Queue import Queue, Empty
import re
import socket
from subprocess import Popen, PIPE
import sys
import threading
-__version__ = '0.5.4'
+__version__ = '0.5.5'
__author__ = 'Vinay Sajip'
-__date__ = '$07-Jan-2025 10:13:17$'
+__date__ = '$04-Aug-2025 19:49:23$'
STARTUPINFO = None
if os.name == 'nt': # pragma: no cover
@@ -137,7 +141,7 @@
return s
-def _copy_data(instream, outstream, buffer_size):
+def _copy_data(instream, outstream, buffer_size, error_queue):
# Copy one stream to another
assert buffer_size > 0
sent = 0
@@ -150,8 +154,9 @@
# for what is actually a binary file
try:
data = instream.read(buffer_size)
- except Exception: # pragma: no cover
+ except Exception as e: # pragma: no cover
logger.warning('Exception occurred while reading', exc_info=1)
+ error_queue.put_nowait(e)
break
if not data:
break
@@ -161,10 +166,11 @@
outstream.write(data)
except UnicodeError: # pragma: no cover
outstream.write(data.encode(enc))
- except Exception: # pragma: no cover
+ except Exception as e: # pragma: no cover
# Can sometimes get 'broken pipe' errors even when the data has all
# been sent
logger.exception('Error sending data')
+ error_queue.put_nowait(e)
break
try:
outstream.close()
@@ -173,9 +179,9 @@
logger.debug('closed output, %d bytes sent', sent)
-def _threaded_copy_data(instream, outstream, buffer_size):
+def _threaded_copy_data(instream, outstream, buffer_size, error_queue):
assert buffer_size > 0
- wr = threading.Thread(target=_copy_data, args=(instream, outstream,
buffer_size))
+ wr = threading.Thread(target=_copy_data, args=(instream, outstream,
buffer_size, error_queue))
wr.daemon = True
logger.debug('data copier: %r, %r, %r', wr, instream, outstream)
wr.start()
@@ -569,6 +575,7 @@
self.curkey = None
self.fingerprints = []
self.uids = []
+ self.uid_map = {}
def get_fields(self, args):
"""
@@ -597,6 +604,10 @@
uid = uid.replace(k, v)
self.curkey['uids'].append(uid)
self.uids.append(uid)
+ uid_data = {}
+ self.uid_map[uid] = uid_data
+ for fn, fv in zip(self.FIELDS, args):
+ uid_data[fn] = fv
def handle_status(self, key, value): # pragma: no cover
pass
@@ -1053,7 +1064,7 @@
self.fingerprint = self.fingerprint or args[9]
-VERSION_RE = re.compile(r'^cfg:version:(\d+(\.\d+)*)'.encode('ascii'))
+VERSION_RE = re.compile(r'\bcfg:version:(\d+(\.\d+)*)'.encode('ascii'))
HEX_DIGITS_RE = re.compile(r'[0-9a-f]+$', re.I)
PUBLIC_KEY_RE = re.compile(r'gpg: public key is (\w+)')
@@ -1154,7 +1165,7 @@
self._collect_output(p, result, stdin=p.stdin)
if p.returncode != 0: # pragma: no cover
raise ValueError('Error invoking gpg: %s: %s' % (p.returncode,
result.stderr))
- m = VERSION_RE.match(result.data)
+ m = VERSION_RE.search(result.data)
if not m: # pragma: no cover
self.version = None
else:
@@ -1344,17 +1355,24 @@
# Handle a basic data call - pass data to GPG, handle the output
# including status information. Garbage In, Garbage Out :)
fileobj = self._get_fileobj(fileobj_or_path)
+ writer = None # See issue #237
try:
p = self._open_subprocess(args, passphrase is not None)
if not binary: # pragma: no cover
stdin = codecs.getwriter(self.encoding)(p.stdin)
else:
stdin = p.stdin
- writer = None # See issue #237
if passphrase:
_write_passphrase(stdin, passphrase, self.encoding)
- writer = _threaded_copy_data(fileobj, stdin, self.buffer_size)
+ error_queue = Queue()
+ writer = _threaded_copy_data(fileobj, stdin, self.buffer_size,
error_queue)
self._collect_output(p, result, writer, stdin)
+ try:
+ exc = error_queue.get_nowait()
+ # if we get here, that means an error occurred in the copying
thread
+ raise exc
+ except Empty:
+ pass
return result
finally:
if writer:
@@ -1476,14 +1494,21 @@
# passphrase is bad, gpg bails and you can't write the message.
fileobj = self._get_fileobj(fileobj_or_path)
p = self._open_subprocess(args, passphrase is not None)
+ writer = None
try:
stdin = p.stdin
if passphrase:
_write_passphrase(stdin, passphrase, self.encoding)
- writer = _threaded_copy_data(fileobj, stdin, self.buffer_size)
+ error_queue = Queue()
+ writer = _threaded_copy_data(fileobj, stdin, self.buffer_size,
error_queue)
+ try:
+ exc = error_queue.get_nowait()
+ # if we get here, that means an error occurred in the copying
thread
+ raise exc
+ except Empty:
+ pass
except IOError: # pragma: no cover
logging.exception('error writing message')
- writer = None
finally:
if writer:
writer.join(0.01)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-gnupg-0.5.4/python_gnupg.egg-info/PKG-INFO
new/python-gnupg-0.5.5/python_gnupg.egg-info/PKG-INFO
--- old/python-gnupg-0.5.4/python_gnupg.egg-info/PKG-INFO 2025-01-07
12:57:56.000000000 +0100
+++ new/python-gnupg-0.5.5/python_gnupg.egg-info/PKG-INFO 2025-08-04
21:16:45.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-gnupg
-Version: 0.5.4
+Version: 0.5.5
Summary: A wrapper for the Gnu Privacy Guard (GPG or GnuPG)
Home-page: https://github.com/vsajip/python-gnupg
Author: Vinay Sajip
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-gnupg-0.5.4/test_gnupg.py
new/python-gnupg-0.5.5/test_gnupg.py
--- old/python-gnupg-0.5.4/test_gnupg.py 2025-01-07 11:12:41.000000000
+0100
+++ new/python-gnupg-0.5.5/test_gnupg.py 2025-08-04 20:50:21.000000000
+0200
@@ -2,9 +2,10 @@
"""
A test harness for gnupg.py.
-Copyright (C) 2008-2024 Vinay Sajip. All rights reserved.
+Copyright (C) 2008-2025 Vinay Sajip. All rights reserved.
"""
import argparse
+import io
import json
import logging
import os.path
@@ -35,7 +36,7 @@
import gnupg
__author__ = 'Vinay Sajip'
-__date__ = '$07-Jan-2025 10:12:41$'
+__date__ = '$04-Aug-2025 19:50:21$'
ALL_TESTS = True
@@ -1167,12 +1168,9 @@
# Try opening the encrypted file in text mode (Issue #39)
# this doesn't fail in 2.x
if gnupg._py3k:
- efile = open(encfname, 'r')
- ddata = self.gpg.decrypt_file(efile, passphrase='bbrown',
output=decfname)
- self.assertEqual(2, ddata.returncode, 'Unexpected return code')
- self.assertFalse(ddata)
- self.assertEqual(ddata.status, 'no data was provided')
- efile.close()
+ logger.debug('about to pass text stream to decrypt_file')
+ with open(encfname, 'r') as efile:
+ self.assertRaises(UnicodeDecodeError,
self.gpg.decrypt_file, efile, passphrase='bbrown', output=decfname)
finally:
for fn in (encfname, decfname):
if os.name == 'posix' and mode is not None:
@@ -1206,8 +1204,13 @@
data = 'Hello, world!'
for badout, message in cases:
stream = gnupg._make_binary_stream(data, self.gpg.encoding)
- edata = self.gpg.encrypt_file(stream, barbara, armor=False,
output=badout)
- self.assertEqual(2, edata.returncode, 'Unexpecteds return code')
+ try:
+ # On Ubuntu and pypy-2.7, you often get an IOError "Broken
pipe"
+ # during the encrypt operation ...
+ edata = self.gpg.encrypt_file(stream, barbara, armor=False,
output=badout)
+ self.assertEqual(2, edata.returncode, 'Unexpected return code')
+ except IOError:
+ pass
# on GnuPG 1.4, you sometimes don't get any FAILURE messages, in
# which case status will not be set
if edata.status:
@@ -1235,12 +1238,18 @@
for badout, message in cases:
stream = gnupg._make_binary_stream(data, self.gpg.encoding)
- edata = self.gpg.encrypt_file(stream, barbara,
armor=False, output=badout)
- self.assertEqual(2, edata.returncode, 'Unexpected return
code')
+ try:
+ # On Ubuntu and pypy-2.7, you often get an IOError
"Broken pipe"
+ # during the encrypt operation ...
+ edata = self.gpg.encrypt_file(stream, barbara,
armor=False, output=badout)
+ self.assertEqual(2, edata.returncode, 'Unexpected
return code')
+ except IOError:
+ pass
# on GnuPG 1.4, you sometimes don't get any FAILURE
messages, in
# which case status will not be set
if edata.status:
- self.assertEqual(edata.status, message)
+ message = '%s (%s)' % (message, badout)
+ self.assertIn(edata.status, message)
finally:
os.chmod(encfname, 0o700)
os.remove(encfname)
@@ -1578,6 +1587,24 @@
def test_passphrase_encoding(self):
self.assertRaises(UnicodeEncodeError, self.gpg.decrypt, 'foo',
passphrase=u'I’ll')
+ def test_configured_group(self):
+ # See issue #249
+ conf = 'group somegroup = BADF00D15BAD\n'
+ fn = os.path.join(self.homedir, 'gpg.conf')
+ with open(fn, 'w') as f:
+ f.write(conf)
+ gpg = gnupg.GPG(gnupghome=self.homedir, gpgbinary=GPGBINARY)
+ self.assertEqual(gpg.version, self.gpg.version)
+
+ def test_exception_propagation(self):
+ if sys.version_info[0] < 3:
+ raise unittest.SkipTest('python 2 is too loose with Unicode')
+ key = self.generate_key('Andrew', 'Able', 'alpha.com',
passphrase='andy')
+ self.assertEqual(0, key.returncode, 'Non-zero return code')
+ andrew = key.fingerprint
+ stream = io.StringIO(u'Hello, world!') # make the wrong type of stream
+ self.assertRaises(TypeError, self.gpg.encrypt_file, stream, [andrew],
armor=False)
+
TEST_GROUPS = {
'sign':
@@ -1600,7 +1627,7 @@
'basic':
set(['test_environment', 'test_list_keys_initial', 'test_nogpg',
'test_make_args', 'test_quote_with_shell']),
'test':
- set(['test_passphrase_encoding']),
+ set(['test_filenames_with_spaces']),
}
@@ -1621,11 +1648,19 @@
def init_logging():
+ class PrimegenFilter(logging.Filter):
+ def filter(self, record):
+ arg = record.args
+ if isinstance(arg, (list, tuple)) and len(arg) > 0:
+ arg = arg[0]
+ return not arg or not isinstance(arg, unicode) or '[GNUPG:]
PROGRESS primegen' not in arg
+
logging.basicConfig(level=logging.DEBUG,
filename='test_gnupg.log',
filemode='w',
format='%(asctime)s %(levelname)-5s %(name)-10s '
'%(threadName)-10s %(lineno)4d %(message)s')
+ logging.root.handlers[0].addFilter(PrimegenFilter())
def main():