From 58338ccb980fc019f26b036bf8772dee69cb5c0d Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Thu, 8 Jul 2010 21:27:05 +0000 Subject: [PATCH] Issue #9136: Fix 'dictionary changed size during iteration' RuntimeError produced when profiling the decimal module. This was due to a dangerous iteration over 'locals()' in Context.__init__. (Backport of r82656 from release27-maint.) --- Lib/decimal.py | 46 +++++++++++++++++++++++++++++++--------------- Misc/NEWS | 4 ++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py index 3819759b02b..b3bdc7f0c5d 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -3690,22 +3690,38 @@ class Context(object): Emin=None, Emax=None, capitals=None, _clamp=0, _ignored_flags=None): - if flags is None: - flags = [] + # Set defaults; for everything except flags and _ignored_flags, + # inherit from DefaultContext. + try: + dc = DefaultContext + except NameError: + pass + + self.prec = prec if prec is not None else dc.prec + self.rounding = rounding if rounding is not None else dc.rounding + self.Emin = Emin if Emin is not None else dc.Emin + self.Emax = Emax if Emax is not None else dc.Emax + self.capitals = capitals if capitals is not None else dc.capitals + self._clamp = _clamp if _clamp is not None else dc._clamp + if _ignored_flags is None: - _ignored_flags = [] - if not isinstance(flags, dict): - flags = dict([(s, int(s in flags)) for s in _signals]) - del s - if traps is not None and not isinstance(traps, dict): - traps = dict([(s, int(s in traps)) for s in _signals]) - del s - for name, val in locals().items(): - if val is None: - setattr(self, name, _copy.copy(getattr(DefaultContext, name))) - else: - setattr(self, name, val) - del self.self + self._ignored_flags = [] + else: + self._ignored_flags = _ignored_flags + + if traps is None: + self.traps = dc.traps.copy() + elif not isinstance(traps, dict): + self.traps = dict((s, int(s in traps)) for s in _signals) + else: + self.traps = traps + + if flags is None: + self.flags = dict.fromkeys(_signals, 0) + elif not isinstance(flags, dict): + self.flags = dict((s, int(s in flags)) for s in _signals) + else: + self.flags = flags def __repr__(self): """Show the current context.""" diff --git a/Misc/NEWS b/Misc/NEWS index 70f8853a5e7..0efac1b772a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -81,6 +81,10 @@ C-API Library ------- +- Issue #9136: Fix 'dictionary changed size during iteration' + RuntimeError produced when profiling the decimal module. This was + due to a dangerous iteration over 'locals()' in Context.__init__. + - Fix extreme speed issue in Decimal.pow when the base is an exact power of 10 and the exponent is tiny (for example, Decimal(10) ** Decimal('1e-999999999')).