mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	The methods always return Decimal classes, even if they're
executed through a subclass (thanks Mark Dickinson). Added a bit of testing for this.
This commit is contained in:
		
							parent
							
								
									b67da23718
								
							
						
					
					
						commit
						6c398da0e7
					
				
					 2 changed files with 53 additions and 34 deletions
				
			
		|  | @ -1473,7 +1473,7 @@ def _fix_nan(self, context): | |||
|                 pos += 1 | ||||
|             payload = payload[pos:] | ||||
|             return Decimal((self._sign, payload, self._exp)) | ||||
|         return self | ||||
|         return Decimal(self) | ||||
| 
 | ||||
|     def _fix(self, context): | ||||
|         """Round if it is necessary to keep self within prec precision. | ||||
|  | @ -1494,7 +1494,7 @@ def _fix(self, context): | |||
|                 return self._fix_nan(context) | ||||
|             else: | ||||
|                 # self is +/-Infinity; return unaltered | ||||
|                 return self | ||||
|                 return Decimal(self) | ||||
| 
 | ||||
|         # if self is zero then exponent should be between Etiny and | ||||
|         # Emax if _clamp==0, and between Etiny and Etop if _clamp==1. | ||||
|  | @ -1507,7 +1507,7 @@ def _fix(self, context): | |||
|                 context._raise_error(Clamped) | ||||
|                 return Decimal((self._sign, (0,), new_exp)) | ||||
|             else: | ||||
|                 return self | ||||
|                 return Decimal(self) | ||||
| 
 | ||||
|         # exp_min is the smallest allowable exponent of the result, | ||||
|         # equal to max(self.adjusted()-context.prec+1, Etiny) | ||||
|  | @ -1551,7 +1551,7 @@ def _fix(self, context): | |||
|             return Decimal((self._sign, self_padded, Etop)) | ||||
| 
 | ||||
|         # here self was representable to begin with; return unchanged | ||||
|         return self | ||||
|         return Decimal(self) | ||||
| 
 | ||||
|     _pick_rounding_function = {} | ||||
| 
 | ||||
|  | @ -1678,10 +1678,10 @@ def _power_modulo(self, other, modulo, context=None): | |||
|                 return context._raise_error(InvalidOperation, 'sNaN', | ||||
|                                         1, modulo) | ||||
|             if self_is_nan: | ||||
|                 return self | ||||
|                 return self._fix_nan(context) | ||||
|             if other_is_nan: | ||||
|                 return other | ||||
|             return modulo | ||||
|                 return other._fix_nan(context) | ||||
|             return modulo._fix_nan(context) | ||||
| 
 | ||||
|         # check inputs: we apply same restrictions as Python's pow() | ||||
|         if not (self._isinteger() and | ||||
|  | @ -2179,7 +2179,7 @@ def quantize(self, exp, rounding=None, context=None, watchexp=True): | |||
| 
 | ||||
|             if exp._isinfinity() or self._isinfinity(): | ||||
|                 if exp._isinfinity() and self._isinfinity(): | ||||
|                     return self  # if both are inf, it is OK | ||||
|                     return Decimal(self)  # if both are inf, it is OK | ||||
|                 return context._raise_error(InvalidOperation, | ||||
|                                         'quantize with one INF') | ||||
| 
 | ||||
|  | @ -2254,7 +2254,7 @@ def _rescale(self, exp, rounding): | |||
|         rounding = rounding mode | ||||
|         """ | ||||
|         if self._is_special: | ||||
|             return self | ||||
|             return Decimal(self) | ||||
|         if not self: | ||||
|             return Decimal((self._sign, (0,), exp)) | ||||
| 
 | ||||
|  | @ -2285,9 +2285,9 @@ def to_integral_exact(self, rounding=None, context=None): | |||
|             ans = self._check_nans(context=context) | ||||
|             if ans: | ||||
|                 return ans | ||||
|             return self | ||||
|             return Decimal(self) | ||||
|         if self._exp >= 0: | ||||
|             return self | ||||
|             return Decimal(self) | ||||
|         if not self: | ||||
|             return Decimal((self._sign, (0,), 0)) | ||||
|         if context is None: | ||||
|  | @ -2310,9 +2310,9 @@ def to_integral_value(self, rounding=None, context=None): | |||
|             ans = self._check_nans(context=context) | ||||
|             if ans: | ||||
|                 return ans | ||||
|             return self | ||||
|             return Decimal(self) | ||||
|         if self._exp >= 0: | ||||
|             return self | ||||
|             return Decimal(self) | ||||
|         else: | ||||
|             return self._rescale(0, rounding) | ||||
| 
 | ||||
|  | @ -2426,6 +2426,9 @@ def max(self, other, context=None): | |||
|         """ | ||||
|         other = _convert_other(other, raiseit=True) | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
| 
 | ||||
|         if self._is_special or other._is_special: | ||||
|             # If one operand is a quiet NaN and the other is number, then the | ||||
|             # number is always returned | ||||
|  | @ -2433,9 +2436,9 @@ def max(self, other, context=None): | |||
|             on = other._isnan() | ||||
|             if sn or on: | ||||
|                 if on == 1 and sn != 2: | ||||
|                     return self | ||||
|                     return self._fix_nan(context) | ||||
|                 if sn == 1 and on != 2: | ||||
|                     return other | ||||
|                     return other._fix_nan(context) | ||||
|                 return self._check_nans(other, context) | ||||
| 
 | ||||
|         c = self.__cmp__(other) | ||||
|  | @ -2455,8 +2458,6 @@ def max(self, other, context=None): | |||
|         else: | ||||
|             ans = self | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
|         if context._rounding_decision == ALWAYS_ROUND: | ||||
|             return ans._fix(context) | ||||
|         return ans | ||||
|  | @ -2469,6 +2470,9 @@ def min(self, other, context=None): | |||
|         """ | ||||
|         other = _convert_other(other, raiseit=True) | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
| 
 | ||||
|         if self._is_special or other._is_special: | ||||
|             # If one operand is a quiet NaN and the other is number, then the | ||||
|             # number is always returned | ||||
|  | @ -2476,9 +2480,9 @@ def min(self, other, context=None): | |||
|             on = other._isnan() | ||||
|             if sn or on: | ||||
|                 if on == 1 and sn != 2: | ||||
|                     return self | ||||
|                     return self._fix_nan(context) | ||||
|                 if sn == 1 and on != 2: | ||||
|                     return other | ||||
|                     return other._fix_nan(context) | ||||
|                 return self._check_nans(other, context) | ||||
| 
 | ||||
|         c = self.__cmp__(other) | ||||
|  | @ -2490,8 +2494,6 @@ def min(self, other, context=None): | |||
|         else: | ||||
|             ans = other | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
|         if context._rounding_decision == ALWAYS_ROUND: | ||||
|             return ans._fix(context) | ||||
|         return ans | ||||
|  | @ -3087,6 +3089,9 @@ def max_mag(self, other, context=None): | |||
|         """Compares the values numerically with their sign ignored.""" | ||||
|         other = _convert_other(other, raiseit=True) | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
| 
 | ||||
|         if self._is_special or other._is_special: | ||||
|             # If one operand is a quiet NaN and the other is number, then the | ||||
|             # number is always returned | ||||
|  | @ -3094,9 +3099,9 @@ def max_mag(self, other, context=None): | |||
|             on = other._isnan() | ||||
|             if sn or on: | ||||
|                 if on == 1 and sn != 2: | ||||
|                     return self | ||||
|                     return self._fix_nan(context) | ||||
|                 if sn == 1 and on != 2: | ||||
|                     return other | ||||
|                     return other._fix_nan(context) | ||||
|                 return self._check_nans(other, context) | ||||
| 
 | ||||
|         c = self.copy_abs().__cmp__(other.copy_abs()) | ||||
|  | @ -3108,8 +3113,6 @@ def max_mag(self, other, context=None): | |||
|         else: | ||||
|             ans = self | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
|         if context._rounding_decision == ALWAYS_ROUND: | ||||
|             return ans._fix(context) | ||||
|         return ans | ||||
|  | @ -3118,6 +3121,9 @@ def min_mag(self, other, context=None): | |||
|         """Compares the values numerically with their sign ignored.""" | ||||
|         other = _convert_other(other, raiseit=True) | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
| 
 | ||||
|         if self._is_special or other._is_special: | ||||
|             # If one operand is a quiet NaN and the other is number, then the | ||||
|             # number is always returned | ||||
|  | @ -3125,9 +3131,9 @@ def min_mag(self, other, context=None): | |||
|             on = other._isnan() | ||||
|             if sn or on: | ||||
|                 if on == 1 and sn != 2: | ||||
|                     return self | ||||
|                     return self._fix_nan(context) | ||||
|                 if sn == 1 and on != 2: | ||||
|                     return other | ||||
|                     return other._fix_nan(context) | ||||
|                 return self._check_nans(other, context) | ||||
| 
 | ||||
|         c = self.copy_abs().__cmp__(other.copy_abs()) | ||||
|  | @ -3139,8 +3145,6 @@ def min_mag(self, other, context=None): | |||
|         else: | ||||
|             ans = other | ||||
| 
 | ||||
|         if context is None: | ||||
|             context = getcontext() | ||||
|         if context._rounding_decision == ALWAYS_ROUND: | ||||
|             return ans._fix(context) | ||||
|         return ans | ||||
|  | @ -3296,7 +3300,7 @@ def rotate(self, other, context=None): | |||
|             return context._raise_error(InvalidOperation) | ||||
| 
 | ||||
|         if self._isinfinity(): | ||||
|             return self | ||||
|             return Decimal(self) | ||||
| 
 | ||||
|         # get values, pad if necessary | ||||
|         torot = int(other) | ||||
|  | @ -3334,7 +3338,7 @@ def scaleb (self, other, context=None): | |||
|             return context._raise_error(InvalidOperation) | ||||
| 
 | ||||
|         if self._isinfinity(): | ||||
|             return self | ||||
|             return Decimal(self) | ||||
| 
 | ||||
|         d = Decimal((self._sign, self._int, self._exp + int(other))) | ||||
|         d = d._fix(context) | ||||
|  | @ -3355,12 +3359,12 @@ def shift(self, other, context=None): | |||
|             return context._raise_error(InvalidOperation) | ||||
| 
 | ||||
|         if self._isinfinity(): | ||||
|             return self | ||||
|             return Decimal(self) | ||||
| 
 | ||||
|         # get values, pad if necessary | ||||
|         torot = int(other) | ||||
|         if not torot: | ||||
|             return self | ||||
|             return Decimal(self) | ||||
|         rotdig = self._int | ||||
|         topad = context.prec - len(rotdig) | ||||
|         if topad: | ||||
|  | @ -3751,7 +3755,7 @@ def copy_decimal(self, a): | |||
|         >>> ExtendedContext.copy_decimal(Decimal('-1.00')) | ||||
|         Decimal("-1.00") | ||||
|         """ | ||||
|         return a | ||||
|         return Decimal(a) | ||||
| 
 | ||||
|     def copy_negate(self, a): | ||||
|         """Returns a copy of the operand with the sign inverted. | ||||
|  |  | |||
|  | @ -1072,6 +1072,21 @@ def checkSameDec(operation, useOther=False): | |||
|         checkSameDec("to_eng_string") | ||||
|         checkSameDec("to_integral") | ||||
| 
 | ||||
|     def test_subclassing(self): | ||||
|         # Different behaviours when subclassing Decimal | ||||
| 
 | ||||
|         class MyDecimal(Decimal): | ||||
|             pass | ||||
| 
 | ||||
|         d1 = MyDecimal(1) | ||||
|         d2 = MyDecimal(2) | ||||
|         d = d1 + d2 | ||||
|         self.assertTrue(type(d) is Decimal) | ||||
| 
 | ||||
|         d = d1.max(d2) | ||||
|         self.assertTrue(type(d) is Decimal) | ||||
| 
 | ||||
| 
 | ||||
| class DecimalPythonAPItests(unittest.TestCase): | ||||
| 
 | ||||
|     def test_pickle(self): | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Facundo Batista
						Facundo Batista