Skip to content

Commit

Permalink
Fix #242
Browse files Browse the repository at this point in the history
  • Loading branch information
vsajip committed Oct 15, 2024
1 parent 9e2a4f5 commit 7fe897f
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
9 changes: 9 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,15 @@ user-friendly, but nevertheless it should be usable.)
a separate stream. The callable should not raise any exceptions (unless it wants
the current operation to fail).

.. versionadded:: 0.5.4
Instances of the result classes from operations now have an ``on_data_failure``
attribute, which defaults to ``None``. If an ``on_data`` callable raises an exception,
the ``on_data_failure`` attribute of the returned object from a high-level operation
is set to the first exception that was raised. The ``on_data`` callable will continue
to be called with future chunks. If you use ``on_data`` with code that can raise any
exceptions, be sure to check the ``on_data_failure`` attribute of a returned object
before using any other aspects of the result.

.. versionadded:: 0.4.2
Information on keys returned by :meth:`~gnupg.GPG.list_keys` or
:meth:`~gnupg.GPG.scan_keys` now incudes a ``subkey_info`` dictionary, which
Expand Down
18 changes: 16 additions & 2 deletions gnupg.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ class StatusHandler(object):
The base class for handling status messages from `gpg`.
"""

on_data_failure = None # set at instance level when failures occur

def __init__(self, gpg):
"""
Initialize an instance.
Expand Down Expand Up @@ -1249,24 +1251,36 @@ def _read_data(self, stream, result, on_data=None, buffer_size=1024):
# Read the contents of the file from GPG's stdout
assert buffer_size > 0
chunks = []
on_data_failure = None
while True:
data = stream.read(buffer_size)
if len(data) == 0:
if on_data:
on_data(data)
try:
on_data(data)
except Exception as e:
if on_data_failure is None:
on_data_failure = e
break
if log_everything:
logger.debug('chunk: %r' % data[:256])
append = True
if on_data:
append = on_data(data) is not False
try:
on_data_result = on_data(data)
append = on_data_result is not False
except Exception as e:
if on_data_failure is None:
on_data_failure = e
if append:
chunks.append(data)
if _py3k:
# Join using b'' or '', as appropriate
result.data = type(data)().join(chunks)
else:
result.data = ''.join(chunks)
if on_data_failure:
result.on_data_failure = on_data_failure

def _collect_output(self, process, result, writer=None, stdin=None):
"""
Expand Down
13 changes: 13 additions & 0 deletions test_gnupg.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,7 @@ def collector(data):
gpg.on_data = collector
result = gpg.encrypt(data, barbara)
self.assertEqual(0, result.returncode, 'Non-zero return code')
self.assertIsNone(result.on_data_failure)
edata = str(result)
self.assertTrue(chunks)
expected = type(chunks[0])().join(chunks)
Expand All @@ -840,9 +841,21 @@ def collector(data):
ddata = gpg.decrypt(edata, passphrase='bbrown')
self.assertEqual(0, ddata.returncode, 'Non-zero return code')
self.assertEqual(data.encode('ascii'), ddata.data, 'Round-trip must work')
self.assertIsNone(result.on_data_failure)
expected = type(chunks[0])().join(chunks)
self.assertEqual(expected.decode('ascii'), data)

# test with on-data generating an exception

def exceptor(data):
raise ValueError('exception in on_data')

chunks = []
gpg.on_data = exceptor
ddata = gpg.decrypt(edata, passphrase='bbrown')
self.assertIs(type(ddata.on_data_failure), ValueError)
self.assertEqual(str(ddata.on_data_failure), 'exception in on_data')

# test signing with encryption and verification during decryption
logger.debug('encrypting with signature')
gpg.on_data = None
Expand Down

0 comments on commit 7fe897f

Please sign in to comment.