@@ -78,14 +78,20 @@ def assert_signals(cls, context, attr, expected):
7878 d = getattr (context , attr )
7979 cls .assertTrue (all (d [s ] if s in expected else not d [s ] for s in d ))
8080
81- RoundingModes = {
82- C : (C .ROUND_UP , C .ROUND_DOWN , C .ROUND_CEILING , C .ROUND_FLOOR ,
83- C .ROUND_HALF_UP , C .ROUND_HALF_DOWN , C .ROUND_HALF_EVEN ,
84- C .ROUND_05UP ) if C else None ,
85- P : (P .ROUND_UP , P .ROUND_DOWN , P .ROUND_CEILING , P .ROUND_FLOOR ,
86- P .ROUND_HALF_UP , P .ROUND_HALF_DOWN , P .ROUND_HALF_EVEN ,
87- P .ROUND_05UP )
88- }
81+ ROUND_UP = P .ROUND_UP
82+ ROUND_DOWN = P .ROUND_DOWN
83+ ROUND_CEILING = P .ROUND_CEILING
84+ ROUND_FLOOR = P .ROUND_FLOOR
85+ ROUND_HALF_UP = P .ROUND_HALF_UP
86+ ROUND_HALF_DOWN = P .ROUND_HALF_DOWN
87+ ROUND_HALF_EVEN = P .ROUND_HALF_EVEN
88+ ROUND_05UP = P .ROUND_05UP
89+
90+ RoundingModes = [
91+ ROUND_UP , ROUND_DOWN , ROUND_CEILING , ROUND_FLOOR ,
92+ ROUND_HALF_UP , ROUND_HALF_DOWN , ROUND_HALF_EVEN ,
93+ ROUND_05UP
94+ ]
8995
9096# Tests are built around these assumed context defaults.
9197# test_main() restores the original context.
@@ -96,7 +102,7 @@ def assert_signals(cls, context, attr, expected):
96102def init (m ):
97103 if not m : return
98104 DefaultTestContext = m .Context (
99- prec = 9 , rounding = m . ROUND_HALF_EVEN , traps = dict .fromkeys (Signals [m ], 0 )
105+ prec = 9 , rounding = ROUND_HALF_EVEN , traps = dict .fromkeys (Signals [m ], 0 )
100106 )
101107 m .setcontext (DefaultTestContext )
102108
@@ -229,14 +235,14 @@ def setUp(self):
229235 'xor' :'logical_xor' }
230236
231237 # Map test-case names to roundings.
232- self .RoundingDict = {'ceiling' : self . decimal . ROUND_CEILING ,
233- 'down' : self . decimal . ROUND_DOWN ,
234- 'floor' : self . decimal . ROUND_FLOOR ,
235- 'half_down' : self . decimal . ROUND_HALF_DOWN ,
236- 'half_even' : self . decimal . ROUND_HALF_EVEN ,
237- 'half_up' : self . decimal . ROUND_HALF_UP ,
238- 'up' : self . decimal . ROUND_UP ,
239- '05up' : self . decimal . ROUND_05UP }
238+ self .RoundingDict = {'ceiling' : ROUND_CEILING ,
239+ 'down' : ROUND_DOWN ,
240+ 'floor' : ROUND_FLOOR ,
241+ 'half_down' : ROUND_HALF_DOWN ,
242+ 'half_even' : ROUND_HALF_EVEN ,
243+ 'half_up' : ROUND_HALF_UP ,
244+ 'up' : ROUND_UP ,
245+ '05up' : ROUND_05UP }
240246
241247 # Map the test cases' error names to the actual errors.
242248 self .ErrorNames = {'clamped' : self .decimal .Clamped ,
@@ -2101,9 +2107,6 @@ def test_none_args(self):
21012107 Inexact = self .decimal .Inexact
21022108 Rounded = self .decimal .Rounded
21032109 Clamped = self .decimal .Clamped
2104- ROUND_HALF_EVEN = self .decimal .ROUND_HALF_EVEN
2105- ROUND_DOWN = self .decimal .ROUND_DOWN
2106- ROUND_UP = self .decimal .ROUND_UP
21072110
21082111 with localcontext (Context ()) as c :
21092112 c .prec = 7
@@ -2430,7 +2433,6 @@ def test_pickle(self):
24302433
24312434 def test_int (self ):
24322435 Decimal = self .decimal .Decimal
2433- ROUND_DOWN = self .decimal .ROUND_DOWN
24342436
24352437 for x in range (- 250 , 250 ):
24362438 s = '%0.2f' % (x / 100.0 )
@@ -2448,7 +2450,6 @@ def test_int(self):
24482450
24492451 def test_trunc (self ):
24502452 Decimal = self .decimal .Decimal
2451- ROUND_DOWN = self .decimal .ROUND_DOWN
24522453
24532454 for x in range (- 250 , 250 ):
24542455 s = '%0.2f' % (x / 100.0 )
@@ -2491,8 +2492,6 @@ class MyDecimal(Decimal):
24912492 def test_create_decimal_from_float (self ):
24922493 Decimal = self .decimal .Decimal
24932494 Context = self .decimal .Context
2494- ROUND_DOWN = self .decimal .ROUND_DOWN
2495- ROUND_UP = self .decimal .ROUND_UP
24962495 Inexact = self .decimal .Inexact
24972496
24982497 context = Context (prec = 5 , rounding = ROUND_DOWN )
@@ -2522,7 +2521,6 @@ def test_quantize(self):
25222521 Decimal = self .decimal .Decimal
25232522 Context = self .decimal .Context
25242523 InvalidOperation = self .decimal .InvalidOperation
2525- ROUND_DOWN = self .decimal .ROUND_DOWN
25262524
25272525 c = Context (Emax = 99999 , Emin = - 99999 )
25282526 self .assertEqual (
@@ -2723,7 +2721,6 @@ def test_none_args(self):
27232721 InvalidOperation = self .decimal .InvalidOperation
27242722 DivisionByZero = self .decimal .DivisionByZero
27252723 Overflow = self .decimal .Overflow
2726- ROUND_HALF_EVEN = self .decimal .ROUND_HALF_EVEN
27272724
27282725 c1 = Context ()
27292726 c2 = Context (prec = None , rounding = None , Emax = None , Emin = None ,
@@ -2739,6 +2736,21 @@ def test_none_args(self):
27392736 assert_signals (self , c , 'traps' , [InvalidOperation , DivisionByZero ,
27402737 Overflow ])
27412738
2739+ @cpython_only
2740+ def test_from_legacy_strings (self ):
2741+ import _testcapi
2742+ c = self .decimal .Context ()
2743+
2744+ for rnd in RoundingModes :
2745+ c .rounding = _testcapi .unicode_legacy_string (rnd )
2746+ self .assertEqual (c .rounding , rnd )
2747+
2748+ s = _testcapi .unicode_legacy_string ('' )
2749+ self .assertRaises (TypeError , setattr , c , 'rounding' , s )
2750+
2751+ s = _testcapi .unicode_legacy_string ('ROUND_\x00 UP' )
2752+ self .assertRaises (TypeError , setattr , c , 'rounding' , s )
2753+
27422754 def test_pickle (self ):
27432755
27442756 Context = self .decimal .Context
@@ -2762,7 +2774,7 @@ def test_pickle(self):
27622774 # Test interchangeability
27632775 combinations = [(C , P ), (P , C )] if C else [(P , P )]
27642776 for dumper , loader in combinations :
2765- for ri , _ in enumerate (RoundingModes [ dumper ] ):
2777+ for ri , _ in enumerate (RoundingModes ):
27662778 for fi , _ in enumerate (OrderedSignals [dumper ]):
27672779 for ti , _ in enumerate (OrderedSignals [dumper ]):
27682780
@@ -2776,7 +2788,7 @@ def test_pickle(self):
27762788 sys .modules ['decimal' ] = dumper
27772789 c = dumper .Context (
27782790 prec = prec , Emin = emin , Emax = emax ,
2779- rounding = RoundingModes [dumper ][ ri ],
2791+ rounding = RoundingModes [ri ],
27802792 capitals = caps , clamp = clamp ,
27812793 flags = OrderedSignals [dumper ][:fi ],
27822794 traps = OrderedSignals [dumper ][:ti ]
@@ -2791,7 +2803,7 @@ def test_pickle(self):
27912803 self .assertEqual (d .prec , prec )
27922804 self .assertEqual (d .Emin , emin )
27932805 self .assertEqual (d .Emax , emax )
2794- self .assertEqual (d .rounding , RoundingModes [loader ][ ri ])
2806+ self .assertEqual (d .rounding , RoundingModes [ri ])
27952807 self .assertEqual (d .capitals , caps )
27962808 self .assertEqual (d .clamp , clamp )
27972809 assert_signals (self , d , 'flags' , OrderedSignals [loader ][:fi ])
@@ -3593,7 +3605,6 @@ def test_flags_irrelevant(self):
35933605 Underflow = self .decimal .Underflow
35943606 Clamped = self .decimal .Clamped
35953607 Subnormal = self .decimal .Subnormal
3596- ROUND_HALF_EVEN = self .decimal .ROUND_HALF_EVEN
35973608
35983609 def raise_error (context , flag ):
35993610 if self .decimal == C :
@@ -3960,17 +3971,6 @@ def test_invalid_context(self):
39603971 self .assertRaises (ValueError , setattr , c , 'Emin' , 1 )
39613972 self .assertRaises (TypeError , setattr , c , 'Emin' , (1 ,2 ,3 ))
39623973
3963- # rounding: always raise TypeError in order to get consistent
3964- # exceptions across implementations. In decimal, rounding
3965- # modes are strings, in _decimal they are integers. The idea
3966- # is to view rounding as an abstract type and not mind the
3967- # implementation details.
3968- # Hence, a user should view the rounding modes as if they
3969- # had been defined in a language that supports abstract
3970- # data types, e.g. ocaml:
3971- #
3972- # type rounding = ROUND_DOWN | ROUND_HALF_UP | ... ;;
3973- #
39743974 self .assertRaises (TypeError , setattr , c , 'rounding' , - 1 )
39753975 self .assertRaises (TypeError , setattr , c , 'rounding' , 9 )
39763976 self .assertRaises (TypeError , setattr , c , 'rounding' , 1.0 )
@@ -4023,8 +4023,6 @@ def test_context_subclassing(self):
40234023 decimal = self .decimal
40244024 Decimal = decimal .Decimal
40254025 Context = decimal .Context
4026- ROUND_HALF_EVEN = decimal .ROUND_HALF_EVEN
4027- ROUND_DOWN = decimal .ROUND_DOWN
40284026 Clamped = decimal .Clamped
40294027 DivisionByZero = decimal .DivisionByZero
40304028 Inexact = decimal .Inexact
@@ -4192,7 +4190,7 @@ def test_context_repr(self):
41924190 c .prec = 425000000
41934191 c .Emax = 425000000
41944192 c .Emin = - 425000000
4195- c .rounding = self . decimal . ROUND_HALF_DOWN
4193+ c .rounding = ROUND_HALF_DOWN
41964194 c .capitals = 0
41974195 c .clamp = 1
41984196 for sig in OrderedSignals [self .decimal ]:
@@ -4584,7 +4582,6 @@ def test_py_decimal_id(self):
45844582 def test_py_rescale (self ):
45854583 # Coverage
45864584 Decimal = P .Decimal
4587- ROUND_UP = P .ROUND_UP
45884585 localcontext = P .localcontext
45894586
45904587 with localcontext () as c :
@@ -4594,7 +4591,6 @@ def test_py_rescale(self):
45944591 def test_py__round (self ):
45954592 # Coverage
45964593 Decimal = P .Decimal
4597- ROUND_UP = P .ROUND_UP
45984594
45994595 self .assertRaises (ValueError , Decimal ("3.1234" )._round , 0 , ROUND_UP )
46004596
@@ -4663,11 +4659,6 @@ def test_constants(self):
46634659 self .assertEqual (C .DECIMAL128 , 128 )
46644660 self .assertEqual (C .IEEE_CONTEXT_MAX_BITS , 512 )
46654661
4666- # Rounding modes
4667- for i , v in enumerate (RoundingModes [C ]):
4668- self .assertEqual (v , i )
4669- self .assertEqual (C .ROUND_TRUNC , 8 )
4670-
46714662 # Conditions
46724663 for i , v in enumerate (cond ):
46734664 self .assertEqual (v , 1 << i )
@@ -4727,7 +4718,6 @@ def test_c_context_repr(self):
47274718 # in the same order.
47284719 DefaultContext = C .DefaultContext
47294720 FloatOperation = C .FloatOperation
4730- ROUND_HALF_DOWN = C .ROUND_HALF_DOWN
47314721
47324722 c = DefaultContext .copy ()
47334723
@@ -4800,7 +4790,6 @@ def test_c_context_errors(self):
48004790 self .assertRaises (OverflowError , Context , prec = int_max + 1 )
48014791 self .assertRaises (OverflowError , Context , Emax = int_max + 1 )
48024792 self .assertRaises (OverflowError , Context , Emin = - int_max - 2 )
4803- self .assertRaises (OverflowError , Context , rounding = int_max + 1 )
48044793 self .assertRaises (OverflowError , Context , clamp = int_max + 1 )
48054794 self .assertRaises (OverflowError , Context , capitals = int_max + 1 )
48064795
@@ -4812,14 +4801,6 @@ def test_c_context_errors(self):
48124801 self .assertRaises (ValueError , setattr , c , attr , int_max )
48134802 self .assertRaises (ValueError , setattr , c , attr , - int_max - 1 )
48144803
4815- # OverflowError, general TypeError
4816- for attr in ('rounding' ,):
4817- self .assertRaises (OverflowError , setattr , c , attr , int_max + 1 )
4818- self .assertRaises (OverflowError , setattr , c , attr , - int_max - 2 )
4819- if sys .platform != 'win32' :
4820- self .assertRaises (TypeError , setattr , c , attr , int_max )
4821- self .assertRaises (TypeError , setattr , c , attr , - int_max - 1 )
4822-
48234804 # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
48244805 if C .MAX_PREC == 425000000 :
48254806 self .assertRaises (OverflowError , getattr (c , '_unsafe_setprec' ),
@@ -4862,6 +4843,17 @@ def test_c_context_errors(self):
48624843 self .assertRaises (TypeError , setcontext , "xyz" )
48634844 setcontext (saved_context )
48644845
4846+ def test_rounding_strings_interned (self ):
4847+
4848+ self .assertIs (C .ROUND_UP , P .ROUND_UP )
4849+ self .assertIs (C .ROUND_DOWN , P .ROUND_DOWN )
4850+ self .assertIs (C .ROUND_CEILING , P .ROUND_CEILING )
4851+ self .assertIs (C .ROUND_FLOOR , P .ROUND_FLOOR )
4852+ self .assertIs (C .ROUND_HALF_UP , P .ROUND_HALF_UP )
4853+ self .assertIs (C .ROUND_HALF_DOWN , P .ROUND_HALF_DOWN )
4854+ self .assertIs (C .ROUND_HALF_EVEN , P .ROUND_HALF_EVEN )
4855+ self .assertIs (C .ROUND_05UP , P .ROUND_05UP )
4856+
48654857 @requires_extra_functionality
48664858 def test_c_context_errors_extra (self ):
48674859 Context = C .Context
@@ -4908,7 +4900,6 @@ def test_c_context_errors_extra(self):
49084900 def test_c_valid_context (self ):
49094901 # These tests are for code coverage in _decimal.
49104902 DefaultContext = C .DefaultContext
4911- ROUND_HALF_UP = C .ROUND_HALF_UP
49124903 Clamped = C .Clamped
49134904 Underflow = C .Underflow
49144905 Inexact = C .Inexact
@@ -5000,7 +4991,6 @@ def test_c_format(self):
50004991 def test_c_integral (self ):
50014992 Decimal = C .Decimal
50024993 Inexact = C .Inexact
5003- ROUND_UP = C .ROUND_UP
50044994 localcontext = C .localcontext
50054995
50064996 x = Decimal (10 )
@@ -5034,7 +5024,6 @@ def test_c_funcs(self):
50345024 Decimal = C .Decimal
50355025 InvalidOperation = C .InvalidOperation
50365026 DivisionByZero = C .DivisionByZero
5037- ROUND_UP = C .ROUND_UP
50385027 getcontext = C .getcontext
50395028 localcontext = C .localcontext
50405029
@@ -5237,7 +5226,7 @@ def assertIsExclusivelySet(signal, signal_dict):
52375226 lim = len (OrderedSignals [C ])
52385227 for r in range (lim ):
52395228 for t in range (lim ):
5240- for round in RoundingModes [ C ] :
5229+ for round in RoundingModes :
52415230 flags = random .sample (OrderedSignals [C ], r )
52425231 traps = random .sample (OrderedSignals [C ], t )
52435232 prec = random .randrange (1 , 10000 )
0 commit comments