← 输入框|github.com|刷新
Skip to content

gh-160945: Fix _pydecimal losing companion signal flags when a signal is trapped - #160947

Open
arpittkhandelwal wants to merge 5 commits into
python:mainfrom
arpittkhandelwal:fix/pydecimal-trapped-flags
Open

arpittkhandelwal wants to merge 5 commits into
python:mainfrom
arpittkhandelwal:fix/pydecimal-trapped-flags

Conversation

@arpittkhandelwal

@arpittkhandelwal arpittkhandelwal commented Oct 30, 2026 •

Copy link
Copy Markdown

_pydecimal lost the flags of companion conditions when an operation
signalled several conditions and one of them was trapped:
Context._raise_error() set one signal's flag and raised at once, so
the calls signalling the remaining conditions never ran. _decimal
records 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 the
block until the block exits; _raise_error still sets every flag and
returns the default response. The sequential multi-signal sequences in
Decimal._fix, __divmod__, __pow__, quantize,
to_integral_exact and next_toward are 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
_pydecimal without this change, and test_decimal passes (596
tests).

Differential fuzzing against _decimal (5,793 seeded cases) matched
results, exceptions and flags everywhere except 6 cases of a separate
pre-existing difference: with clamp=1 and a zero quotient,
__divmod__ does not finalise the quotient in _pydecimal, so
Clamped is not signalled. Not addressed here.

Disclosure: this change was drafted with AI assistance and reviewed by
the author, who takes responsibility for it.

@python-cla-bot

python-cla-bot Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@picnixz picnixz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are unrelated whitespace changes.

Comment thread Lib/_pydecimal.py Outdated
def _defer_traps(self):
"""Defer trapped signals until the end of the with block.
Some operations signal several conditions at once (for

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clearly AI prose and should have been trimmed.

@bedevere-app

bedevere-app Bot commented Oct 30, 2026

Copy link
Copy Markdown

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. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@arpittkhandelwal

Copy link
Copy Markdown
Author

I have made the requested changes; please review again.

Trimmed the _defer_traps docstring and the comments around it, dropped the unrelated comment reflow in _fix, and shortened this description. The remaining whitespace changes are the re-indentation of the code wrapped in with context._defer_traps(): blocks and the line re-wraps that the extra indentation forces. test_decimal passes (596 tests).

@bedevere-app

bedevere-app Bot commented Oct 30, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@picnixz: please review the changes made to this pull request.

@bedevere-app
bedevere-app Bot requested a review from picnixz October 30, 2026 11:51
Comment thread Lib/_pydecimal.py Outdated
context._raise_error(InvalidOperation, 'x % 0'))
with context._defer_traps():
return (context._raise_error(DivisionByZero, 'x // 0',
sign),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unrelated whitespace new line change.

Comment thread Lib/_pydecimal.py Outdated
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'):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
elif name in ('_ignored_flags', '_deferred_traps', '_deferred_error'):
elif name in {'_ignored_flags', '_deferred_traps', '_deferred_error'}:

Comment thread Lib/_pydecimal.py Outdated
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'):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need test for that as well.

@arpittkhandelwal

Copy link
Copy Markdown
Author

I have made the requested changes; please review again.

  • Restored the original single line in __divmod__ (removed the unrelated newline change).
  • Used a set literal in Context.__setattr__, as suggested.
  • Added test_deferred_traps_attributes in PyContextFlags, covering the _deferred_traps and _deferred_error attributes and the state reset after a trapped operation.

@bedevere-app

bedevere-app Bot commented Oct 30, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@picnixz: please review the changes made to this pull request.

@bedevere-app
bedevere-app Bot requested a review from picnixz October 30, 2026 16:01
Comment thread Lib/_pydecimal.py Outdated
Comment on lines +1779 to +1780
ans = context._raise_error(Overflow, 'above Emax',
self._sign)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ans = context._raise_error(Overflow, 'above Emax',
self._sign)
ans = context._raise_error(Overflow, 'above Emax', self._sign)

Comment thread Lib/_pydecimal.py Outdated
Comment on lines +1776 to +1777
with context._defer_traps():
# check if rounding pushed the exponent out of range

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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():

Comment thread Lib/_pydecimal.py Outdated
Comment on lines +2567 to +2568
for exception in (Underflow, Subnormal, Inexact, Rounded,
Clamped):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for exception in (Underflow, Subnormal, Inexact, Rounded,
Clamped):
for exception in Underflow, Subnormal, Inexact, Rounded, Clamped:

@arpittkhandelwal

Copy link
Copy Markdown
Author

I have made the requested changes; please review again.

  • Joined the context._raise_error(Overflow, 'above Emax', self._sign) call onto a single line in _fix.
  • Moved the "check if rounding pushed the exponent out of range" comment above the with context._defer_traps(): block.
  • Dropped the redundant parentheses in the for exception in ... loop in __pow__.

@bedevere-app

bedevere-app Bot commented Oct 30, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@picnixz: please review the changes made to this pull request.

@bedevere-app
bedevere-app Bot requested a review from picnixz October 30, 2026 17:48
Comment thread Lib/_pydecimal.py Outdated
Comment on lines +4176 to +4178
if self._deferred_traps == 1:
self._deferred_error = None
raise

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment thread Lib/_pydecimal.py Outdated
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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_raise_error sets the flag of every signal in the block and
_raise_error() sets the flag of every signal in the block and

@arpittkhandelwal

Copy link
Copy Markdown
Author

I have made the requested changes; please review again.

  • _raise_error() in the _defer_traps docstring, as suggested.
  • On keeping _deferred_error when an exception propagates: you are right to question it. The C implementation never stores an exception on the context at all — operations only accumulate condition flags in the context status (dec_addstatus ORs them into ctx->status), and the exception is created from those flags once the operation completes; if the operation itself fails, no decimal error is left behind. _defer_traps now clears _deferred_error unconditionally when an exception propagates, at every nesting level: the operation is aborted, so the propagating exception wins, and the context never retains an exception object (the clean-exit path already detached it before raising). The signal flags themselves are still set, as in C. The new test_deferred_traps_exception_discards_error covers the nested case.

@bedevere-app

bedevere-app Bot commented Oct 30, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@picnixz: please review the changes made to this pull request.

@bedevere-app
bedevere-app Bot requested a review from picnixz October 30, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants