Repository navigation
gh-160945: Fix _pydecimal losing companion signal flags when a signal is trapped - #160947
arpittkhandelwal wants to merge 5 commits into
Conversation
…signal is trapped
picnixz
left a comment
There was a problem hiding this comment.
There are unrelated whitespace changes.
| def _defer_traps(self): | ||
| """Defer trapped signals until the end of the with block. | ||
| Some operations signal several conditions at once (for |
There was a problem hiding this comment.
This is clearly AI prose and should have been trimmed.
|
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
|
I have made the requested changes; please review again. Trimmed the |
|
Thanks for making the requested changes! @picnixz: please review the changes made to this pull request. |
| context._raise_error(InvalidOperation, 'x % 0')) | ||
| with context._defer_traps(): | ||
| return (context._raise_error(DivisionByZero, 'x // 0', | ||
| sign), |
There was a problem hiding this comment.
This is an unrelated whitespace new line change.
| elif name == 'flags' or name == 'traps': | ||
| return self._set_signal_dict(name, value) | ||
| elif name == '_ignored_flags': | ||
| elif name in ('_ignored_flags', '_deferred_traps', '_deferred_error'): |
There was a problem hiding this comment.
| elif name in ('_ignored_flags', '_deferred_traps', '_deferred_error'): | |
| elif name in {'_ignored_flags', '_deferred_traps', '_deferred_error'}: |
| elif name == 'flags' or name == 'traps': | ||
| return self._set_signal_dict(name, value) | ||
| elif name == '_ignored_flags': | ||
| elif name in ('_ignored_flags', '_deferred_traps', '_deferred_error'): |
There was a problem hiding this comment.
You need test for that as well.
|
I have made the requested changes; please review again.
|
|
Thanks for making the requested changes! @picnixz: please review the changes made to this pull request. |
| ans = context._raise_error(Overflow, 'above Emax', | ||
| self._sign) |
There was a problem hiding this comment.
| ans = context._raise_error(Overflow, 'above Emax', | |
| self._sign) | |
| ans = context._raise_error(Overflow, 'above Emax', self._sign) |
| with context._defer_traps(): | ||
| # check if rounding pushed the exponent out of range |
There was a problem hiding this comment.
| with context._defer_traps(): | |
| # check if rounding pushed the exponent out of range | |
| # check if rounding pushed the exponent out of range | |
| with context._defer_traps(): |
| for exception in (Underflow, Subnormal, Inexact, Rounded, | ||
| Clamped): |
There was a problem hiding this comment.
| for exception in (Underflow, Subnormal, Inexact, Rounded, | |
| Clamped): | |
| for exception in Underflow, Subnormal, Inexact, Rounded, Clamped: |
…bove with, drop redundant parens
|
I have made the requested changes; please review again.
|
|
Thanks for making the requested changes! @picnixz: please review the changes made to this pull request. |
| if self._deferred_traps == 1: | ||
| self._deferred_error = None | ||
| raise |
There was a problem hiding this comment.
I wonder: should we really keep self._deferred_error even in the case of an exception? I don't want to keep possible cycles but I don't know whether it's.. reasonable to clear the errors here in general.
Is it possible to see what the C implementation does?
| def _defer_traps(self): | ||
| """Defer trapped signals until the end of the with block. | ||
|
|
||
| _raise_error sets the flag of every signal in the block and |
There was a problem hiding this comment.
| _raise_error sets the flag of every signal in the block and | |
| _raise_error() sets the flag of every signal in the block and |
|
I have made the requested changes; please review again.
|
|
Thanks for making the requested changes! @picnixz: please review the changes made to this pull request. |
_pydecimallost the flags of companion conditions when an operationsignalled several conditions and one of them was trapped:
Context._raise_error()set one signal's flag and raised at once, sothe calls signalling the remaining conditions never ran.
_decimalrecords all conditions in the context status before raising. The
exception raised is unchanged; only the flags are now complete.
Context._defer_traps()defers a trapped exception raised inside theblock until the block exits;
_raise_errorstill sets every flag andreturns the default response. The sequential multi-signal sequences in
Decimal._fix,__divmod__,__pow__,quantize,to_integral_exactandnext_towardare wrapped in it.Tests: new
ContextFlags.test_trapped_signal_sets_companion_flags,covering trapped Overflow, Inexact, Underflow, Subnormal and
DivisionByZero. It runs against both implementations, fails on
_pydecimalwithout this change, andtest_decimalpasses (596tests).
Differential fuzzing against
_decimal(5,793 seeded cases) matchedresults, exceptions and flags everywhere except 6 cases of a separate
pre-existing difference: with
clamp=1and a zero quotient,__divmod__does not finalise the quotient in_pydecimal, soClampedis not signalled. Not addressed here.Disclosure: this change was drafted with AI assistance and reviewed by
the author, who takes responsibility for it.