blob: dbd58e8a6519b1907f7be8228002cae1d3659af7 [file] [log] [blame]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001# Copyright (c) 2004 Python Software Foundation.
2# All rights reserved.
3
4# Written by Eric Price <eprice at tjhsst.edu>
5# and Facundo Batista <facundo at taniquetil.com.ar>
6# and Raymond Hettinger <python at rcn.com>
7# and Aahz (aahz at pobox.com)
8# and Tim Peters
9
10"""
11These are the test cases for the Decimal module.
12
13There are two groups of tests, Arithmetic and Behaviour. The former test
14the Decimal arithmetic using the tests provided by Mike Cowlishaw. The latter
15test the pythonic behaviour according to PEP 327.
16
17Cowlishaw's tests can be downloaded from:
18
Stefan Krah1919b7e2012-03-21 18:25:23 +010019 http://speleotrove.com/decimal/dectest.zip
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000020
21This test module can be called from command line with one parameter (Arithmetic
22or Behaviour) to test each part, or without parameter to test both parts. If
23you're working through IDLE, you can import this test module and call test_main()
24with the corresponding argument.
25"""
26
Christian Heimes400adb02008-02-01 08:12:03 +000027import math
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000028import os, sys
Mark Dickinsonac256ab2010-04-03 11:08:14 +000029import operator
Mark Dickinsonb1d8e322010-05-22 18:35:36 +000030import warnings
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000031import pickle, copy
Christian Heimes400adb02008-02-01 08:12:03 +000032import unittest
Raymond Hettinger82417ca2009-02-03 03:54:28 +000033import numbers
Stefan Krah1919b7e2012-03-21 18:25:23 +010034import locale
Eric Smith3ab08ca2010-12-04 15:17:38 +000035from test.support import (run_unittest, run_doctest, is_resource_enabled,
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +030036 requires_IEEE_754, requires_docstrings,
37 requires_legacy_unicode_capi)
Hai Shif7ba40b2020-06-25 18:38:51 +080038from test.support import (TestFailed,
Stefan Krah6e467042012-11-10 23:09:04 +010039 run_with_locale, cpython_only)
Hai Shif7ba40b2020-06-25 18:38:51 +080040from test.support.import_helper import import_fresh_module
Inada Naoki902356a2020-07-20 12:02:50 +090041from test.support import warnings_helper
Raymond Hettinger0aeac102004-07-05 22:53:03 +000042import random
Stefan Krah5de1f822014-05-01 15:53:42 +020043import inspect
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020044import threading
Raymond Hettinger7c85fa42004-07-01 11:01:35 +000045
Stefan Krah39042e02020-08-10 16:32:21 +020046from _testcapi import decimal_is_special
47from _testcapi import decimal_is_nan
48from _testcapi import decimal_is_infinite
49from _testcapi import decimal_get_digits
50from _testcapi import decimal_as_triple
51from _testcapi import decimal_from_triple
52
Raymond Hettingerfed52962004-07-14 15:41:57 +000053
Stefan Krah1919b7e2012-03-21 18:25:23 +010054C = import_fresh_module('decimal', fresh=['_decimal'])
55P = import_fresh_module('decimal', blocked=['_decimal'])
56orig_sys_decimal = sys.modules['decimal']
57
58# fractions module must import the correct decimal module.
59cfractions = import_fresh_module('fractions', fresh=['fractions'])
60sys.modules['decimal'] = P
61pfractions = import_fresh_module('fractions', fresh=['fractions'])
62sys.modules['decimal'] = C
63fractions = {C:cfractions, P:pfractions}
64sys.modules['decimal'] = orig_sys_decimal
65
66
67# Useful Test Constant
68Signals = {
69 C: tuple(C.getcontext().flags.keys()) if C else None,
70 P: tuple(P.getcontext().flags.keys())
71}
Mark Dickinsonc69160e2010-05-04 14:35:33 +000072# Signals ordered with respect to precedence: when an operation
73# produces multiple signals, signals occurring later in the list
74# should be handled before those occurring earlier in the list.
Stefan Krah1919b7e2012-03-21 18:25:23 +010075OrderedSignals = {
76 C: [C.Clamped, C.Rounded, C.Inexact, C.Subnormal, C.Underflow,
77 C.Overflow, C.DivisionByZero, C.InvalidOperation,
78 C.FloatOperation] if C else None,
79 P: [P.Clamped, P.Rounded, P.Inexact, P.Subnormal, P.Underflow,
80 P.Overflow, P.DivisionByZero, P.InvalidOperation,
81 P.FloatOperation]
82}
83def assert_signals(cls, context, attr, expected):
84 d = getattr(context, attr)
85 cls.assertTrue(all(d[s] if s in expected else not d[s] for s in d))
86
Stefan Krah59a4a932013-01-16 12:58:59 +010087ROUND_UP = P.ROUND_UP
88ROUND_DOWN = P.ROUND_DOWN
89ROUND_CEILING = P.ROUND_CEILING
90ROUND_FLOOR = P.ROUND_FLOOR
91ROUND_HALF_UP = P.ROUND_HALF_UP
92ROUND_HALF_DOWN = P.ROUND_HALF_DOWN
93ROUND_HALF_EVEN = P.ROUND_HALF_EVEN
94ROUND_05UP = P.ROUND_05UP
95
96RoundingModes = [
97 ROUND_UP, ROUND_DOWN, ROUND_CEILING, ROUND_FLOOR,
98 ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN,
99 ROUND_05UP
100]
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000101
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000102# Tests are built around these assumed context defaults.
103# test_main() restores the original context.
Stefan Krah1919b7e2012-03-21 18:25:23 +0100104ORIGINAL_CONTEXT = {
105 C: C.getcontext().copy() if C else None,
106 P: P.getcontext().copy()
107}
108def init(m):
109 if not m: return
110 DefaultTestContext = m.Context(
Stefan Krah59a4a932013-01-16 12:58:59 +0100111 prec=9, rounding=ROUND_HALF_EVEN, traps=dict.fromkeys(Signals[m], 0)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100112 )
113 m.setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +0000114
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000115TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000116if __name__ == '__main__':
117 file = sys.argv[0]
118else:
119 file = __file__
120testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +0000121directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000122
Raymond Hettinger267b8682005-03-27 10:47:39 +0000123skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000124
125# Make sure it actually raises errors when not expected and caught in flags
126# Slower, since it runs some things several times.
127EXTENDEDERRORTEST = False
128
Stefan Krah1919b7e2012-03-21 18:25:23 +0100129# Test extra functionality in the C version (-DEXTRA_FUNCTIONALITY).
130EXTRA_FUNCTIONALITY = True if hasattr(C, 'DecClamped') else False
131requires_extra_functionality = unittest.skipUnless(
132 EXTRA_FUNCTIONALITY, "test requires build with -DEXTRA_FUNCTIONALITY")
133skip_if_extra_functionality = unittest.skipIf(
134 EXTRA_FUNCTIONALITY, "test requires regular build")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000135
136
Stefan Krah1919b7e2012-03-21 18:25:23 +0100137class IBMTestCases(unittest.TestCase):
138 """Class which tests the Decimal class against the IBM test cases."""
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000139
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000140 def setUp(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100141 self.context = self.decimal.Context()
142 self.readcontext = self.decimal.Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000143 self.ignore_list = ['#']
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000144
Stefan Krah1919b7e2012-03-21 18:25:23 +0100145 # List of individual .decTest test ids that correspond to tests that
146 # we're skipping for one reason or another.
147 self.skipped_test_ids = set([
148 # Skip implementation-specific scaleb tests.
149 'scbx164',
150 'scbx165',
151
152 # For some operations (currently exp, ln, log10, power), the decNumber
153 # reference implementation imposes additional restrictions on the context
154 # and operands. These restrictions are not part of the specification;
155 # however, the effect of these restrictions does show up in some of the
156 # testcases. We skip testcases that violate these restrictions, since
157 # Decimal behaves differently from decNumber for these testcases so these
158 # testcases would otherwise fail.
159 'expx901',
160 'expx902',
161 'expx903',
162 'expx905',
163 'lnx901',
164 'lnx902',
165 'lnx903',
166 'lnx905',
167 'logx901',
168 'logx902',
169 'logx903',
170 'logx905',
171 'powx1183',
172 'powx1184',
173 'powx4001',
174 'powx4002',
175 'powx4003',
176 'powx4005',
177 'powx4008',
178 'powx4010',
179 'powx4012',
180 'powx4014',
181 ])
182
183 if self.decimal == C:
184 # status has additional Subnormal, Underflow
185 self.skipped_test_ids.add('pwsx803')
186 self.skipped_test_ids.add('pwsx805')
187 # Correct rounding (skipped for decNumber, too)
188 self.skipped_test_ids.add('powx4302')
189 self.skipped_test_ids.add('powx4303')
190 self.skipped_test_ids.add('powx4342')
191 self.skipped_test_ids.add('powx4343')
192 # http://bugs.python.org/issue7049
193 self.skipped_test_ids.add('pwmx325')
194 self.skipped_test_ids.add('pwmx326')
195
196 # Map test directives to setter functions.
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000197 self.ChangeDict = {'precision' : self.change_precision,
Stefan Krah1919b7e2012-03-21 18:25:23 +0100198 'rounding' : self.change_rounding_method,
199 'maxexponent' : self.change_max_exponent,
200 'minexponent' : self.change_min_exponent,
201 'clamp' : self.change_clamp}
202
203 # Name adapter to be able to change the Decimal and Context
204 # interface without changing the test files from Cowlishaw.
205 self.NameAdapter = {'and':'logical_and',
206 'apply':'_apply',
207 'class':'number_class',
208 'comparesig':'compare_signal',
209 'comparetotal':'compare_total',
210 'comparetotmag':'compare_total_mag',
211 'copy':'copy_decimal',
212 'copyabs':'copy_abs',
213 'copynegate':'copy_negate',
214 'copysign':'copy_sign',
215 'divideint':'divide_int',
216 'invert':'logical_invert',
217 'iscanonical':'is_canonical',
218 'isfinite':'is_finite',
219 'isinfinite':'is_infinite',
220 'isnan':'is_nan',
221 'isnormal':'is_normal',
222 'isqnan':'is_qnan',
223 'issigned':'is_signed',
224 'issnan':'is_snan',
225 'issubnormal':'is_subnormal',
226 'iszero':'is_zero',
227 'maxmag':'max_mag',
228 'minmag':'min_mag',
229 'nextminus':'next_minus',
230 'nextplus':'next_plus',
231 'nexttoward':'next_toward',
232 'or':'logical_or',
233 'reduce':'normalize',
234 'remaindernear':'remainder_near',
235 'samequantum':'same_quantum',
236 'squareroot':'sqrt',
237 'toeng':'to_eng_string',
238 'tointegral':'to_integral_value',
239 'tointegralx':'to_integral_exact',
240 'tosci':'to_sci_string',
241 'xor':'logical_xor'}
242
243 # Map test-case names to roundings.
Stefan Krah59a4a932013-01-16 12:58:59 +0100244 self.RoundingDict = {'ceiling' : ROUND_CEILING,
245 'down' : ROUND_DOWN,
246 'floor' : ROUND_FLOOR,
247 'half_down' : ROUND_HALF_DOWN,
248 'half_even' : ROUND_HALF_EVEN,
249 'half_up' : ROUND_HALF_UP,
250 'up' : ROUND_UP,
251 '05up' : ROUND_05UP}
Stefan Krah1919b7e2012-03-21 18:25:23 +0100252
253 # Map the test cases' error names to the actual errors.
254 self.ErrorNames = {'clamped' : self.decimal.Clamped,
255 'conversion_syntax' : self.decimal.InvalidOperation,
256 'division_by_zero' : self.decimal.DivisionByZero,
257 'division_impossible' : self.decimal.InvalidOperation,
258 'division_undefined' : self.decimal.InvalidOperation,
259 'inexact' : self.decimal.Inexact,
260 'invalid_context' : self.decimal.InvalidOperation,
261 'invalid_operation' : self.decimal.InvalidOperation,
262 'overflow' : self.decimal.Overflow,
263 'rounded' : self.decimal.Rounded,
264 'subnormal' : self.decimal.Subnormal,
265 'underflow' : self.decimal.Underflow}
266
267 # The following functions return True/False rather than a
268 # Decimal instance.
269 self.LogicalFunctions = ('is_canonical',
270 'is_finite',
271 'is_infinite',
272 'is_nan',
273 'is_normal',
274 'is_qnan',
275 'is_signed',
276 'is_snan',
277 'is_subnormal',
278 'is_zero',
279 'same_quantum')
280
281 def read_unlimited(self, v, context):
282 """Work around the limitations of the 32-bit _decimal version. The
283 guaranteed maximum values for prec, Emax etc. are 425000000,
284 but higher values usually work, except for rare corner cases.
285 In particular, all of the IBM tests pass with maximum values
286 of 1070000000."""
287 if self.decimal == C and self.decimal.MAX_EMAX == 425000000:
288 self.readcontext._unsafe_setprec(1070000000)
289 self.readcontext._unsafe_setemax(1070000000)
290 self.readcontext._unsafe_setemin(-1070000000)
291 return self.readcontext.create_decimal(v)
292 else:
293 return self.decimal.Decimal(v, context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000294
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000295 def eval_file(self, file):
296 global skip_expected
297 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +0000298 raise unittest.SkipTest
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000299 with open(file) as f:
300 for line in f:
301 line = line.replace('\r\n', '').replace('\n', '')
302 #print line
303 try:
304 t = self.eval_line(line)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100305 except self.decimal.DecimalException as exception:
Ezio Melotti13925002011-03-16 11:05:33 +0200306 #Exception raised where there shouldn't have been one.
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000307 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000308
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000309
310 def eval_line(self, s):
311 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
312 s = (s.split('->')[0] + '->' +
313 s.split('->')[1].split('--')[0]).strip()
314 else:
315 s = s.split('--')[0].strip()
316
317 for ignore in self.ignore_list:
318 if s.find(ignore) >= 0:
319 #print s.split()[0], 'NotImplemented--', ignore
320 return
321 if not s:
322 return
323 elif ':' in s:
324 return self.eval_directive(s)
325 else:
326 return self.eval_equation(s)
327
328 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000329 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000330 if funct == 'rounding':
Stefan Krah1919b7e2012-03-21 18:25:23 +0100331 value = self.RoundingDict[value]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000332 else:
333 try:
334 value = int(value)
335 except ValueError:
336 pass
337
Stefan Krah1919b7e2012-03-21 18:25:23 +0100338 funct = self.ChangeDict.get(funct, (lambda *args: None))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000339 funct(value)
340
341 def eval_equation(self, s):
Raymond Hettingered20ad82004-09-04 20:09:13 +0000342
343 if not TEST_ALL and random.random() < 0.90:
344 return
345
Stefan Krah1919b7e2012-03-21 18:25:23 +0100346 self.context.clear_flags()
347
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000348 try:
349 Sides = s.split('->')
350 L = Sides[0].strip().split()
351 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000352 if DEBUG:
353 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000354 funct = L[1].lower()
355 valstemp = L[2:]
356 L = Sides[1].strip().split()
357 ans = L[0]
358 exceptions = L[1:]
359 except (TypeError, AttributeError, IndexError):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100360 raise self.decimal.InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000361 def FixQuotes(val):
362 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
363 val = val.replace("'", '').replace('"', '')
364 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
365 return val
Mark Dickinson8a546532009-10-08 16:30:38 +0000366
Stefan Krah1919b7e2012-03-21 18:25:23 +0100367 if id in self.skipped_test_ids:
Mark Dickinson8a546532009-10-08 16:30:38 +0000368 return
369
Stefan Krah1919b7e2012-03-21 18:25:23 +0100370 fname = self.NameAdapter.get(funct, funct)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000371 if fname == 'rescale':
372 return
373 funct = getattr(self.context, fname)
374 vals = []
375 conglomerate = ''
376 quote = 0
Stefan Krah1919b7e2012-03-21 18:25:23 +0100377 theirexceptions = [self.ErrorNames[x.lower()] for x in exceptions]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000378
Stefan Krah1919b7e2012-03-21 18:25:23 +0100379 for exception in Signals[self.decimal]:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000380 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000381 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000382 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000383 for i, val in enumerate(valstemp):
384 if val.count("'") % 2 == 1:
385 quote = 1 - quote
386 if quote:
387 conglomerate = conglomerate + ' ' + val
388 continue
389 else:
390 val = conglomerate + val
391 conglomerate = ''
392 v = FixQuotes(val)
393 if fname in ('to_sci_string', 'to_eng_string'):
394 if EXTENDEDERRORTEST:
395 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000396 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000397 try:
398 funct(self.context.create_decimal(v))
399 except error:
400 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100401 except Signals[self.decimal] as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000402 self.fail("Raised %s in %s when %s disabled" % \
403 (e, s, error))
404 else:
405 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000406 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000407 v = self.context.create_decimal(v)
408 else:
Stefan Krah1919b7e2012-03-21 18:25:23 +0100409 v = self.read_unlimited(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000410 vals.append(v)
411
412 ans = FixQuotes(ans)
413
414 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
415 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000416 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000417 try:
418 funct(*vals)
419 except error:
420 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100421 except Signals[self.decimal] as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000422 self.fail("Raised %s in %s when %s disabled" % \
423 (e, s, error))
424 else:
425 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000426 self.context.traps[error] = 0
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000427
428 # as above, but add traps cumulatively, to check precedence
Stefan Krah1919b7e2012-03-21 18:25:23 +0100429 ordered_errors = [e for e in OrderedSignals[self.decimal] if e in theirexceptions]
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000430 for error in ordered_errors:
431 self.context.traps[error] = 1
432 try:
433 funct(*vals)
434 except error:
435 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100436 except Signals[self.decimal] as e:
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000437 self.fail("Raised %s in %s; expected %s" %
438 (type(e), s, error))
439 else:
440 self.fail("Did not raise %s in %s" % (error, s))
441 # reset traps
442 for error in ordered_errors:
443 self.context.traps[error] = 0
444
445
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000446 if DEBUG:
447 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000448 try:
449 result = str(funct(*vals))
Stefan Krah1919b7e2012-03-21 18:25:23 +0100450 if fname in self.LogicalFunctions:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000451 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Stefan Krah1919b7e2012-03-21 18:25:23 +0100452 except Signals[self.decimal] as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000453 self.fail("Raised %s in %s" % (error, s))
454 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000455 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000456 raise
457
458 myexceptions = self.getexceptions()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000459
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000460 myexceptions.sort(key=repr)
461 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000462
463 self.assertEqual(result, ans,
464 'Incorrect answer for ' + s + ' -- got ' + result)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100465
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000466 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000467 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000468
469 def getexceptions(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100470 return [e for e in Signals[self.decimal] if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000471
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000472 def change_precision(self, prec):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100473 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
474 self.context._unsafe_setprec(prec)
475 else:
476 self.context.prec = prec
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000477 def change_rounding_method(self, rounding):
478 self.context.rounding = rounding
479 def change_min_exponent(self, exp):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100480 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
481 self.context._unsafe_setemin(exp)
482 else:
483 self.context.Emin = exp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000484 def change_max_exponent(self, exp):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100485 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
486 self.context._unsafe_setemax(exp)
487 else:
488 self.context.Emax = exp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000489 def change_clamp(self, clamp):
Mark Dickinsonb1d8e322010-05-22 18:35:36 +0000490 self.context.clamp = clamp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000491
Stefan Krah1919b7e2012-03-21 18:25:23 +0100492class CIBMTestCases(IBMTestCases):
493 decimal = C
494class PyIBMTestCases(IBMTestCases):
495 decimal = P
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000496
497# The following classes test the behaviour of Decimal according to PEP 327
498
Stefan Krah1919b7e2012-03-21 18:25:23 +0100499class ExplicitConstructionTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000500 '''Unit tests for Explicit Construction cases of Decimal.'''
501
502 def test_explicit_empty(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100503 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000504 self.assertEqual(Decimal(), Decimal("0"))
505
506 def test_explicit_from_None(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100507 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000508 self.assertRaises(TypeError, Decimal, None)
509
510 def test_explicit_from_int(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100511 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000512
513 #positive
514 d = Decimal(45)
515 self.assertEqual(str(d), '45')
516
517 #very large positive
518 d = Decimal(500000123)
519 self.assertEqual(str(d), '500000123')
520
521 #negative
522 d = Decimal(-45)
523 self.assertEqual(str(d), '-45')
524
525 #zero
526 d = Decimal(0)
527 self.assertEqual(str(d), '0')
528
Stefan Krah1919b7e2012-03-21 18:25:23 +0100529 # single word longs
530 for n in range(0, 32):
531 for sign in (-1, 1):
532 for x in range(-5, 5):
533 i = sign * (2**n + x)
534 d = Decimal(i)
535 self.assertEqual(str(d), str(i))
536
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000537 def test_explicit_from_string(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100538 Decimal = self.decimal.Decimal
539 InvalidOperation = self.decimal.InvalidOperation
540 localcontext = self.decimal.localcontext
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000541
542 #empty
543 self.assertEqual(str(Decimal('')), 'NaN')
544
545 #int
546 self.assertEqual(str(Decimal('45')), '45')
547
548 #float
549 self.assertEqual(str(Decimal('45.34')), '45.34')
550
551 #engineer notation
552 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
553
554 #just not a number
555 self.assertEqual(str(Decimal('ugly')), 'NaN')
556
Christian Heimesa62da1d2008-01-12 19:39:10 +0000557 #leading and trailing whitespace permitted
558 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
559 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
Stefan Krah1919b7e2012-03-21 18:25:23 +0100560 self.assertEqual(str(Decimal(" 3.45679 ")), '3.45679')
561
Brett Cannona721aba2016-09-09 14:57:09 -0700562 # underscores
563 self.assertEqual(str(Decimal('1_3.3e4_0')), '1.33E+41')
564 self.assertEqual(str(Decimal('1_0_0_0')), '1000')
565
Stefan Krah1919b7e2012-03-21 18:25:23 +0100566 # unicode whitespace
567 for lead in ["", ' ', '\u00a0', '\u205f']:
568 for trail in ["", ' ', '\u00a0', '\u205f']:
569 self.assertEqual(str(Decimal(lead + '9.311E+28' + trail)),
570 '9.311E+28')
571
572 with localcontext() as c:
573 c.traps[InvalidOperation] = True
574 # Invalid string
575 self.assertRaises(InvalidOperation, Decimal, "xyz")
576 # Two arguments max
577 self.assertRaises(TypeError, Decimal, "1234", "x", "y")
578
579 # space within the numeric part
580 self.assertRaises(InvalidOperation, Decimal, "1\u00a02\u00a03")
581 self.assertRaises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0")
582
583 # unicode whitespace
584 self.assertRaises(InvalidOperation, Decimal, "\u00a0")
585 self.assertRaises(InvalidOperation, Decimal, "\u00a0\u00a0")
586
587 # embedded NUL
588 self.assertRaises(InvalidOperation, Decimal, "12\u00003")
589
Brett Cannona721aba2016-09-09 14:57:09 -0700590 # underscores don't prevent errors
591 self.assertRaises(InvalidOperation, Decimal, "1_2_\u00003")
592
Stefan Krah6e467042012-11-10 23:09:04 +0100593 @cpython_only
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +0300594 @requires_legacy_unicode_capi
Inada Naoki902356a2020-07-20 12:02:50 +0900595 @warnings_helper.ignore_warnings(category=DeprecationWarning)
Stefan Krah6e467042012-11-10 23:09:04 +0100596 def test_from_legacy_strings(self):
597 import _testcapi
598 Decimal = self.decimal.Decimal
599 context = self.decimal.Context()
600
601 s = _testcapi.unicode_legacy_string('9.999999')
602 self.assertEqual(str(Decimal(s)), '9.999999')
603 self.assertEqual(str(context.create_decimal(s)), '9.999999')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000604
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000605 def test_explicit_from_tuples(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100606 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000607
608 #zero
609 d = Decimal( (0, (0,), 0) )
610 self.assertEqual(str(d), '0')
611
612 #int
613 d = Decimal( (1, (4, 5), 0) )
614 self.assertEqual(str(d), '-45')
615
616 #float
617 d = Decimal( (0, (4, 5, 3, 4), -2) )
618 self.assertEqual(str(d), '45.34')
619
620 #weird
621 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
622 self.assertEqual(str(d), '-4.34913534E-17')
623
Stefan Krah1919b7e2012-03-21 18:25:23 +0100624 #inf
625 d = Decimal( (0, (), "F") )
626 self.assertEqual(str(d), 'Infinity')
627
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000628 #wrong number of items
629 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
630
631 #bad sign
632 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000633 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
634 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000635
636 #bad exp
637 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000638 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
639 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000640
641 #bad coefficients
Stefan Krah1919b7e2012-03-21 18:25:23 +0100642 self.assertRaises(ValueError, Decimal, (1, "xyz", 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000643 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
644 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000645 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000646 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000647
Stefan Krah1919b7e2012-03-21 18:25:23 +0100648 def test_explicit_from_list(self):
649 Decimal = self.decimal.Decimal
650
651 d = Decimal([0, [0], 0])
652 self.assertEqual(str(d), '0')
653
654 d = Decimal([1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25])
655 self.assertEqual(str(d), '-4.34913534E-17')
656
657 d = Decimal([1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25])
658 self.assertEqual(str(d), '-4.34913534E-17')
659
660 d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25))
661 self.assertEqual(str(d), '-4.34913534E-17')
662
Antoine Pitrou503ab332010-03-30 18:56:19 +0000663 def test_explicit_from_bool(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100664 Decimal = self.decimal.Decimal
665
Antoine Pitrou503ab332010-03-30 18:56:19 +0000666 self.assertIs(bool(Decimal(0)), False)
667 self.assertIs(bool(Decimal(1)), True)
668 self.assertEqual(Decimal(False), Decimal(0))
669 self.assertEqual(Decimal(True), Decimal(1))
670
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000671 def test_explicit_from_Decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100672 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000673
674 #positive
675 d = Decimal(45)
676 e = Decimal(d)
677 self.assertEqual(str(e), '45')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000678
679 #very large positive
680 d = Decimal(500000123)
681 e = Decimal(d)
682 self.assertEqual(str(e), '500000123')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000683
684 #negative
685 d = Decimal(-45)
686 e = Decimal(d)
687 self.assertEqual(str(e), '-45')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000688
689 #zero
690 d = Decimal(0)
691 e = Decimal(d)
692 self.assertEqual(str(e), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000693
Raymond Hettinger96798592010-04-02 16:58:27 +0000694 @requires_IEEE_754
695 def test_explicit_from_float(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100696
697 Decimal = self.decimal.Decimal
698
Raymond Hettinger96798592010-04-02 16:58:27 +0000699 r = Decimal(0.1)
700 self.assertEqual(type(r), Decimal)
701 self.assertEqual(str(r),
702 '0.1000000000000000055511151231257827021181583404541015625')
703 self.assertTrue(Decimal(float('nan')).is_qnan())
704 self.assertTrue(Decimal(float('inf')).is_infinite())
705 self.assertTrue(Decimal(float('-inf')).is_infinite())
706 self.assertEqual(str(Decimal(float('nan'))),
707 str(Decimal('NaN')))
708 self.assertEqual(str(Decimal(float('inf'))),
709 str(Decimal('Infinity')))
710 self.assertEqual(str(Decimal(float('-inf'))),
711 str(Decimal('-Infinity')))
712 self.assertEqual(str(Decimal(float('-0.0'))),
713 str(Decimal('-0')))
714 for i in range(200):
715 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
716 self.assertEqual(x, float(Decimal(x))) # roundtrip
717
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000718 def test_explicit_context_create_decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100719 Decimal = self.decimal.Decimal
720 InvalidOperation = self.decimal.InvalidOperation
721 Rounded = self.decimal.Rounded
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000722
Stefan Krah1919b7e2012-03-21 18:25:23 +0100723 nc = copy.copy(self.decimal.getcontext())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000724 nc.prec = 3
725
726 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000727 d = Decimal()
728 self.assertEqual(str(d), '0')
729 d = nc.create_decimal()
730 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000731
732 # from None
733 self.assertRaises(TypeError, nc.create_decimal, None)
734
735 # from int
736 d = nc.create_decimal(456)
Ezio Melottie9615932010-01-24 19:26:24 +0000737 self.assertIsInstance(d, Decimal)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000738 self.assertEqual(nc.create_decimal(45678),
739 nc.create_decimal('457E+2'))
740
741 # from string
742 d = Decimal('456789')
743 self.assertEqual(str(d), '456789')
744 d = nc.create_decimal('456789')
745 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000746 # leading and trailing whitespace should result in a NaN;
747 # spaces are already checked in Cowlishaw's test-suite, so
748 # here we just check that a trailing newline results in a NaN
749 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000750
751 # from tuples
752 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
753 self.assertEqual(str(d), '-4.34913534E-17')
754 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
755 self.assertEqual(str(d), '-4.35E-17')
756
757 # from Decimal
758 prevdec = Decimal(500000123)
759 d = Decimal(prevdec)
760 self.assertEqual(str(d), '500000123')
761 d = nc.create_decimal(prevdec)
762 self.assertEqual(str(d), '5.00E+8')
763
Stefan Krah1919b7e2012-03-21 18:25:23 +0100764 # more integers
765 nc.prec = 28
766 nc.traps[InvalidOperation] = True
767
768 for v in [-2**63-1, -2**63, -2**31-1, -2**31, 0,
769 2**31-1, 2**31, 2**63-1, 2**63]:
770 d = nc.create_decimal(v)
771 self.assertTrue(isinstance(d, Decimal))
772 self.assertEqual(int(d), v)
773
774 nc.prec = 3
775 nc.traps[Rounded] = True
776 self.assertRaises(Rounded, nc.create_decimal, 1234)
777
778 # from string
779 nc.prec = 28
780 self.assertEqual(str(nc.create_decimal('0E-017')), '0E-17')
781 self.assertEqual(str(nc.create_decimal('45')), '45')
782 self.assertEqual(str(nc.create_decimal('-Inf')), '-Infinity')
783 self.assertEqual(str(nc.create_decimal('NaN123')), 'NaN123')
784
785 # invalid arguments
786 self.assertRaises(InvalidOperation, nc.create_decimal, "xyz")
787 self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25))
788 self.assertRaises(TypeError, nc.create_decimal, "1234", "5678")
Brett Cannona721aba2016-09-09 14:57:09 -0700789 # no whitespace and underscore stripping is done with this method
790 self.assertRaises(InvalidOperation, nc.create_decimal, " 1234")
791 self.assertRaises(InvalidOperation, nc.create_decimal, "12_34")
Stefan Krah1919b7e2012-03-21 18:25:23 +0100792
793 # too many NaN payload digits
794 nc.prec = 3
795 self.assertRaises(InvalidOperation, nc.create_decimal, 'NaN12345')
796 self.assertRaises(InvalidOperation, nc.create_decimal,
797 Decimal('NaN12345'))
798
799 nc.traps[InvalidOperation] = False
800 self.assertEqual(str(nc.create_decimal('NaN12345')), 'NaN')
801 self.assertTrue(nc.flags[InvalidOperation])
802
803 nc.flags[InvalidOperation] = False
804 self.assertEqual(str(nc.create_decimal(Decimal('NaN12345'))), 'NaN')
805 self.assertTrue(nc.flags[InvalidOperation])
806
807 def test_explicit_context_create_from_float(self):
808
809 Decimal = self.decimal.Decimal
810
811 nc = self.decimal.Context()
812 r = nc.create_decimal(0.1)
813 self.assertEqual(type(r), Decimal)
814 self.assertEqual(str(r), '0.1000000000000000055511151231')
815 self.assertTrue(nc.create_decimal(float('nan')).is_qnan())
816 self.assertTrue(nc.create_decimal(float('inf')).is_infinite())
817 self.assertTrue(nc.create_decimal(float('-inf')).is_infinite())
818 self.assertEqual(str(nc.create_decimal(float('nan'))),
819 str(nc.create_decimal('NaN')))
820 self.assertEqual(str(nc.create_decimal(float('inf'))),
821 str(nc.create_decimal('Infinity')))
822 self.assertEqual(str(nc.create_decimal(float('-inf'))),
823 str(nc.create_decimal('-Infinity')))
824 self.assertEqual(str(nc.create_decimal(float('-0.0'))),
825 str(nc.create_decimal('-0')))
826 nc.prec = 100
827 for i in range(200):
828 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
829 self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip
830
Mark Dickinson345adc42009-08-02 10:14:23 +0000831 def test_unicode_digits(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100832 Decimal = self.decimal.Decimal
833
Mark Dickinson345adc42009-08-02 10:14:23 +0000834 test_values = {
835 '\uff11': '1',
836 '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
837 '-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
838 }
839 for input, expected in test_values.items():
840 self.assertEqual(str(Decimal(input)), expected)
841
Stefan Krah1919b7e2012-03-21 18:25:23 +0100842class CExplicitConstructionTest(ExplicitConstructionTest):
843 decimal = C
844class PyExplicitConstructionTest(ExplicitConstructionTest):
845 decimal = P
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000846
Stefan Krah1919b7e2012-03-21 18:25:23 +0100847class ImplicitConstructionTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000848 '''Unit tests for Implicit Construction cases of Decimal.'''
849
850 def test_implicit_from_None(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100851 Decimal = self.decimal.Decimal
852 self.assertRaises(TypeError, eval, 'Decimal(5) + None', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000853
854 def test_implicit_from_int(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100855 Decimal = self.decimal.Decimal
856
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000857 #normal
858 self.assertEqual(str(Decimal(5) + 45), '50')
859 #exceeding precision
860 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
861
862 def test_implicit_from_string(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100863 Decimal = self.decimal.Decimal
864 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000865
866 def test_implicit_from_float(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100867 Decimal = self.decimal.Decimal
868 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000869
870 def test_implicit_from_Decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100871 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000872 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
873
Raymond Hettinger267b8682005-03-27 10:47:39 +0000874 def test_rop(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100875 Decimal = self.decimal.Decimal
876
Raymond Hettinger267b8682005-03-27 10:47:39 +0000877 # Allow other classes to be trained to interact with Decimals
878 class E:
879 def __divmod__(self, other):
880 return 'divmod ' + str(other)
881 def __rdivmod__(self, other):
882 return str(other) + ' rdivmod'
883 def __lt__(self, other):
884 return 'lt ' + str(other)
885 def __gt__(self, other):
886 return 'gt ' + str(other)
887 def __le__(self, other):
888 return 'le ' + str(other)
889 def __ge__(self, other):
890 return 'ge ' + str(other)
891 def __eq__(self, other):
892 return 'eq ' + str(other)
893 def __ne__(self, other):
894 return 'ne ' + str(other)
895
896 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
897 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
898 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
899 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
900 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
901 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
902 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
903 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
904
905 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000906 oplist = [
907 ('+', '__add__', '__radd__'),
908 ('-', '__sub__', '__rsub__'),
909 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000910 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000911 ('%', '__mod__', '__rmod__'),
912 ('//', '__floordiv__', '__rfloordiv__'),
913 ('**', '__pow__', '__rpow__')
914 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000915
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000916 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000917 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
918 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
919 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
920 'str' + lop + '10')
921 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
922 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000923
Stefan Krah1919b7e2012-03-21 18:25:23 +0100924class CImplicitConstructionTest(ImplicitConstructionTest):
925 decimal = C
926class PyImplicitConstructionTest(ImplicitConstructionTest):
927 decimal = P
Mark Dickinson79f52032009-03-17 23:12:51 +0000928
Stefan Krah1919b7e2012-03-21 18:25:23 +0100929class FormatTest(unittest.TestCase):
Christian Heimesf16baeb2008-02-29 14:57:44 +0000930 '''Unit tests for the format function.'''
931 def test_formatting(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100932 Decimal = self.decimal.Decimal
933
Christian Heimesf16baeb2008-02-29 14:57:44 +0000934 # triples giving a format, a Decimal, and the expected result
935 test_values = [
936 ('e', '0E-15', '0e-15'),
937 ('e', '2.3E-15', '2.3e-15'),
938 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
939 ('e', '2.30000E-15', '2.30000e-15'),
940 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
941 ('e', '1.5', '1.5e+0'),
942 ('e', '0.15', '1.5e-1'),
943 ('e', '0.015', '1.5e-2'),
944 ('e', '0.0000000000015', '1.5e-12'),
945 ('e', '15.0', '1.50e+1'),
946 ('e', '-15', '-1.5e+1'),
947 ('e', '0', '0e+0'),
948 ('e', '0E1', '0e+1'),
949 ('e', '0.0', '0e-1'),
950 ('e', '0.00', '0e-2'),
951 ('.6e', '0E-15', '0.000000e-9'),
952 ('.6e', '0', '0.000000e+6'),
953 ('.6e', '9.999999', '9.999999e+0'),
954 ('.6e', '9.9999999', '1.000000e+1'),
955 ('.6e', '-1.23e5', '-1.230000e+5'),
956 ('.6e', '1.23456789e-3', '1.234568e-3'),
957 ('f', '0', '0'),
958 ('f', '0.0', '0.0'),
959 ('f', '0E-2', '0.00'),
960 ('f', '0.00E-8', '0.0000000000'),
961 ('f', '0E1', '0'), # loses exponent information
962 ('f', '3.2E1', '32'),
963 ('f', '3.2E2', '320'),
964 ('f', '3.20E2', '320'),
965 ('f', '3.200E2', '320.0'),
966 ('f', '3.2E-6', '0.0000032'),
967 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
968 ('.6f', '0E1', '0.000000'),
969 ('.6f', '0', '0.000000'),
970 ('.0f', '0', '0'), # no decimal point
971 ('.0f', '0e-2', '0'),
972 ('.0f', '3.14159265', '3'),
973 ('.1f', '3.14159265', '3.1'),
974 ('.4f', '3.14159265', '3.1416'),
975 ('.6f', '3.14159265', '3.141593'),
976 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
977 ('.8f', '3.14159265', '3.14159265'),
978 ('.9f', '3.14159265', '3.141592650'),
979
980 ('g', '0', '0'),
981 ('g', '0.0', '0.0'),
982 ('g', '0E1', '0e+1'),
983 ('G', '0E1', '0E+1'),
984 ('g', '0E-5', '0.00000'),
985 ('g', '0E-6', '0.000000'),
986 ('g', '0E-7', '0e-7'),
987 ('g', '-0E2', '-0e+2'),
988 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
Stefan Krah1919b7e2012-03-21 18:25:23 +0100989 ('.0n', '3.14159265', '3'), # same for 'n'
Christian Heimesf16baeb2008-02-29 14:57:44 +0000990 ('.1g', '3.14159265', '3'),
991 ('.2g', '3.14159265', '3.1'),
992 ('.5g', '3.14159265', '3.1416'),
993 ('.7g', '3.14159265', '3.141593'),
994 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
995 ('.9g', '3.14159265', '3.14159265'),
996 ('.10g', '3.14159265', '3.14159265'), # don't pad
997
998 ('%', '0E1', '0%'),
999 ('%', '0E0', '0%'),
1000 ('%', '0E-1', '0%'),
1001 ('%', '0E-2', '0%'),
1002 ('%', '0E-3', '0.0%'),
1003 ('%', '0E-4', '0.00%'),
1004
1005 ('.3%', '0', '0.000%'), # all zeros treated equally
1006 ('.3%', '0E10', '0.000%'),
1007 ('.3%', '0E-10', '0.000%'),
1008 ('.3%', '2.34', '234.000%'),
1009 ('.3%', '1.234567', '123.457%'),
1010 ('.0%', '1.23', '123%'),
1011
1012 ('e', 'NaN', 'NaN'),
1013 ('f', '-NaN123', '-NaN123'),
1014 ('+g', 'NaN456', '+NaN456'),
1015 ('.3e', 'Inf', 'Infinity'),
1016 ('.16f', '-Inf', '-Infinity'),
1017 ('.0g', '-sNaN', '-sNaN'),
1018
1019 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +00001020
Mark Dickinson79f52032009-03-17 23:12:51 +00001021 # test alignment and padding
Mark Dickinson46ab5d02009-09-08 20:22:46 +00001022 ('6', '123', ' 123'),
Mark Dickinsonad416342009-03-17 18:10:15 +00001023 ('<6', '123', '123 '),
1024 ('>6', '123', ' 123'),
1025 ('^6', '123', ' 123 '),
1026 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +00001027 ('#<10', 'NaN', 'NaN#######'),
1028 ('#<10', '-4.3', '-4.3######'),
1029 ('#<+10', '0.0130', '+0.0130###'),
1030 ('#< 10', '0.0130', ' 0.0130###'),
1031 ('@>10', '-Inf', '@-Infinity'),
1032 ('#>5', '-Inf', '-Infinity'),
1033 ('?^5', '123', '?123?'),
1034 ('%^6', '123', '%123%%'),
1035 (' ^6', '-45.6', '-45.6 '),
1036 ('/=10', '-45.6', '-/////45.6'),
1037 ('/=+10', '45.6', '+/////45.6'),
1038 ('/= 10', '45.6', ' /////45.6'),
Stefan Krah6edda142013-05-29 15:45:38 +02001039 ('\x00=10', '-inf', '-\x00Infinity'),
1040 ('\x00^16', '-inf', '\x00\x00\x00-Infinity\x00\x00\x00\x00'),
1041 ('\x00>10', '1.2345', '\x00\x00\x00\x001.2345'),
1042 ('\x00<10', '1.2345', '1.2345\x00\x00\x00\x00'),
Mark Dickinson79f52032009-03-17 23:12:51 +00001043
1044 # thousands separator
1045 (',', '1234567', '1,234,567'),
1046 (',', '123456', '123,456'),
1047 (',', '12345', '12,345'),
1048 (',', '1234', '1,234'),
1049 (',', '123', '123'),
1050 (',', '12', '12'),
1051 (',', '1', '1'),
1052 (',', '0', '0'),
1053 (',', '-1234567', '-1,234,567'),
1054 (',', '-123456', '-123,456'),
1055 ('7,', '123456', '123,456'),
Mark Dickinson46ab5d02009-09-08 20:22:46 +00001056 ('8,', '123456', ' 123,456'),
Mark Dickinson79f52032009-03-17 23:12:51 +00001057 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
1058 ('+08,', '123456', '+123,456'), # but not if there's a sign
1059 (' 08,', '123456', ' 123,456'),
1060 ('08,', '-123456', '-123,456'),
1061 ('+09,', '123456', '+0,123,456'),
1062 # ... with fractional part...
1063 ('07,', '1234.56', '1,234.56'),
1064 ('08,', '1234.56', '1,234.56'),
1065 ('09,', '1234.56', '01,234.56'),
1066 ('010,', '1234.56', '001,234.56'),
1067 ('011,', '1234.56', '0,001,234.56'),
1068 ('012,', '1234.56', '0,001,234.56'),
1069 ('08,.1f', '1234.5', '01,234.5'),
1070 # no thousands separators in fraction part
1071 (',', '1.23456789', '1.23456789'),
1072 (',%', '123.456789', '12,345.6789%'),
1073 (',e', '123456', '1.23456e+5'),
1074 (',E', '123456', '1.23456E+5'),
Mark Dickinson7718d2b2009-09-07 16:21:56 +00001075
1076 # issue 6850
1077 ('a=-7.0', '0.12345', 'aaaa0.1'),
Stefan Krah298131a2014-08-26 20:46:49 +02001078
1079 # issue 22090
1080 ('<^+15.20%', 'inf', '<<+Infinity%<<<'),
1081 ('\x07>,%', 'sNaN1234567', 'sNaN1234567%'),
1082 ('=10.10%', 'NaN123', ' NaN123%'),
Christian Heimesf16baeb2008-02-29 14:57:44 +00001083 ]
1084 for fmt, d, result in test_values:
1085 self.assertEqual(format(Decimal(d), fmt), result)
1086
Stefan Krah1919b7e2012-03-21 18:25:23 +01001087 # bytes format argument
1088 self.assertRaises(TypeError, Decimal(1).__format__, b'-020')
1089
Mark Dickinson79f52032009-03-17 23:12:51 +00001090 def test_n_format(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001091 Decimal = self.decimal.Decimal
1092
Mark Dickinson79f52032009-03-17 23:12:51 +00001093 try:
1094 from locale import CHAR_MAX
1095 except ImportError:
Zachary Ware9fe6d862013-12-08 00:20:35 -06001096 self.skipTest('locale.CHAR_MAX not available')
Mark Dickinson79f52032009-03-17 23:12:51 +00001097
Stefan Krah1919b7e2012-03-21 18:25:23 +01001098 def make_grouping(lst):
1099 return ''.join([chr(x) for x in lst]) if self.decimal == C else lst
1100
1101 def get_fmt(x, override=None, fmt='n'):
1102 if self.decimal == C:
1103 return Decimal(x).__format__(fmt, override)
1104 else:
1105 return Decimal(x).__format__(fmt, _localeconv=override)
1106
Mark Dickinson79f52032009-03-17 23:12:51 +00001107 # Set up some localeconv-like dictionaries
1108 en_US = {
1109 'decimal_point' : '.',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001110 'grouping' : make_grouping([3, 3, 0]),
1111 'thousands_sep' : ','
Mark Dickinson79f52032009-03-17 23:12:51 +00001112 }
1113
1114 fr_FR = {
1115 'decimal_point' : ',',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001116 'grouping' : make_grouping([CHAR_MAX]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001117 'thousands_sep' : ''
1118 }
1119
1120 ru_RU = {
1121 'decimal_point' : ',',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001122 'grouping': make_grouping([3, 3, 0]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001123 'thousands_sep' : ' '
1124 }
1125
1126 crazy = {
1127 'decimal_point' : '&',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001128 'grouping': make_grouping([1, 4, 2, CHAR_MAX]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001129 'thousands_sep' : '-'
1130 }
1131
Stefan Krah1919b7e2012-03-21 18:25:23 +01001132 dotsep_wide = {
1133 'decimal_point' : b'\xc2\xbf'.decode('utf-8'),
1134 'grouping': make_grouping([3, 3, 0]),
1135 'thousands_sep' : b'\xc2\xb4'.decode('utf-8')
1136 }
Mark Dickinson79f52032009-03-17 23:12:51 +00001137
1138 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
1139 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
1140 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
1141 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
1142
1143 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
1144 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
1145 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
1146 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
1147
1148 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
1149 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
1150 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
1151 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
1152
Mark Dickinson7303b592009-03-18 08:25:36 +00001153 # zero padding
1154 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
1155 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
1156 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
1157 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
1158
1159 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
1160 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
1161 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
1162 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
1163 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
1164 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
1165
1166 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
1167 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
1168 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
1169 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
1170 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
1171 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
1172 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
1173 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
1174
Stefan Krah1919b7e2012-03-21 18:25:23 +01001175 # wide char separator and decimal point
1176 self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'),
1177 '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5')
Mark Dickinson79f52032009-03-17 23:12:51 +00001178
Stefan Krah6fb204a2012-09-28 16:18:54 +02001179 @run_with_locale('LC_ALL', 'ps_AF')
Stefan Krah1919b7e2012-03-21 18:25:23 +01001180 def test_wide_char_separator_decimal_point(self):
1181 # locale with wide char separator and decimal point
1182 Decimal = self.decimal.Decimal
1183
Stefan Krah8a491a82012-09-28 17:17:11 +02001184 decimal_point = locale.localeconv()['decimal_point']
1185 thousands_sep = locale.localeconv()['thousands_sep']
Zachary Ware9fe6d862013-12-08 00:20:35 -06001186 if decimal_point != '\u066b':
Serhiy Storchaka34fd4c22018-11-05 16:20:25 +02001187 self.skipTest('inappropriate decimal point separator '
Zachary Ware0f533ac2013-12-12 10:32:16 -06001188 '({!a} not {!a})'.format(decimal_point, '\u066b'))
Zachary Ware9fe6d862013-12-08 00:20:35 -06001189 if thousands_sep != '\u066c':
Serhiy Storchaka34fd4c22018-11-05 16:20:25 +02001190 self.skipTest('inappropriate thousands separator '
Zachary Ware0f533ac2013-12-12 10:32:16 -06001191 '({!a} not {!a})'.format(thousands_sep, '\u066c'))
Stefan Krah8a491a82012-09-28 17:17:11 +02001192
Stefan Krah1919b7e2012-03-21 18:25:23 +01001193 self.assertEqual(format(Decimal('100000000.123'), 'n'),
1194 '100\u066c000\u066c000\u066b123')
Stefan Krah1919b7e2012-03-21 18:25:23 +01001195
Andrew Nester6d1dece2017-02-14 21:22:55 +03001196 def test_decimal_from_float_argument_type(self):
1197 class A(self.decimal.Decimal):
1198 def __init__(self, a):
1199 self.a_type = type(a)
1200 a = A.from_float(42.5)
1201 self.assertEqual(self.decimal.Decimal, a.a_type)
1202
1203 a = A.from_float(42)
1204 self.assertEqual(self.decimal.Decimal, a.a_type)
1205
Stefan Krah1919b7e2012-03-21 18:25:23 +01001206class CFormatTest(FormatTest):
1207 decimal = C
1208class PyFormatTest(FormatTest):
1209 decimal = P
1210
1211class ArithmeticOperatorsTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001212 '''Unit tests for all arithmetic operators, binary and unary.'''
1213
1214 def test_addition(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001215 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001216
1217 d1 = Decimal('-11.1')
1218 d2 = Decimal('22.2')
1219
1220 #two Decimals
1221 self.assertEqual(d1+d2, Decimal('11.1'))
1222 self.assertEqual(d2+d1, Decimal('11.1'))
1223
1224 #with other type, left
1225 c = d1 + 5
1226 self.assertEqual(c, Decimal('-6.1'))
1227 self.assertEqual(type(c), type(d1))
1228
1229 #with other type, right
1230 c = 5 + d1
1231 self.assertEqual(c, Decimal('-6.1'))
1232 self.assertEqual(type(c), type(d1))
1233
1234 #inline with decimal
1235 d1 += d2
1236 self.assertEqual(d1, Decimal('11.1'))
1237
1238 #inline with other type
1239 d1 += 5
1240 self.assertEqual(d1, Decimal('16.1'))
1241
1242 def test_subtraction(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001243 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001244
1245 d1 = Decimal('-11.1')
1246 d2 = Decimal('22.2')
1247
1248 #two Decimals
1249 self.assertEqual(d1-d2, Decimal('-33.3'))
1250 self.assertEqual(d2-d1, Decimal('33.3'))
1251
1252 #with other type, left
1253 c = d1 - 5
1254 self.assertEqual(c, Decimal('-16.1'))
1255 self.assertEqual(type(c), type(d1))
1256
1257 #with other type, right
1258 c = 5 - d1
1259 self.assertEqual(c, Decimal('16.1'))
1260 self.assertEqual(type(c), type(d1))
1261
1262 #inline with decimal
1263 d1 -= d2
1264 self.assertEqual(d1, Decimal('-33.3'))
1265
1266 #inline with other type
1267 d1 -= 5
1268 self.assertEqual(d1, Decimal('-38.3'))
1269
1270 def test_multiplication(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001271 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001272
1273 d1 = Decimal('-5')
1274 d2 = Decimal('3')
1275
1276 #two Decimals
1277 self.assertEqual(d1*d2, Decimal('-15'))
1278 self.assertEqual(d2*d1, Decimal('-15'))
1279
1280 #with other type, left
1281 c = d1 * 5
1282 self.assertEqual(c, Decimal('-25'))
1283 self.assertEqual(type(c), type(d1))
1284
1285 #with other type, right
1286 c = 5 * d1
1287 self.assertEqual(c, Decimal('-25'))
1288 self.assertEqual(type(c), type(d1))
1289
1290 #inline with decimal
1291 d1 *= d2
1292 self.assertEqual(d1, Decimal('-15'))
1293
1294 #inline with other type
1295 d1 *= 5
1296 self.assertEqual(d1, Decimal('-75'))
1297
1298 def test_division(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001299 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001300
1301 d1 = Decimal('-5')
1302 d2 = Decimal('2')
1303
1304 #two Decimals
1305 self.assertEqual(d1/d2, Decimal('-2.5'))
1306 self.assertEqual(d2/d1, Decimal('-0.4'))
1307
1308 #with other type, left
1309 c = d1 / 4
1310 self.assertEqual(c, Decimal('-1.25'))
1311 self.assertEqual(type(c), type(d1))
1312
1313 #with other type, right
1314 c = 4 / d1
1315 self.assertEqual(c, Decimal('-0.8'))
1316 self.assertEqual(type(c), type(d1))
1317
1318 #inline with decimal
1319 d1 /= d2
1320 self.assertEqual(d1, Decimal('-2.5'))
1321
1322 #inline with other type
1323 d1 /= 4
1324 self.assertEqual(d1, Decimal('-0.625'))
1325
1326 def test_floor_division(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001327 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001328
1329 d1 = Decimal('5')
1330 d2 = Decimal('2')
1331
1332 #two Decimals
1333 self.assertEqual(d1//d2, Decimal('2'))
1334 self.assertEqual(d2//d1, Decimal('0'))
1335
1336 #with other type, left
1337 c = d1 // 4
1338 self.assertEqual(c, Decimal('1'))
1339 self.assertEqual(type(c), type(d1))
1340
1341 #with other type, right
1342 c = 7 // d1
1343 self.assertEqual(c, Decimal('1'))
1344 self.assertEqual(type(c), type(d1))
1345
1346 #inline with decimal
1347 d1 //= d2
1348 self.assertEqual(d1, Decimal('2'))
1349
1350 #inline with other type
1351 d1 //= 2
1352 self.assertEqual(d1, Decimal('1'))
1353
1354 def test_powering(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001355 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001356
1357 d1 = Decimal('5')
1358 d2 = Decimal('2')
1359
1360 #two Decimals
1361 self.assertEqual(d1**d2, Decimal('25'))
1362 self.assertEqual(d2**d1, Decimal('32'))
1363
1364 #with other type, left
1365 c = d1 ** 4
1366 self.assertEqual(c, Decimal('625'))
1367 self.assertEqual(type(c), type(d1))
1368
1369 #with other type, right
1370 c = 7 ** d1
1371 self.assertEqual(c, Decimal('16807'))
1372 self.assertEqual(type(c), type(d1))
1373
1374 #inline with decimal
1375 d1 **= d2
1376 self.assertEqual(d1, Decimal('25'))
1377
1378 #inline with other type
1379 d1 **= 4
1380 self.assertEqual(d1, Decimal('390625'))
1381
1382 def test_module(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001383 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001384
1385 d1 = Decimal('5')
1386 d2 = Decimal('2')
1387
1388 #two Decimals
1389 self.assertEqual(d1%d2, Decimal('1'))
1390 self.assertEqual(d2%d1, Decimal('2'))
1391
1392 #with other type, left
1393 c = d1 % 4
1394 self.assertEqual(c, Decimal('1'))
1395 self.assertEqual(type(c), type(d1))
1396
1397 #with other type, right
1398 c = 7 % d1
1399 self.assertEqual(c, Decimal('2'))
1400 self.assertEqual(type(c), type(d1))
1401
1402 #inline with decimal
1403 d1 %= d2
1404 self.assertEqual(d1, Decimal('1'))
1405
1406 #inline with other type
1407 d1 %= 4
1408 self.assertEqual(d1, Decimal('1'))
1409
1410 def test_floor_div_module(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001411 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001412
1413 d1 = Decimal('5')
1414 d2 = Decimal('2')
1415
1416 #two Decimals
1417 (p, q) = divmod(d1, d2)
1418 self.assertEqual(p, Decimal('2'))
1419 self.assertEqual(q, Decimal('1'))
1420 self.assertEqual(type(p), type(d1))
1421 self.assertEqual(type(q), type(d1))
1422
1423 #with other type, left
1424 (p, q) = divmod(d1, 4)
1425 self.assertEqual(p, Decimal('1'))
1426 self.assertEqual(q, Decimal('1'))
1427 self.assertEqual(type(p), type(d1))
1428 self.assertEqual(type(q), type(d1))
1429
1430 #with other type, right
1431 (p, q) = divmod(7, d1)
1432 self.assertEqual(p, Decimal('1'))
1433 self.assertEqual(q, Decimal('2'))
1434 self.assertEqual(type(p), type(d1))
1435 self.assertEqual(type(q), type(d1))
1436
1437 def test_unary_operators(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001438 Decimal = self.decimal.Decimal
1439
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001440 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1441 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1442 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1443
Christian Heimes77c02eb2008-02-09 02:18:51 +00001444 def test_nan_comparisons(self):
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001445 # comparisons involving signaling nans signal InvalidOperation
1446
1447 # order comparisons (<, <=, >, >=) involving only quiet nans
1448 # also signal InvalidOperation
1449
1450 # equality comparisons (==, !=) involving only quiet nans
1451 # don't signal, but return False or True respectively.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001452 Decimal = self.decimal.Decimal
1453 InvalidOperation = self.decimal.InvalidOperation
1454 localcontext = self.decimal.localcontext
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001455
Christian Heimes77c02eb2008-02-09 02:18:51 +00001456 n = Decimal('NaN')
1457 s = Decimal('sNaN')
1458 i = Decimal('Inf')
1459 f = Decimal('2')
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001460
1461 qnan_pairs = (n, n), (n, i), (i, n), (n, f), (f, n)
1462 snan_pairs = (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)
1463 order_ops = operator.lt, operator.le, operator.gt, operator.ge
1464 equality_ops = operator.eq, operator.ne
1465
1466 # results when InvalidOperation is not trapped
1467 for x, y in qnan_pairs + snan_pairs:
1468 for op in order_ops + equality_ops:
1469 got = op(x, y)
1470 expected = True if op is operator.ne else False
1471 self.assertIs(expected, got,
1472 "expected {0!r} for operator.{1}({2!r}, {3!r}); "
1473 "got {4!r}".format(
1474 expected, op.__name__, x, y, got))
1475
1476 # repeat the above, but this time trap the InvalidOperation
1477 with localcontext() as ctx:
1478 ctx.traps[InvalidOperation] = 1
1479
1480 for x, y in qnan_pairs:
1481 for op in equality_ops:
1482 got = op(x, y)
1483 expected = True if op is operator.ne else False
1484 self.assertIs(expected, got,
1485 "expected {0!r} for "
1486 "operator.{1}({2!r}, {3!r}); "
1487 "got {4!r}".format(
1488 expected, op.__name__, x, y, got))
1489
1490 for x, y in snan_pairs:
1491 for op in equality_ops:
1492 self.assertRaises(InvalidOperation, operator.eq, x, y)
1493 self.assertRaises(InvalidOperation, operator.ne, x, y)
1494
1495 for x, y in qnan_pairs + snan_pairs:
1496 for op in order_ops:
1497 self.assertRaises(InvalidOperation, op, x, y)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001498
Mark Dickinson84230a12010-02-18 14:49:50 +00001499 def test_copy_sign(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001500 Decimal = self.decimal.Decimal
Mark Dickinson84230a12010-02-18 14:49:50 +00001501
Stefan Krah1919b7e2012-03-21 18:25:23 +01001502 d = Decimal(1).copy_sign(Decimal(-2))
Mark Dickinson84230a12010-02-18 14:49:50 +00001503 self.assertEqual(Decimal(1).copy_sign(-2), d)
1504 self.assertRaises(TypeError, Decimal(1).copy_sign, '-2')
1505
Stefan Krah1919b7e2012-03-21 18:25:23 +01001506class CArithmeticOperatorsTest(ArithmeticOperatorsTest):
1507 decimal = C
1508class PyArithmeticOperatorsTest(ArithmeticOperatorsTest):
1509 decimal = P
1510
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001511# The following are two functions used to test threading in the next class
1512
1513def thfunc1(cls):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001514 Decimal = cls.decimal.Decimal
1515 InvalidOperation = cls.decimal.InvalidOperation
1516 DivisionByZero = cls.decimal.DivisionByZero
1517 Overflow = cls.decimal.Overflow
1518 Underflow = cls.decimal.Underflow
1519 Inexact = cls.decimal.Inexact
1520 getcontext = cls.decimal.getcontext
1521 localcontext = cls.decimal.localcontext
1522
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001523 d1 = Decimal(1)
1524 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001525 test1 = d1/d3
Christian Heimesfe337bf2008-03-23 21:54:12 +00001526
Stefan Krah1919b7e2012-03-21 18:25:23 +01001527 cls.finish1.set()
1528 cls.synchro.wait()
1529
1530 test2 = d1/d3
1531 with localcontext() as c2:
1532 cls.assertTrue(c2.flags[Inexact])
1533 cls.assertRaises(DivisionByZero, c2.divide, d1, 0)
1534 cls.assertTrue(c2.flags[DivisionByZero])
1535 with localcontext() as c3:
1536 cls.assertTrue(c3.flags[Inexact])
1537 cls.assertTrue(c3.flags[DivisionByZero])
1538 cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN'))
1539 cls.assertTrue(c3.flags[InvalidOperation])
1540 del c3
1541 cls.assertFalse(c2.flags[InvalidOperation])
1542 del c2
1543
1544 cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
1545 cls.assertEqual(test2, Decimal('0.333333333333333333333333'))
1546
1547 c1 = getcontext()
1548 cls.assertTrue(c1.flags[Inexact])
1549 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
1550 cls.assertFalse(c1.flags[sig])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001551
1552def thfunc2(cls):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001553 Decimal = cls.decimal.Decimal
1554 InvalidOperation = cls.decimal.InvalidOperation
1555 DivisionByZero = cls.decimal.DivisionByZero
1556 Overflow = cls.decimal.Overflow
1557 Underflow = cls.decimal.Underflow
1558 Inexact = cls.decimal.Inexact
1559 getcontext = cls.decimal.getcontext
1560 localcontext = cls.decimal.localcontext
1561
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001562 d1 = Decimal(1)
1563 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001564 test1 = d1/d3
Stefan Krah1919b7e2012-03-21 18:25:23 +01001565
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001566 thiscontext = getcontext()
1567 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001568 test2 = d1/d3
Stefan Krah1919b7e2012-03-21 18:25:23 +01001569
1570 with localcontext() as c2:
1571 cls.assertTrue(c2.flags[Inexact])
1572 cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999)
1573 cls.assertTrue(c2.flags[Overflow])
1574 with localcontext(thiscontext) as c3:
1575 cls.assertTrue(c3.flags[Inexact])
1576 cls.assertFalse(c3.flags[Overflow])
1577 c3.traps[Underflow] = True
1578 cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999)
1579 cls.assertTrue(c3.flags[Underflow])
1580 del c3
1581 cls.assertFalse(c2.flags[Underflow])
1582 cls.assertFalse(c2.traps[Underflow])
1583 del c2
1584
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001585 cls.synchro.set()
1586 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001587
Stefan Krah1919b7e2012-03-21 18:25:23 +01001588 cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001589 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Stefan Krah1919b7e2012-03-21 18:25:23 +01001590
1591 cls.assertFalse(thiscontext.traps[Underflow])
1592 cls.assertTrue(thiscontext.flags[Inexact])
1593 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
1594 cls.assertFalse(thiscontext.flags[sig])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001595
Stefan Krah1919b7e2012-03-21 18:25:23 +01001596class ThreadingTest(unittest.TestCase):
1597 '''Unit tests for thread local contexts in Decimal.'''
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001598
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001599 # Take care executing this test from IDLE, there's an issue in threading
1600 # that hangs IDLE and I couldn't find it
1601
1602 def test_threading(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001603 DefaultContext = self.decimal.DefaultContext
1604
1605 if self.decimal == C and not self.decimal.HAVE_THREADS:
1606 self.skipTest("compiled without threading")
1607 # Test the "threading isolation" of a Context. Also test changing
1608 # the DefaultContext, which acts as a template for the thread-local
1609 # contexts.
1610 save_prec = DefaultContext.prec
1611 save_emax = DefaultContext.Emax
1612 save_emin = DefaultContext.Emin
1613 DefaultContext.prec = 24
1614 DefaultContext.Emax = 425000000
1615 DefaultContext.Emin = -425000000
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001616
1617 self.synchro = threading.Event()
1618 self.finish1 = threading.Event()
1619 self.finish2 = threading.Event()
1620
1621 th1 = threading.Thread(target=thfunc1, args=(self,))
1622 th2 = threading.Thread(target=thfunc2, args=(self,))
1623
1624 th1.start()
1625 th2.start()
1626
1627 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001628 self.finish2.wait()
Stefan Krah1919b7e2012-03-21 18:25:23 +01001629
1630 for sig in Signals[self.decimal]:
1631 self.assertFalse(DefaultContext.flags[sig])
1632
Victor Stinner18e95b42017-09-14 08:43:04 -07001633 th1.join()
1634 th2.join()
1635
Stefan Krah1919b7e2012-03-21 18:25:23 +01001636 DefaultContext.prec = save_prec
1637 DefaultContext.Emax = save_emax
1638 DefaultContext.Emin = save_emin
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001639
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001640
Stefan Krah1919b7e2012-03-21 18:25:23 +01001641class CThreadingTest(ThreadingTest):
1642 decimal = C
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001643
Stefan Krah1919b7e2012-03-21 18:25:23 +01001644class PyThreadingTest(ThreadingTest):
1645 decimal = P
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001646
Stefan Krah1919b7e2012-03-21 18:25:23 +01001647class UsabilityTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001648 '''Unit tests for Usability cases of Decimal.'''
1649
1650 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001651
Stefan Krah1919b7e2012-03-21 18:25:23 +01001652 Decimal = self.decimal.Decimal
1653
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001654 da = Decimal('23.42')
1655 db = Decimal('23.42')
1656 dc = Decimal('45')
1657
1658 #two Decimals
Ezio Melotti6607d512010-04-03 14:59:49 +00001659 self.assertGreater(dc, da)
1660 self.assertGreaterEqual(dc, da)
1661 self.assertLess(da, dc)
1662 self.assertLessEqual(da, dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001663 self.assertEqual(da, db)
Ezio Melotti6607d512010-04-03 14:59:49 +00001664 self.assertNotEqual(da, dc)
1665 self.assertLessEqual(da, db)
1666 self.assertGreaterEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001667
1668 #a Decimal and an int
Ezio Melotti6607d512010-04-03 14:59:49 +00001669 self.assertGreater(dc, 23)
1670 self.assertLess(23, dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001671 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001672
1673 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001674 self.assertNotEqual(da, 'ugly')
1675 self.assertNotEqual(da, 32.7)
1676 self.assertNotEqual(da, object())
1677 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001678
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001679 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001680 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001681 b = a[:]
1682 random.shuffle(a)
1683 a.sort()
1684 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001685
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001686 def test_decimal_float_comparison(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001687 Decimal = self.decimal.Decimal
1688
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001689 da = Decimal('0.25')
1690 db = Decimal('3.0')
Ezio Melotti6607d512010-04-03 14:59:49 +00001691 self.assertLess(da, 3.0)
1692 self.assertLessEqual(da, 3.0)
1693 self.assertGreater(db, 0.25)
1694 self.assertGreaterEqual(db, 0.25)
1695 self.assertNotEqual(da, 1.5)
1696 self.assertEqual(da, 0.25)
1697 self.assertGreater(3.0, da)
1698 self.assertGreaterEqual(3.0, da)
1699 self.assertLess(0.25, db)
1700 self.assertLessEqual(0.25, db)
1701 self.assertNotEqual(0.25, db)
1702 self.assertEqual(3.0, db)
1703 self.assertNotEqual(0.1, Decimal('0.1'))
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001704
Stefan Krah1919b7e2012-03-21 18:25:23 +01001705 def test_decimal_complex_comparison(self):
1706 Decimal = self.decimal.Decimal
1707
1708 da = Decimal('0.25')
1709 db = Decimal('3.0')
1710 self.assertNotEqual(da, (1.5+0j))
1711 self.assertNotEqual((1.5+0j), da)
1712 self.assertEqual(da, (0.25+0j))
1713 self.assertEqual((0.25+0j), da)
1714 self.assertEqual((3.0+0j), db)
1715 self.assertEqual(db, (3.0+0j))
1716
1717 self.assertNotEqual(db, (3.0+1j))
1718 self.assertNotEqual((3.0+1j), db)
1719
1720 self.assertIs(db.__lt__(3.0+0j), NotImplemented)
1721 self.assertIs(db.__le__(3.0+0j), NotImplemented)
1722 self.assertIs(db.__gt__(3.0+0j), NotImplemented)
1723 self.assertIs(db.__le__(3.0+0j), NotImplemented)
1724
1725 def test_decimal_fraction_comparison(self):
1726 D = self.decimal.Decimal
1727 F = fractions[self.decimal].Fraction
1728 Context = self.decimal.Context
1729 localcontext = self.decimal.localcontext
1730 InvalidOperation = self.decimal.InvalidOperation
1731
1732
1733 emax = C.MAX_EMAX if C else 999999999
1734 emin = C.MIN_EMIN if C else -999999999
1735 etiny = C.MIN_ETINY if C else -1999999997
1736 c = Context(Emax=emax, Emin=emin)
1737
1738 with localcontext(c):
1739 c.prec = emax
1740 self.assertLess(D(0), F(1,9999999999999999999999999999999999999))
1741 self.assertLess(F(-1,9999999999999999999999999999999999999), D(0))
1742 self.assertLess(F(0,1), D("1e" + str(etiny)))
1743 self.assertLess(D("-1e" + str(etiny)), F(0,1))
1744 self.assertLess(F(0,9999999999999999999999999), D("1e" + str(etiny)))
1745 self.assertLess(D("-1e" + str(etiny)), F(0,9999999999999999999999999))
1746
1747 self.assertEqual(D("0.1"), F(1,10))
1748 self.assertEqual(F(1,10), D("0.1"))
1749
1750 c.prec = 300
1751 self.assertNotEqual(D(1)/3, F(1,3))
1752 self.assertNotEqual(F(1,3), D(1)/3)
1753
1754 self.assertLessEqual(F(120984237, 9999999999), D("9e" + str(emax)))
1755 self.assertGreaterEqual(D("9e" + str(emax)), F(120984237, 9999999999))
1756
1757 self.assertGreater(D('inf'), F(99999999999,123))
1758 self.assertGreater(D('inf'), F(-99999999999,123))
1759 self.assertLess(D('-inf'), F(99999999999,123))
1760 self.assertLess(D('-inf'), F(-99999999999,123))
1761
1762 self.assertRaises(InvalidOperation, D('nan').__gt__, F(-9,123))
1763 self.assertIs(NotImplemented, F(-9,123).__lt__(D('nan')))
1764 self.assertNotEqual(D('nan'), F(-9,123))
1765 self.assertNotEqual(F(-9,123), D('nan'))
1766
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001767 def test_copy_and_deepcopy_methods(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001768 Decimal = self.decimal.Decimal
1769
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001770 d = Decimal('43.24')
1771 c = copy.copy(d)
1772 self.assertEqual(id(c), id(d))
1773 dc = copy.deepcopy(d)
1774 self.assertEqual(id(dc), id(d))
1775
1776 def test_hash_method(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001777
1778 Decimal = self.decimal.Decimal
1779 localcontext = self.decimal.localcontext
1780
Stefan Krahdc817b22010-11-17 11:16:34 +00001781 def hashit(d):
1782 a = hash(d)
1783 b = d.__hash__()
1784 self.assertEqual(a, b)
1785 return a
1786
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001787 #just that it's hashable
Stefan Krahdc817b22010-11-17 11:16:34 +00001788 hashit(Decimal(23))
1789 hashit(Decimal('Infinity'))
1790 hashit(Decimal('-Infinity'))
1791 hashit(Decimal('nan123'))
1792 hashit(Decimal('-NaN'))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001793
1794 test_values = [Decimal(sign*(2**m + n))
1795 for m in [0, 14, 15, 16, 17, 30, 31,
Stefan Krahdc817b22010-11-17 11:16:34 +00001796 32, 33, 61, 62, 63, 64, 65, 66]
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001797 for n in range(-10, 10)
1798 for sign in [-1, 1]]
1799 test_values.extend([
Stefan Krahdc817b22010-11-17 11:16:34 +00001800 Decimal("-1"), # ==> -2
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001801 Decimal("-0"), # zeros
1802 Decimal("0.00"),
1803 Decimal("-0.000"),
1804 Decimal("0E10"),
1805 Decimal("-0E12"),
1806 Decimal("10.0"), # negative exponent
1807 Decimal("-23.00000"),
1808 Decimal("1230E100"), # positive exponent
1809 Decimal("-4.5678E50"),
1810 # a value for which hash(n) != hash(n % (2**64-1))
1811 # in Python pre-2.6
1812 Decimal(2**64 + 2**32 - 1),
1813 # selection of values which fail with the old (before
1814 # version 2.6) long.__hash__
1815 Decimal("1.634E100"),
1816 Decimal("90.697E100"),
1817 Decimal("188.83E100"),
1818 Decimal("1652.9E100"),
1819 Decimal("56531E100"),
1820 ])
1821
1822 # check that hash(d) == hash(int(d)) for integral values
1823 for value in test_values:
Stefan Krahdc817b22010-11-17 11:16:34 +00001824 self.assertEqual(hashit(value), hashit(int(value)))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001825
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001826 #the same hash that to an int
Stefan Krahdc817b22010-11-17 11:16:34 +00001827 self.assertEqual(hashit(Decimal(23)), hashit(23))
Raymond Hettingerd325c4b2010-11-21 04:08:28 +00001828 self.assertRaises(TypeError, hash, Decimal('sNaN'))
Stefan Krahdc817b22010-11-17 11:16:34 +00001829 self.assertTrue(hashit(Decimal('Inf')))
1830 self.assertTrue(hashit(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001831
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001832 # check that the hashes of a Decimal float match when they
1833 # represent exactly the same values
1834 test_strings = ['inf', '-Inf', '0.0', '-.0e1',
1835 '34.0', '2.5', '112390.625', '-0.515625']
1836 for s in test_strings:
1837 f = float(s)
1838 d = Decimal(s)
Stefan Krahdc817b22010-11-17 11:16:34 +00001839 self.assertEqual(hashit(f), hashit(d))
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001840
Stefan Krah1919b7e2012-03-21 18:25:23 +01001841 with localcontext() as c:
1842 # check that the value of the hash doesn't depend on the
1843 # current context (issue #1757)
1844 x = Decimal("123456789.1")
Christian Heimes2380ac72008-01-09 00:17:24 +00001845
Stefan Krah1919b7e2012-03-21 18:25:23 +01001846 c.prec = 6
1847 h1 = hashit(x)
1848 c.prec = 10
1849 h2 = hashit(x)
1850 c.prec = 16
1851 h3 = hashit(x)
Christian Heimes2380ac72008-01-09 00:17:24 +00001852
Stefan Krah1919b7e2012-03-21 18:25:23 +01001853 self.assertEqual(h1, h2)
1854 self.assertEqual(h1, h3)
1855
1856 c.prec = 10000
1857 x = 1100 ** 1248
1858 self.assertEqual(hashit(Decimal(x)), hashit(x))
Christian Heimes2380ac72008-01-09 00:17:24 +00001859
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001860 def test_min_and_max_methods(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001861 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001862
1863 d1 = Decimal('15.32')
1864 d2 = Decimal('28.5')
1865 l1 = 15
1866 l2 = 28
1867
1868 #between Decimals
Ezio Melotti6607d512010-04-03 14:59:49 +00001869 self.assertIs(min(d1,d2), d1)
1870 self.assertIs(min(d2,d1), d1)
1871 self.assertIs(max(d1,d2), d2)
1872 self.assertIs(max(d2,d1), d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001873
Serhiy Storchaka95949422013-08-27 19:40:23 +03001874 #between Decimal and int
Ezio Melotti6607d512010-04-03 14:59:49 +00001875 self.assertIs(min(d1,l2), d1)
1876 self.assertIs(min(l2,d1), d1)
1877 self.assertIs(max(l1,d2), d2)
1878 self.assertIs(max(d2,l1), d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001879
1880 def test_as_nonzero(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001881 Decimal = self.decimal.Decimal
1882
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001883 #as false
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001884 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001885 #as true
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001886 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001887
1888 def test_tostring_methods(self):
1889 #Test str and repr methods.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001890 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001891
1892 d = Decimal('15.32')
1893 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001894 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001895
1896 def test_tonum_methods(self):
Mark Dickinson5c2db372009-12-05 20:28:34 +00001897 #Test float and int methods.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001898 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001899
1900 d1 = Decimal('66')
1901 d2 = Decimal('15.32')
1902
1903 #int
1904 self.assertEqual(int(d1), 66)
1905 self.assertEqual(int(d2), 15)
1906
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001907 #float
1908 self.assertEqual(float(d1), 66)
1909 self.assertEqual(float(d2), 15.32)
1910
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001911 #floor
1912 test_pairs = [
1913 ('123.00', 123),
1914 ('3.2', 3),
1915 ('3.54', 3),
1916 ('3.899', 3),
1917 ('-2.3', -3),
1918 ('-11.0', -11),
1919 ('0.0', 0),
1920 ('-0E3', 0),
Stefan Krah1919b7e2012-03-21 18:25:23 +01001921 ('89891211712379812736.1', 89891211712379812736),
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001922 ]
1923 for d, i in test_pairs:
1924 self.assertEqual(math.floor(Decimal(d)), i)
1925 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1926 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1927 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1928 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1929 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1930
1931 #ceiling
1932 test_pairs = [
1933 ('123.00', 123),
1934 ('3.2', 4),
1935 ('3.54', 4),
1936 ('3.899', 4),
1937 ('-2.3', -2),
1938 ('-11.0', -11),
1939 ('0.0', 0),
1940 ('-0E3', 0),
Stefan Krah1919b7e2012-03-21 18:25:23 +01001941 ('89891211712379812736.1', 89891211712379812737),
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001942 ]
1943 for d, i in test_pairs:
1944 self.assertEqual(math.ceil(Decimal(d)), i)
1945 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1946 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1947 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1948 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1949 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1950
1951 #round, single argument
1952 test_pairs = [
1953 ('123.00', 123),
1954 ('3.2', 3),
1955 ('3.54', 4),
1956 ('3.899', 4),
1957 ('-2.3', -2),
1958 ('-11.0', -11),
1959 ('0.0', 0),
1960 ('-0E3', 0),
1961 ('-3.5', -4),
1962 ('-2.5', -2),
1963 ('-1.5', -2),
1964 ('-0.5', 0),
1965 ('0.5', 0),
1966 ('1.5', 2),
1967 ('2.5', 2),
1968 ('3.5', 4),
1969 ]
1970 for d, i in test_pairs:
1971 self.assertEqual(round(Decimal(d)), i)
1972 self.assertRaises(ValueError, round, Decimal('-NaN'))
1973 self.assertRaises(ValueError, round, Decimal('sNaN'))
1974 self.assertRaises(ValueError, round, Decimal('NaN123'))
1975 self.assertRaises(OverflowError, round, Decimal('Inf'))
1976 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1977
1978 #round, two arguments; this is essentially equivalent
1979 #to quantize, which is already extensively tested
1980 test_triples = [
1981 ('123.456', -4, '0E+4'),
1982 ('123.456', -3, '0E+3'),
1983 ('123.456', -2, '1E+2'),
1984 ('123.456', -1, '1.2E+2'),
1985 ('123.456', 0, '123'),
1986 ('123.456', 1, '123.5'),
1987 ('123.456', 2, '123.46'),
1988 ('123.456', 3, '123.456'),
1989 ('123.456', 4, '123.4560'),
1990 ('123.455', 2, '123.46'),
1991 ('123.445', 2, '123.44'),
1992 ('Inf', 4, 'NaN'),
1993 ('-Inf', -23, 'NaN'),
1994 ('sNaN314', 3, 'NaN314'),
1995 ]
1996 for d, n, r in test_triples:
1997 self.assertEqual(str(round(Decimal(d), n)), r)
1998
Mark Dickinsonfc33d4c2012-08-24 18:53:10 +01001999 def test_nan_to_float(self):
2000 # Test conversions of decimal NANs to float.
2001 # See http://bugs.python.org/issue15544
2002 Decimal = self.decimal.Decimal
2003 for s in ('nan', 'nan1234', '-nan', '-nan2468'):
2004 f = float(Decimal(s))
2005 self.assertTrue(math.isnan(f))
2006 sign = math.copysign(1.0, f)
2007 self.assertEqual(sign, -1.0 if s.startswith('-') else 1.0)
2008
2009 def test_snan_to_float(self):
2010 Decimal = self.decimal.Decimal
2011 for s in ('snan', '-snan', 'snan1357', '-snan1234'):
2012 d = Decimal(s)
2013 self.assertRaises(ValueError, float, d)
2014
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002015 def test_eval_round_trip(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01002016 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002017
2018 #with zero
2019 d = Decimal( (0, (0,), 0) )
2020 self.assertEqual(d, eval(repr(d)))
2021
2022 #int
2023 d = Decimal( (1, (4, 5), 0) )
2024 self.assertEqual(d, eval(repr(d)))
2025
2026 #float
2027 d = Decimal( (0, (4, 5, 3, 4), -2) )
2028 self.assertEqual(d, eval(repr(d)))
2029
2030 #weird
2031 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
2032 self.assertEqual(d, eval(repr(d)))
2033
2034 def test_as_tuple(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01002035 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002036
2037 #with zero
2038 d = Decimal(0)
2039 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
2040
2041 #int
2042 d = Decimal(-45)
2043 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
2044
2045 #complicated string
2046 d = Decimal("-4.34913534E-17")
2047 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
2048
Stefan Krah76e12172012-09-10 19:34:58 +02002049 # The '0' coefficient is implementation specific to decimal.py.
2050 # It has no meaning in the C-version and is ignored there.
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002051 d = Decimal("Infinity")
2052 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
2053
Guido van Rossum8ce8a782007-11-01 19:42:39 +00002054 #leading zeros in coefficient should be stripped
2055 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
2056 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
2057 d = Decimal( (1, (0, 0, 0), 37) )
2058 self.assertEqual(d.as_tuple(), (1, (0,), 37))
2059 d = Decimal( (1, (), 37) )
2060 self.assertEqual(d.as_tuple(), (1, (0,), 37))
2061
2062 #leading zeros in NaN diagnostic info should be stripped
2063 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
2064 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
2065 d = Decimal( (1, (0, 0, 0), 'N') )
2066 self.assertEqual(d.as_tuple(), (1, (), 'N') )
2067 d = Decimal( (1, (), 'n') )
2068 self.assertEqual(d.as_tuple(), (1, (), 'n') )
2069
Stefan Krah76e12172012-09-10 19:34:58 +02002070 # For infinities, decimal.py has always silently accepted any
2071 # coefficient tuple.
2072 d = Decimal( (0, (0,), 'F') )
2073 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
2074 d = Decimal( (0, (4, 5, 3, 4), 'F') )
2075 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
2076 d = Decimal( (1, (0, 2, 7, 1), 'F') )
2077 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
Guido van Rossum8ce8a782007-11-01 19:42:39 +00002078
Stefan Krah53f2e0a2015-12-28 23:02:02 +01002079 def test_as_integer_ratio(self):
2080 Decimal = self.decimal.Decimal
2081
2082 # exceptional cases
2083 self.assertRaises(OverflowError,
2084 Decimal.as_integer_ratio, Decimal('inf'))
2085 self.assertRaises(OverflowError,
2086 Decimal.as_integer_ratio, Decimal('-inf'))
2087 self.assertRaises(ValueError,
2088 Decimal.as_integer_ratio, Decimal('-nan'))
2089 self.assertRaises(ValueError,
2090 Decimal.as_integer_ratio, Decimal('snan123'))
2091
2092 for exp in range(-4, 2):
2093 for coeff in range(1000):
2094 for sign in '+', '-':
2095 d = Decimal('%s%dE%d' % (sign, coeff, exp))
2096 pq = d.as_integer_ratio()
2097 p, q = pq
2098
2099 # check return type
2100 self.assertIsInstance(pq, tuple)
2101 self.assertIsInstance(p, int)
2102 self.assertIsInstance(q, int)
2103
2104 # check normalization: q should be positive;
2105 # p should be relatively prime to q.
2106 self.assertGreater(q, 0)
2107 self.assertEqual(math.gcd(p, q), 1)
2108
2109 # check that p/q actually gives the correct value
2110 self.assertEqual(Decimal(p) / Decimal(q), d)
2111
Stefan Krah1919b7e2012-03-21 18:25:23 +01002112 def test_subclassing(self):
2113 # Different behaviours when subclassing Decimal
2114 Decimal = self.decimal.Decimal
2115
2116 class MyDecimal(Decimal):
Stefan Krah0f82b762012-11-08 11:17:29 +01002117 y = None
Stefan Krah1919b7e2012-03-21 18:25:23 +01002118
2119 d1 = MyDecimal(1)
2120 d2 = MyDecimal(2)
2121 d = d1 + d2
2122 self.assertIs(type(d), Decimal)
2123
2124 d = d1.max(d2)
2125 self.assertIs(type(d), Decimal)
2126
2127 d = copy.copy(d1)
2128 self.assertIs(type(d), MyDecimal)
2129 self.assertEqual(d, d1)
2130
2131 d = copy.deepcopy(d1)
2132 self.assertIs(type(d), MyDecimal)
2133 self.assertEqual(d, d1)
2134
Stefan Krah0f82b762012-11-08 11:17:29 +01002135 # Decimal(Decimal)
2136 d = Decimal('1.0')
2137 x = Decimal(d)
2138 self.assertIs(type(x), Decimal)
2139 self.assertEqual(x, d)
Stefan Krahf4abc7b2012-11-07 23:12:25 +01002140
Stefan Krah0f82b762012-11-08 11:17:29 +01002141 # MyDecimal(Decimal)
2142 m = MyDecimal(d)
2143 self.assertIs(type(m), MyDecimal)
2144 self.assertEqual(m, d)
2145 self.assertIs(m.y, None)
2146
2147 # Decimal(MyDecimal)
2148 x = Decimal(m)
2149 self.assertIs(type(x), Decimal)
2150 self.assertEqual(x, d)
2151
2152 # MyDecimal(MyDecimal)
2153 m.y = 9
2154 x = MyDecimal(m)
2155 self.assertIs(type(x), MyDecimal)
2156 self.assertEqual(x, d)
2157 self.assertIs(x.y, None)
Stefan Krahed16eff2012-11-07 23:47:19 +01002158
Stefan Krah1919b7e2012-03-21 18:25:23 +01002159 def test_implicit_context(self):
2160 Decimal = self.decimal.Decimal
2161 getcontext = self.decimal.getcontext
2162
2163 # Check results when context given implicitly. (Issue 2478)
2164 c = getcontext()
2165 self.assertEqual(str(Decimal(0).sqrt()),
2166 str(c.sqrt(Decimal(0))))
2167
Stefan Krah040e3112012-12-15 22:33:33 +01002168 def test_none_args(self):
2169 Decimal = self.decimal.Decimal
2170 Context = self.decimal.Context
2171 localcontext = self.decimal.localcontext
2172 InvalidOperation = self.decimal.InvalidOperation
2173 DivisionByZero = self.decimal.DivisionByZero
2174 Overflow = self.decimal.Overflow
2175 Underflow = self.decimal.Underflow
2176 Subnormal = self.decimal.Subnormal
2177 Inexact = self.decimal.Inexact
2178 Rounded = self.decimal.Rounded
2179 Clamped = self.decimal.Clamped
Stefan Krah040e3112012-12-15 22:33:33 +01002180
2181 with localcontext(Context()) as c:
2182 c.prec = 7
2183 c.Emax = 999
2184 c.Emin = -999
2185
2186 x = Decimal("111")
2187 y = Decimal("1e9999")
2188 z = Decimal("1e-9999")
2189
2190 ##### Unary functions
2191 c.clear_flags()
2192 self.assertEqual(str(x.exp(context=None)), '1.609487E+48')
2193 self.assertTrue(c.flags[Inexact])
2194 self.assertTrue(c.flags[Rounded])
2195 c.clear_flags()
2196 self.assertRaises(Overflow, y.exp, context=None)
2197 self.assertTrue(c.flags[Overflow])
2198
2199 self.assertIs(z.is_normal(context=None), False)
2200 self.assertIs(z.is_subnormal(context=None), True)
2201
2202 c.clear_flags()
2203 self.assertEqual(str(x.ln(context=None)), '4.709530')
2204 self.assertTrue(c.flags[Inexact])
2205 self.assertTrue(c.flags[Rounded])
2206 c.clear_flags()
2207 self.assertRaises(InvalidOperation, Decimal(-1).ln, context=None)
2208 self.assertTrue(c.flags[InvalidOperation])
2209
2210 c.clear_flags()
2211 self.assertEqual(str(x.log10(context=None)), '2.045323')
2212 self.assertTrue(c.flags[Inexact])
2213 self.assertTrue(c.flags[Rounded])
2214 c.clear_flags()
2215 self.assertRaises(InvalidOperation, Decimal(-1).log10, context=None)
2216 self.assertTrue(c.flags[InvalidOperation])
2217
2218 c.clear_flags()
2219 self.assertEqual(str(x.logb(context=None)), '2')
2220 self.assertRaises(DivisionByZero, Decimal(0).logb, context=None)
2221 self.assertTrue(c.flags[DivisionByZero])
2222
2223 c.clear_flags()
2224 self.assertEqual(str(x.logical_invert(context=None)), '1111000')
2225 self.assertRaises(InvalidOperation, y.logical_invert, context=None)
2226 self.assertTrue(c.flags[InvalidOperation])
2227
2228 c.clear_flags()
2229 self.assertEqual(str(y.next_minus(context=None)), '9.999999E+999')
2230 self.assertRaises(InvalidOperation, Decimal('sNaN').next_minus, context=None)
2231 self.assertTrue(c.flags[InvalidOperation])
2232
2233 c.clear_flags()
2234 self.assertEqual(str(y.next_plus(context=None)), 'Infinity')
2235 self.assertRaises(InvalidOperation, Decimal('sNaN').next_plus, context=None)
2236 self.assertTrue(c.flags[InvalidOperation])
2237
2238 c.clear_flags()
2239 self.assertEqual(str(z.normalize(context=None)), '0')
2240 self.assertRaises(Overflow, y.normalize, context=None)
2241 self.assertTrue(c.flags[Overflow])
2242
2243 self.assertEqual(str(z.number_class(context=None)), '+Subnormal')
2244
2245 c.clear_flags()
2246 self.assertEqual(str(z.sqrt(context=None)), '0E-1005')
2247 self.assertTrue(c.flags[Clamped])
2248 self.assertTrue(c.flags[Inexact])
2249 self.assertTrue(c.flags[Rounded])
2250 self.assertTrue(c.flags[Subnormal])
2251 self.assertTrue(c.flags[Underflow])
2252 c.clear_flags()
2253 self.assertRaises(Overflow, y.sqrt, context=None)
2254 self.assertTrue(c.flags[Overflow])
2255
2256 c.capitals = 0
2257 self.assertEqual(str(z.to_eng_string(context=None)), '1e-9999')
2258 c.capitals = 1
2259
2260
2261 ##### Binary functions
2262 c.clear_flags()
2263 ans = str(x.compare(Decimal('Nan891287828'), context=None))
2264 self.assertEqual(ans, 'NaN1287828')
2265 self.assertRaises(InvalidOperation, x.compare, Decimal('sNaN'), context=None)
2266 self.assertTrue(c.flags[InvalidOperation])
2267
2268 c.clear_flags()
2269 ans = str(x.compare_signal(8224, context=None))
2270 self.assertEqual(ans, '-1')
2271 self.assertRaises(InvalidOperation, x.compare_signal, Decimal('NaN'), context=None)
2272 self.assertTrue(c.flags[InvalidOperation])
2273
2274 c.clear_flags()
2275 ans = str(x.logical_and(101, context=None))
2276 self.assertEqual(ans, '101')
2277 self.assertRaises(InvalidOperation, x.logical_and, 123, context=None)
2278 self.assertTrue(c.flags[InvalidOperation])
2279
2280 c.clear_flags()
2281 ans = str(x.logical_or(101, context=None))
2282 self.assertEqual(ans, '111')
2283 self.assertRaises(InvalidOperation, x.logical_or, 123, context=None)
2284 self.assertTrue(c.flags[InvalidOperation])
2285
2286 c.clear_flags()
2287 ans = str(x.logical_xor(101, context=None))
2288 self.assertEqual(ans, '10')
2289 self.assertRaises(InvalidOperation, x.logical_xor, 123, context=None)
2290 self.assertTrue(c.flags[InvalidOperation])
2291
2292 c.clear_flags()
2293 ans = str(x.max(101, context=None))
2294 self.assertEqual(ans, '111')
2295 self.assertRaises(InvalidOperation, x.max, Decimal('sNaN'), context=None)
2296 self.assertTrue(c.flags[InvalidOperation])
2297
2298 c.clear_flags()
2299 ans = str(x.max_mag(101, context=None))
2300 self.assertEqual(ans, '111')
2301 self.assertRaises(InvalidOperation, x.max_mag, Decimal('sNaN'), context=None)
2302 self.assertTrue(c.flags[InvalidOperation])
2303
2304 c.clear_flags()
2305 ans = str(x.min(101, context=None))
2306 self.assertEqual(ans, '101')
2307 self.assertRaises(InvalidOperation, x.min, Decimal('sNaN'), context=None)
2308 self.assertTrue(c.flags[InvalidOperation])
2309
2310 c.clear_flags()
2311 ans = str(x.min_mag(101, context=None))
2312 self.assertEqual(ans, '101')
2313 self.assertRaises(InvalidOperation, x.min_mag, Decimal('sNaN'), context=None)
2314 self.assertTrue(c.flags[InvalidOperation])
2315
2316 c.clear_flags()
2317 ans = str(x.remainder_near(101, context=None))
2318 self.assertEqual(ans, '10')
2319 self.assertRaises(InvalidOperation, y.remainder_near, 101, context=None)
2320 self.assertTrue(c.flags[InvalidOperation])
2321
2322 c.clear_flags()
2323 ans = str(x.rotate(2, context=None))
2324 self.assertEqual(ans, '11100')
2325 self.assertRaises(InvalidOperation, x.rotate, 101, context=None)
2326 self.assertTrue(c.flags[InvalidOperation])
2327
2328 c.clear_flags()
2329 ans = str(x.scaleb(7, context=None))
2330 self.assertEqual(ans, '1.11E+9')
2331 self.assertRaises(InvalidOperation, x.scaleb, 10000, context=None)
2332 self.assertTrue(c.flags[InvalidOperation])
2333
2334 c.clear_flags()
2335 ans = str(x.shift(2, context=None))
2336 self.assertEqual(ans, '11100')
2337 self.assertRaises(InvalidOperation, x.shift, 10000, context=None)
2338 self.assertTrue(c.flags[InvalidOperation])
2339
2340
2341 ##### Ternary functions
2342 c.clear_flags()
2343 ans = str(x.fma(2, 3, context=None))
2344 self.assertEqual(ans, '225')
2345 self.assertRaises(Overflow, x.fma, Decimal('1e9999'), 3, context=None)
2346 self.assertTrue(c.flags[Overflow])
2347
2348
2349 ##### Special cases
2350 c.rounding = ROUND_HALF_EVEN
2351 ans = str(Decimal('1.5').to_integral(rounding=None, context=None))
2352 self.assertEqual(ans, '2')
2353 c.rounding = ROUND_DOWN
2354 ans = str(Decimal('1.5').to_integral(rounding=None, context=None))
2355 self.assertEqual(ans, '1')
2356 ans = str(Decimal('1.5').to_integral(rounding=ROUND_UP, context=None))
2357 self.assertEqual(ans, '2')
2358 c.clear_flags()
2359 self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral, context=None)
2360 self.assertTrue(c.flags[InvalidOperation])
2361
2362 c.rounding = ROUND_HALF_EVEN
2363 ans = str(Decimal('1.5').to_integral_value(rounding=None, context=None))
2364 self.assertEqual(ans, '2')
2365 c.rounding = ROUND_DOWN
2366 ans = str(Decimal('1.5').to_integral_value(rounding=None, context=None))
2367 self.assertEqual(ans, '1')
2368 ans = str(Decimal('1.5').to_integral_value(rounding=ROUND_UP, context=None))
2369 self.assertEqual(ans, '2')
2370 c.clear_flags()
2371 self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral_value, context=None)
2372 self.assertTrue(c.flags[InvalidOperation])
2373
2374 c.rounding = ROUND_HALF_EVEN
2375 ans = str(Decimal('1.5').to_integral_exact(rounding=None, context=None))
2376 self.assertEqual(ans, '2')
2377 c.rounding = ROUND_DOWN
2378 ans = str(Decimal('1.5').to_integral_exact(rounding=None, context=None))
2379 self.assertEqual(ans, '1')
2380 ans = str(Decimal('1.5').to_integral_exact(rounding=ROUND_UP, context=None))
2381 self.assertEqual(ans, '2')
2382 c.clear_flags()
2383 self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral_exact, context=None)
2384 self.assertTrue(c.flags[InvalidOperation])
2385
2386 c.rounding = ROUND_UP
2387 ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=None, context=None))
2388 self.assertEqual(ans, '1.501')
2389 c.rounding = ROUND_DOWN
2390 ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=None, context=None))
2391 self.assertEqual(ans, '1.500')
2392 ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=ROUND_UP, context=None))
2393 self.assertEqual(ans, '1.501')
2394 c.clear_flags()
2395 self.assertRaises(InvalidOperation, y.quantize, Decimal('1e-10'), rounding=ROUND_UP, context=None)
2396 self.assertTrue(c.flags[InvalidOperation])
2397
2398 with localcontext(Context()) as context:
2399 context.prec = 7
2400 context.Emax = 999
2401 context.Emin = -999
2402 with localcontext(ctx=None) as c:
2403 self.assertEqual(c.prec, 7)
2404 self.assertEqual(c.Emax, 999)
2405 self.assertEqual(c.Emin, -999)
2406
Stefan Krah1919b7e2012-03-21 18:25:23 +01002407 def test_conversions_from_int(self):
2408 # Check that methods taking a second Decimal argument will
2409 # always accept an integer in place of a Decimal.
2410 Decimal = self.decimal.Decimal
2411
2412 self.assertEqual(Decimal(4).compare(3),
2413 Decimal(4).compare(Decimal(3)))
2414 self.assertEqual(Decimal(4).compare_signal(3),
2415 Decimal(4).compare_signal(Decimal(3)))
2416 self.assertEqual(Decimal(4).compare_total(3),
2417 Decimal(4).compare_total(Decimal(3)))
2418 self.assertEqual(Decimal(4).compare_total_mag(3),
2419 Decimal(4).compare_total_mag(Decimal(3)))
2420 self.assertEqual(Decimal(10101).logical_and(1001),
2421 Decimal(10101).logical_and(Decimal(1001)))
2422 self.assertEqual(Decimal(10101).logical_or(1001),
2423 Decimal(10101).logical_or(Decimal(1001)))
2424 self.assertEqual(Decimal(10101).logical_xor(1001),
2425 Decimal(10101).logical_xor(Decimal(1001)))
2426 self.assertEqual(Decimal(567).max(123),
2427 Decimal(567).max(Decimal(123)))
2428 self.assertEqual(Decimal(567).max_mag(123),
2429 Decimal(567).max_mag(Decimal(123)))
2430 self.assertEqual(Decimal(567).min(123),
2431 Decimal(567).min(Decimal(123)))
2432 self.assertEqual(Decimal(567).min_mag(123),
2433 Decimal(567).min_mag(Decimal(123)))
2434 self.assertEqual(Decimal(567).next_toward(123),
2435 Decimal(567).next_toward(Decimal(123)))
2436 self.assertEqual(Decimal(1234).quantize(100),
2437 Decimal(1234).quantize(Decimal(100)))
2438 self.assertEqual(Decimal(768).remainder_near(1234),
2439 Decimal(768).remainder_near(Decimal(1234)))
2440 self.assertEqual(Decimal(123).rotate(1),
2441 Decimal(123).rotate(Decimal(1)))
2442 self.assertEqual(Decimal(1234).same_quantum(1000),
2443 Decimal(1234).same_quantum(Decimal(1000)))
2444 self.assertEqual(Decimal('9.123').scaleb(-100),
2445 Decimal('9.123').scaleb(Decimal(-100)))
2446 self.assertEqual(Decimal(456).shift(-1),
2447 Decimal(456).shift(Decimal(-1)))
2448
2449 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
2450 Decimal(-12).fma(Decimal(45), Decimal(67)))
2451 self.assertEqual(Decimal(-12).fma(45, 67),
2452 Decimal(-12).fma(Decimal(45), Decimal(67)))
2453 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
2454 Decimal(-12).fma(Decimal(45), Decimal(67)))
2455
2456class CUsabilityTest(UsabilityTest):
2457 decimal = C
2458class PyUsabilityTest(UsabilityTest):
2459 decimal = P
2460
2461class PythonAPItests(unittest.TestCase):
2462
2463 def test_abc(self):
2464 Decimal = self.decimal.Decimal
2465
2466 self.assertTrue(issubclass(Decimal, numbers.Number))
2467 self.assertFalse(issubclass(Decimal, numbers.Real))
2468 self.assertIsInstance(Decimal(0), numbers.Number)
2469 self.assertNotIsInstance(Decimal(0), numbers.Real)
2470
2471 def test_pickle(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02002472 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
2473 Decimal = self.decimal.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002474
Serhiy Storchakabad12572014-12-15 14:03:42 +02002475 savedecimal = sys.modules['decimal']
Stefan Krah1919b7e2012-03-21 18:25:23 +01002476
Serhiy Storchakabad12572014-12-15 14:03:42 +02002477 # Round trip
2478 sys.modules['decimal'] = self.decimal
2479 d = Decimal('-3.141590000')
2480 p = pickle.dumps(d, proto)
2481 e = pickle.loads(p)
2482 self.assertEqual(d, e)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002483
Serhiy Storchakabad12572014-12-15 14:03:42 +02002484 if C:
2485 # Test interchangeability
2486 x = C.Decimal('-3.123e81723')
2487 y = P.Decimal('-3.123e81723')
Stefan Krah1919b7e2012-03-21 18:25:23 +01002488
Serhiy Storchakabad12572014-12-15 14:03:42 +02002489 sys.modules['decimal'] = C
2490 sx = pickle.dumps(x, proto)
2491 sys.modules['decimal'] = P
2492 r = pickle.loads(sx)
2493 self.assertIsInstance(r, P.Decimal)
2494 self.assertEqual(r, y)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002495
Serhiy Storchakabad12572014-12-15 14:03:42 +02002496 sys.modules['decimal'] = P
2497 sy = pickle.dumps(y, proto)
2498 sys.modules['decimal'] = C
2499 r = pickle.loads(sy)
2500 self.assertIsInstance(r, C.Decimal)
2501 self.assertEqual(r, x)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002502
Serhiy Storchakabad12572014-12-15 14:03:42 +02002503 x = C.Decimal('-3.123e81723').as_tuple()
2504 y = P.Decimal('-3.123e81723').as_tuple()
Stefan Krahf1d4e422014-04-29 18:23:35 +02002505
Serhiy Storchakabad12572014-12-15 14:03:42 +02002506 sys.modules['decimal'] = C
2507 sx = pickle.dumps(x, proto)
2508 sys.modules['decimal'] = P
2509 r = pickle.loads(sx)
2510 self.assertIsInstance(r, P.DecimalTuple)
2511 self.assertEqual(r, y)
Stefan Krahf1d4e422014-04-29 18:23:35 +02002512
Serhiy Storchakabad12572014-12-15 14:03:42 +02002513 sys.modules['decimal'] = P
2514 sy = pickle.dumps(y, proto)
2515 sys.modules['decimal'] = C
2516 r = pickle.loads(sy)
2517 self.assertIsInstance(r, C.DecimalTuple)
2518 self.assertEqual(r, x)
Stefan Krahf1d4e422014-04-29 18:23:35 +02002519
Serhiy Storchakabad12572014-12-15 14:03:42 +02002520 sys.modules['decimal'] = savedecimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002521
2522 def test_int(self):
2523 Decimal = self.decimal.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002524
2525 for x in range(-250, 250):
2526 s = '%0.2f' % (x / 100.0)
2527 # should work the same as for floats
2528 self.assertEqual(int(Decimal(s)), int(float(s)))
2529 # should work the same as to_integral in the ROUND_DOWN mode
2530 d = Decimal(s)
2531 r = d.to_integral(ROUND_DOWN)
2532 self.assertEqual(Decimal(int(d)), r)
2533
2534 self.assertRaises(ValueError, int, Decimal('-nan'))
2535 self.assertRaises(ValueError, int, Decimal('snan'))
2536 self.assertRaises(OverflowError, int, Decimal('inf'))
2537 self.assertRaises(OverflowError, int, Decimal('-inf'))
2538
2539 def test_trunc(self):
2540 Decimal = self.decimal.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002541
2542 for x in range(-250, 250):
2543 s = '%0.2f' % (x / 100.0)
2544 # should work the same as for floats
2545 self.assertEqual(int(Decimal(s)), int(float(s)))
2546 # should work the same as to_integral in the ROUND_DOWN mode
2547 d = Decimal(s)
2548 r = d.to_integral(ROUND_DOWN)
2549 self.assertEqual(Decimal(math.trunc(d)), r)
2550
2551 def test_from_float(self):
2552
2553 Decimal = self.decimal.Decimal
2554
2555 class MyDecimal(Decimal):
Stefan Krah6817c592016-06-20 12:10:13 +02002556 def __init__(self, _):
2557 self.x = 'y'
Stefan Krah1919b7e2012-03-21 18:25:23 +01002558
2559 self.assertTrue(issubclass(MyDecimal, Decimal))
2560
2561 r = MyDecimal.from_float(0.1)
2562 self.assertEqual(type(r), MyDecimal)
2563 self.assertEqual(str(r),
2564 '0.1000000000000000055511151231257827021181583404541015625')
Stefan Krah6817c592016-06-20 12:10:13 +02002565 self.assertEqual(r.x, 'y')
2566
Stefan Krah1919b7e2012-03-21 18:25:23 +01002567 bigint = 12345678901234567890123456789
2568 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
2569 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
2570 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
2571 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
2572 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
2573 str(Decimal('NaN')))
2574 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
2575 str(Decimal('Infinity')))
2576 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
2577 str(Decimal('-Infinity')))
2578 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
2579 for i in range(200):
2580 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
2581 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
2582
2583 def test_create_decimal_from_float(self):
2584 Decimal = self.decimal.Decimal
2585 Context = self.decimal.Context
Stefan Krah1919b7e2012-03-21 18:25:23 +01002586 Inexact = self.decimal.Inexact
2587
2588 context = Context(prec=5, rounding=ROUND_DOWN)
2589 self.assertEqual(
2590 context.create_decimal_from_float(math.pi),
2591 Decimal('3.1415')
2592 )
2593 context = Context(prec=5, rounding=ROUND_UP)
2594 self.assertEqual(
2595 context.create_decimal_from_float(math.pi),
2596 Decimal('3.1416')
2597 )
2598 context = Context(prec=5, traps=[Inexact])
2599 self.assertRaises(
2600 Inexact,
2601 context.create_decimal_from_float,
2602 math.pi
2603 )
2604 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
2605 "Decimal('-0')")
2606 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
2607 "Decimal('1')")
2608 self.assertEqual(repr(context.create_decimal_from_float(10)),
2609 "Decimal('10')")
2610
2611 def test_quantize(self):
2612 Decimal = self.decimal.Decimal
2613 Context = self.decimal.Context
2614 InvalidOperation = self.decimal.InvalidOperation
Stefan Krah1919b7e2012-03-21 18:25:23 +01002615
2616 c = Context(Emax=99999, Emin=-99999)
2617 self.assertEqual(
2618 Decimal('7.335').quantize(Decimal('.01')),
2619 Decimal('7.34')
2620 )
2621 self.assertEqual(
2622 Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN),
2623 Decimal('7.33')
2624 )
2625 self.assertRaises(
2626 InvalidOperation,
2627 Decimal("10e99999").quantize, Decimal('1e100000'), context=c
2628 )
2629
2630 c = Context()
2631 d = Decimal("0.871831e800")
2632 x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN)
2633 self.assertEqual(x, Decimal('8.71E+799'))
2634
2635 def test_complex(self):
2636 Decimal = self.decimal.Decimal
2637
2638 x = Decimal("9.8182731e181273")
2639 self.assertEqual(x.real, x)
2640 self.assertEqual(x.imag, 0)
2641 self.assertEqual(x.conjugate(), x)
2642
2643 x = Decimal("1")
2644 self.assertEqual(complex(x), complex(float(1)))
2645
2646 self.assertRaises(AttributeError, setattr, x, 'real', 100)
2647 self.assertRaises(AttributeError, setattr, x, 'imag', 100)
2648 self.assertRaises(AttributeError, setattr, x, 'conjugate', 100)
2649 self.assertRaises(AttributeError, setattr, x, '__complex__', 100)
2650
2651 def test_named_parameters(self):
2652 D = self.decimal.Decimal
2653 Context = self.decimal.Context
2654 localcontext = self.decimal.localcontext
2655 InvalidOperation = self.decimal.InvalidOperation
2656 Overflow = self.decimal.Overflow
2657
2658 xc = Context()
2659 xc.prec = 1
2660 xc.Emax = 1
2661 xc.Emin = -1
2662
2663 with localcontext() as c:
2664 c.clear_flags()
2665
2666 self.assertEqual(D(9, xc), 9)
2667 self.assertEqual(D(9, context=xc), 9)
2668 self.assertEqual(D(context=xc, value=9), 9)
2669 self.assertEqual(D(context=xc), 0)
2670 xc.clear_flags()
2671 self.assertRaises(InvalidOperation, D, "xyz", context=xc)
2672 self.assertTrue(xc.flags[InvalidOperation])
2673 self.assertFalse(c.flags[InvalidOperation])
2674
2675 xc.clear_flags()
2676 self.assertEqual(D(2).exp(context=xc), 7)
2677 self.assertRaises(Overflow, D(8).exp, context=xc)
2678 self.assertTrue(xc.flags[Overflow])
2679 self.assertFalse(c.flags[Overflow])
2680
2681 xc.clear_flags()
2682 self.assertEqual(D(2).ln(context=xc), D('0.7'))
2683 self.assertRaises(InvalidOperation, D(-1).ln, context=xc)
2684 self.assertTrue(xc.flags[InvalidOperation])
2685 self.assertFalse(c.flags[InvalidOperation])
2686
2687 self.assertEqual(D(0).log10(context=xc), D('-inf'))
2688 self.assertEqual(D(-1).next_minus(context=xc), -2)
2689 self.assertEqual(D(-1).next_plus(context=xc), D('-0.9'))
2690 self.assertEqual(D("9.73").normalize(context=xc), D('1E+1'))
2691 self.assertEqual(D("9999").to_integral(context=xc), 9999)
2692 self.assertEqual(D("-2000").to_integral_exact(context=xc), -2000)
2693 self.assertEqual(D("123").to_integral_value(context=xc), 123)
2694 self.assertEqual(D("0.0625").sqrt(context=xc), D('0.2'))
2695
2696 self.assertEqual(D("0.0625").compare(context=xc, other=3), -1)
2697 xc.clear_flags()
2698 self.assertRaises(InvalidOperation,
2699 D("0").compare_signal, D('nan'), context=xc)
2700 self.assertTrue(xc.flags[InvalidOperation])
2701 self.assertFalse(c.flags[InvalidOperation])
2702 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2703 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2704 self.assertEqual(D("0.2").max_mag(D('-0.3'), context=xc),
2705 D('-0.3'))
2706 self.assertEqual(D("0.02").min(D('-0.03'), context=xc), D('-0.0'))
2707 self.assertEqual(D("0.02").min_mag(D('-0.03'), context=xc),
2708 D('0.0'))
2709 self.assertEqual(D("0.2").next_toward(D('-1'), context=xc), D('0.1'))
2710 xc.clear_flags()
2711 self.assertRaises(InvalidOperation,
2712 D("0.2").quantize, D('1e10'), context=xc)
2713 self.assertTrue(xc.flags[InvalidOperation])
2714 self.assertFalse(c.flags[InvalidOperation])
2715 self.assertEqual(D("9.99").remainder_near(D('1.5'), context=xc),
2716 D('-0.5'))
2717
2718 self.assertEqual(D("9.9").fma(third=D('0.9'), context=xc, other=7),
2719 D('7E+1'))
2720
2721 self.assertRaises(TypeError, D(1).is_canonical, context=xc)
2722 self.assertRaises(TypeError, D(1).is_finite, context=xc)
2723 self.assertRaises(TypeError, D(1).is_infinite, context=xc)
2724 self.assertRaises(TypeError, D(1).is_nan, context=xc)
2725 self.assertRaises(TypeError, D(1).is_qnan, context=xc)
2726 self.assertRaises(TypeError, D(1).is_snan, context=xc)
2727 self.assertRaises(TypeError, D(1).is_signed, context=xc)
2728 self.assertRaises(TypeError, D(1).is_zero, context=xc)
2729
2730 self.assertFalse(D("0.01").is_normal(context=xc))
2731 self.assertTrue(D("0.01").is_subnormal(context=xc))
2732
2733 self.assertRaises(TypeError, D(1).adjusted, context=xc)
2734 self.assertRaises(TypeError, D(1).conjugate, context=xc)
2735 self.assertRaises(TypeError, D(1).radix, context=xc)
2736
2737 self.assertEqual(D(-111).logb(context=xc), 2)
2738 self.assertEqual(D(0).logical_invert(context=xc), 1)
2739 self.assertEqual(D('0.01').number_class(context=xc), '+Subnormal')
2740 self.assertEqual(D('0.21').to_eng_string(context=xc), '0.21')
2741
2742 self.assertEqual(D('11').logical_and(D('10'), context=xc), 0)
2743 self.assertEqual(D('11').logical_or(D('10'), context=xc), 1)
2744 self.assertEqual(D('01').logical_xor(D('10'), context=xc), 1)
2745 self.assertEqual(D('23').rotate(1, context=xc), 3)
2746 self.assertEqual(D('23').rotate(1, context=xc), 3)
2747 xc.clear_flags()
2748 self.assertRaises(Overflow,
2749 D('23').scaleb, 1, context=xc)
2750 self.assertTrue(xc.flags[Overflow])
2751 self.assertFalse(c.flags[Overflow])
2752 self.assertEqual(D('23').shift(-1, context=xc), 0)
2753
2754 self.assertRaises(TypeError, D.from_float, 1.1, context=xc)
2755 self.assertRaises(TypeError, D(0).as_tuple, context=xc)
2756
Stefan Krah040e3112012-12-15 22:33:33 +01002757 self.assertEqual(D(1).canonical(), 1)
2758 self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
2759 self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
2760 self.assertRaises(TypeError, D(1).canonical, context="x")
2761 self.assertRaises(TypeError, D(1).canonical, xyz="x")
Stefan Krah1919b7e2012-03-21 18:25:23 +01002762
Stefan Krahb6405ef2012-03-23 14:46:48 +01002763 def test_exception_hierarchy(self):
2764
2765 decimal = self.decimal
2766 DecimalException = decimal.DecimalException
2767 InvalidOperation = decimal.InvalidOperation
2768 FloatOperation = decimal.FloatOperation
2769 DivisionByZero = decimal.DivisionByZero
2770 Overflow = decimal.Overflow
2771 Underflow = decimal.Underflow
2772 Subnormal = decimal.Subnormal
2773 Inexact = decimal.Inexact
2774 Rounded = decimal.Rounded
2775 Clamped = decimal.Clamped
2776
2777 self.assertTrue(issubclass(DecimalException, ArithmeticError))
2778
2779 self.assertTrue(issubclass(InvalidOperation, DecimalException))
2780 self.assertTrue(issubclass(FloatOperation, DecimalException))
2781 self.assertTrue(issubclass(FloatOperation, TypeError))
2782 self.assertTrue(issubclass(DivisionByZero, DecimalException))
2783 self.assertTrue(issubclass(DivisionByZero, ZeroDivisionError))
2784 self.assertTrue(issubclass(Overflow, Rounded))
2785 self.assertTrue(issubclass(Overflow, Inexact))
2786 self.assertTrue(issubclass(Overflow, DecimalException))
2787 self.assertTrue(issubclass(Underflow, Inexact))
2788 self.assertTrue(issubclass(Underflow, Rounded))
2789 self.assertTrue(issubclass(Underflow, Subnormal))
2790 self.assertTrue(issubclass(Underflow, DecimalException))
2791
2792 self.assertTrue(issubclass(Subnormal, DecimalException))
2793 self.assertTrue(issubclass(Inexact, DecimalException))
2794 self.assertTrue(issubclass(Rounded, DecimalException))
2795 self.assertTrue(issubclass(Clamped, DecimalException))
2796
2797 self.assertTrue(issubclass(decimal.ConversionSyntax, InvalidOperation))
2798 self.assertTrue(issubclass(decimal.DivisionImpossible, InvalidOperation))
2799 self.assertTrue(issubclass(decimal.DivisionUndefined, InvalidOperation))
2800 self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError))
2801 self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation))
2802
Stefan Krah1919b7e2012-03-21 18:25:23 +01002803class CPythonAPItests(PythonAPItests):
2804 decimal = C
2805class PyPythonAPItests(PythonAPItests):
2806 decimal = P
2807
2808class ContextAPItests(unittest.TestCase):
2809
Stefan Krah9a4ff432012-12-16 21:10:35 +01002810 def test_none_args(self):
2811 Context = self.decimal.Context
2812 InvalidOperation = self.decimal.InvalidOperation
2813 DivisionByZero = self.decimal.DivisionByZero
2814 Overflow = self.decimal.Overflow
Stefan Krah9a4ff432012-12-16 21:10:35 +01002815
2816 c1 = Context()
2817 c2 = Context(prec=None, rounding=None, Emax=None, Emin=None,
2818 capitals=None, clamp=None, flags=None, traps=None)
2819 for c in [c1, c2]:
2820 self.assertEqual(c.prec, 28)
2821 self.assertEqual(c.rounding, ROUND_HALF_EVEN)
2822 self.assertEqual(c.Emax, 999999)
2823 self.assertEqual(c.Emin, -999999)
2824 self.assertEqual(c.capitals, 1)
2825 self.assertEqual(c.clamp, 0)
2826 assert_signals(self, c, 'flags', [])
2827 assert_signals(self, c, 'traps', [InvalidOperation, DivisionByZero,
2828 Overflow])
2829
Stefan Krah59a4a932013-01-16 12:58:59 +01002830 @cpython_only
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03002831 @requires_legacy_unicode_capi
Inada Naoki902356a2020-07-20 12:02:50 +09002832 @warnings_helper.ignore_warnings(category=DeprecationWarning)
Stefan Krah59a4a932013-01-16 12:58:59 +01002833 def test_from_legacy_strings(self):
2834 import _testcapi
2835 c = self.decimal.Context()
2836
2837 for rnd in RoundingModes:
2838 c.rounding = _testcapi.unicode_legacy_string(rnd)
2839 self.assertEqual(c.rounding, rnd)
2840
2841 s = _testcapi.unicode_legacy_string('')
2842 self.assertRaises(TypeError, setattr, c, 'rounding', s)
2843
2844 s = _testcapi.unicode_legacy_string('ROUND_\x00UP')
2845 self.assertRaises(TypeError, setattr, c, 'rounding', s)
2846
Stefan Krah1919b7e2012-03-21 18:25:23 +01002847 def test_pickle(self):
2848
Serhiy Storchakabad12572014-12-15 14:03:42 +02002849 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
2850 Context = self.decimal.Context
Stefan Krah1919b7e2012-03-21 18:25:23 +01002851
Serhiy Storchakabad12572014-12-15 14:03:42 +02002852 savedecimal = sys.modules['decimal']
Stefan Krah1919b7e2012-03-21 18:25:23 +01002853
Serhiy Storchakabad12572014-12-15 14:03:42 +02002854 # Round trip
2855 sys.modules['decimal'] = self.decimal
2856 c = Context()
2857 e = pickle.loads(pickle.dumps(c, proto))
Stefan Krah1919b7e2012-03-21 18:25:23 +01002858
Serhiy Storchakabad12572014-12-15 14:03:42 +02002859 self.assertEqual(c.prec, e.prec)
2860 self.assertEqual(c.Emin, e.Emin)
2861 self.assertEqual(c.Emax, e.Emax)
2862 self.assertEqual(c.rounding, e.rounding)
2863 self.assertEqual(c.capitals, e.capitals)
2864 self.assertEqual(c.clamp, e.clamp)
2865 self.assertEqual(c.flags, e.flags)
2866 self.assertEqual(c.traps, e.traps)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002867
Serhiy Storchakabad12572014-12-15 14:03:42 +02002868 # Test interchangeability
2869 combinations = [(C, P), (P, C)] if C else [(P, P)]
2870 for dumper, loader in combinations:
2871 for ri, _ in enumerate(RoundingModes):
2872 for fi, _ in enumerate(OrderedSignals[dumper]):
2873 for ti, _ in enumerate(OrderedSignals[dumper]):
Stefan Krah1919b7e2012-03-21 18:25:23 +01002874
Serhiy Storchakabad12572014-12-15 14:03:42 +02002875 prec = random.randrange(1, 100)
2876 emin = random.randrange(-100, 0)
2877 emax = random.randrange(1, 100)
2878 caps = random.randrange(2)
2879 clamp = random.randrange(2)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002880
Serhiy Storchakabad12572014-12-15 14:03:42 +02002881 # One module dumps
2882 sys.modules['decimal'] = dumper
2883 c = dumper.Context(
2884 prec=prec, Emin=emin, Emax=emax,
2885 rounding=RoundingModes[ri],
2886 capitals=caps, clamp=clamp,
2887 flags=OrderedSignals[dumper][:fi],
2888 traps=OrderedSignals[dumper][:ti]
2889 )
2890 s = pickle.dumps(c, proto)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002891
Serhiy Storchakabad12572014-12-15 14:03:42 +02002892 # The other module loads
2893 sys.modules['decimal'] = loader
2894 d = pickle.loads(s)
2895 self.assertIsInstance(d, loader.Context)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002896
Serhiy Storchakabad12572014-12-15 14:03:42 +02002897 self.assertEqual(d.prec, prec)
2898 self.assertEqual(d.Emin, emin)
2899 self.assertEqual(d.Emax, emax)
2900 self.assertEqual(d.rounding, RoundingModes[ri])
2901 self.assertEqual(d.capitals, caps)
2902 self.assertEqual(d.clamp, clamp)
2903 assert_signals(self, d, 'flags', OrderedSignals[loader][:fi])
2904 assert_signals(self, d, 'traps', OrderedSignals[loader][:ti])
Stefan Krah1919b7e2012-03-21 18:25:23 +01002905
Serhiy Storchakabad12572014-12-15 14:03:42 +02002906 sys.modules['decimal'] = savedecimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002907
2908 def test_equality_with_other_types(self):
2909 Decimal = self.decimal.Decimal
2910
2911 self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}])
2912 self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}])
2913
2914 def test_copy(self):
2915 # All copies should be deep
2916 Decimal = self.decimal.Decimal
2917 Context = self.decimal.Context
2918
2919 c = Context()
2920 d = c.copy()
2921 self.assertNotEqual(id(c), id(d))
2922 self.assertNotEqual(id(c.flags), id(d.flags))
2923 self.assertNotEqual(id(c.traps), id(d.traps))
2924 k1 = set(c.flags.keys())
2925 k2 = set(d.flags.keys())
2926 self.assertEqual(k1, k2)
2927 self.assertEqual(c.flags, d.flags)
2928
2929 def test__clamp(self):
2930 # In Python 3.2, the private attribute `_clamp` was made
2931 # public (issue 8540), with the old `_clamp` becoming a
2932 # property wrapping `clamp`. For the duration of Python 3.2
2933 # only, the attribute should be gettable/settable via both
2934 # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be
2935 # removed.
2936 Context = self.decimal.Context
2937 c = Context()
2938 self.assertRaises(AttributeError, getattr, c, '_clamp')
2939
2940 def test_abs(self):
2941 Decimal = self.decimal.Decimal
2942 Context = self.decimal.Context
2943
2944 c = Context()
2945 d = c.abs(Decimal(-1))
2946 self.assertEqual(c.abs(-1), d)
2947 self.assertRaises(TypeError, c.abs, '-1')
2948
2949 def test_add(self):
2950 Decimal = self.decimal.Decimal
2951 Context = self.decimal.Context
2952
2953 c = Context()
2954 d = c.add(Decimal(1), Decimal(1))
2955 self.assertEqual(c.add(1, 1), d)
2956 self.assertEqual(c.add(Decimal(1), 1), d)
2957 self.assertEqual(c.add(1, Decimal(1)), d)
2958 self.assertRaises(TypeError, c.add, '1', 1)
2959 self.assertRaises(TypeError, c.add, 1, '1')
2960
2961 def test_compare(self):
2962 Decimal = self.decimal.Decimal
2963 Context = self.decimal.Context
2964
2965 c = Context()
2966 d = c.compare(Decimal(1), Decimal(1))
2967 self.assertEqual(c.compare(1, 1), d)
2968 self.assertEqual(c.compare(Decimal(1), 1), d)
2969 self.assertEqual(c.compare(1, Decimal(1)), d)
2970 self.assertRaises(TypeError, c.compare, '1', 1)
2971 self.assertRaises(TypeError, c.compare, 1, '1')
2972
2973 def test_compare_signal(self):
2974 Decimal = self.decimal.Decimal
2975 Context = self.decimal.Context
2976
2977 c = Context()
2978 d = c.compare_signal(Decimal(1), Decimal(1))
2979 self.assertEqual(c.compare_signal(1, 1), d)
2980 self.assertEqual(c.compare_signal(Decimal(1), 1), d)
2981 self.assertEqual(c.compare_signal(1, Decimal(1)), d)
2982 self.assertRaises(TypeError, c.compare_signal, '1', 1)
2983 self.assertRaises(TypeError, c.compare_signal, 1, '1')
2984
2985 def test_compare_total(self):
2986 Decimal = self.decimal.Decimal
2987 Context = self.decimal.Context
2988
2989 c = Context()
2990 d = c.compare_total(Decimal(1), Decimal(1))
2991 self.assertEqual(c.compare_total(1, 1), d)
2992 self.assertEqual(c.compare_total(Decimal(1), 1), d)
2993 self.assertEqual(c.compare_total(1, Decimal(1)), d)
2994 self.assertRaises(TypeError, c.compare_total, '1', 1)
2995 self.assertRaises(TypeError, c.compare_total, 1, '1')
2996
2997 def test_compare_total_mag(self):
2998 Decimal = self.decimal.Decimal
2999 Context = self.decimal.Context
3000
3001 c = Context()
3002 d = c.compare_total_mag(Decimal(1), Decimal(1))
3003 self.assertEqual(c.compare_total_mag(1, 1), d)
3004 self.assertEqual(c.compare_total_mag(Decimal(1), 1), d)
3005 self.assertEqual(c.compare_total_mag(1, Decimal(1)), d)
3006 self.assertRaises(TypeError, c.compare_total_mag, '1', 1)
3007 self.assertRaises(TypeError, c.compare_total_mag, 1, '1')
3008
3009 def test_copy_abs(self):
3010 Decimal = self.decimal.Decimal
3011 Context = self.decimal.Context
3012
3013 c = Context()
3014 d = c.copy_abs(Decimal(-1))
3015 self.assertEqual(c.copy_abs(-1), d)
3016 self.assertRaises(TypeError, c.copy_abs, '-1')
3017
3018 def test_copy_decimal(self):
3019 Decimal = self.decimal.Decimal
3020 Context = self.decimal.Context
3021
3022 c = Context()
3023 d = c.copy_decimal(Decimal(-1))
3024 self.assertEqual(c.copy_decimal(-1), d)
3025 self.assertRaises(TypeError, c.copy_decimal, '-1')
3026
3027 def test_copy_negate(self):
3028 Decimal = self.decimal.Decimal
3029 Context = self.decimal.Context
3030
3031 c = Context()
3032 d = c.copy_negate(Decimal(-1))
3033 self.assertEqual(c.copy_negate(-1), d)
3034 self.assertRaises(TypeError, c.copy_negate, '-1')
3035
3036 def test_copy_sign(self):
3037 Decimal = self.decimal.Decimal
3038 Context = self.decimal.Context
3039
3040 c = Context()
3041 d = c.copy_sign(Decimal(1), Decimal(-2))
3042 self.assertEqual(c.copy_sign(1, -2), d)
3043 self.assertEqual(c.copy_sign(Decimal(1), -2), d)
3044 self.assertEqual(c.copy_sign(1, Decimal(-2)), d)
3045 self.assertRaises(TypeError, c.copy_sign, '1', -2)
3046 self.assertRaises(TypeError, c.copy_sign, 1, '-2')
3047
3048 def test_divide(self):
3049 Decimal = self.decimal.Decimal
3050 Context = self.decimal.Context
3051
3052 c = Context()
3053 d = c.divide(Decimal(1), Decimal(2))
3054 self.assertEqual(c.divide(1, 2), d)
3055 self.assertEqual(c.divide(Decimal(1), 2), d)
3056 self.assertEqual(c.divide(1, Decimal(2)), d)
3057 self.assertRaises(TypeError, c.divide, '1', 2)
3058 self.assertRaises(TypeError, c.divide, 1, '2')
3059
3060 def test_divide_int(self):
3061 Decimal = self.decimal.Decimal
3062 Context = self.decimal.Context
3063
3064 c = Context()
3065 d = c.divide_int(Decimal(1), Decimal(2))
3066 self.assertEqual(c.divide_int(1, 2), d)
3067 self.assertEqual(c.divide_int(Decimal(1), 2), d)
3068 self.assertEqual(c.divide_int(1, Decimal(2)), d)
3069 self.assertRaises(TypeError, c.divide_int, '1', 2)
3070 self.assertRaises(TypeError, c.divide_int, 1, '2')
3071
3072 def test_divmod(self):
3073 Decimal = self.decimal.Decimal
3074 Context = self.decimal.Context
3075
3076 c = Context()
3077 d = c.divmod(Decimal(1), Decimal(2))
3078 self.assertEqual(c.divmod(1, 2), d)
3079 self.assertEqual(c.divmod(Decimal(1), 2), d)
3080 self.assertEqual(c.divmod(1, Decimal(2)), d)
3081 self.assertRaises(TypeError, c.divmod, '1', 2)
3082 self.assertRaises(TypeError, c.divmod, 1, '2')
3083
3084 def test_exp(self):
3085 Decimal = self.decimal.Decimal
3086 Context = self.decimal.Context
3087
3088 c = Context()
3089 d = c.exp(Decimal(10))
3090 self.assertEqual(c.exp(10), d)
3091 self.assertRaises(TypeError, c.exp, '10')
3092
3093 def test_fma(self):
3094 Decimal = self.decimal.Decimal
3095 Context = self.decimal.Context
3096
3097 c = Context()
3098 d = c.fma(Decimal(2), Decimal(3), Decimal(4))
3099 self.assertEqual(c.fma(2, 3, 4), d)
3100 self.assertEqual(c.fma(Decimal(2), 3, 4), d)
3101 self.assertEqual(c.fma(2, Decimal(3), 4), d)
3102 self.assertEqual(c.fma(2, 3, Decimal(4)), d)
3103 self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d)
3104 self.assertRaises(TypeError, c.fma, '2', 3, 4)
3105 self.assertRaises(TypeError, c.fma, 2, '3', 4)
3106 self.assertRaises(TypeError, c.fma, 2, 3, '4')
3107
3108 # Issue 12079 for Context.fma ...
3109 self.assertRaises(TypeError, c.fma,
3110 Decimal('Infinity'), Decimal(0), "not a decimal")
3111 self.assertRaises(TypeError, c.fma,
3112 Decimal(1), Decimal('snan'), 1.222)
3113 # ... and for Decimal.fma.
3114 self.assertRaises(TypeError, Decimal('Infinity').fma,
3115 Decimal(0), "not a decimal")
3116 self.assertRaises(TypeError, Decimal(1).fma,
3117 Decimal('snan'), 1.222)
3118
3119 def test_is_finite(self):
3120 Decimal = self.decimal.Decimal
3121 Context = self.decimal.Context
3122
3123 c = Context()
3124 d = c.is_finite(Decimal(10))
3125 self.assertEqual(c.is_finite(10), d)
3126 self.assertRaises(TypeError, c.is_finite, '10')
3127
3128 def test_is_infinite(self):
3129 Decimal = self.decimal.Decimal
3130 Context = self.decimal.Context
3131
3132 c = Context()
3133 d = c.is_infinite(Decimal(10))
3134 self.assertEqual(c.is_infinite(10), d)
3135 self.assertRaises(TypeError, c.is_infinite, '10')
3136
3137 def test_is_nan(self):
3138 Decimal = self.decimal.Decimal
3139 Context = self.decimal.Context
3140
3141 c = Context()
3142 d = c.is_nan(Decimal(10))
3143 self.assertEqual(c.is_nan(10), d)
3144 self.assertRaises(TypeError, c.is_nan, '10')
3145
3146 def test_is_normal(self):
3147 Decimal = self.decimal.Decimal
3148 Context = self.decimal.Context
3149
3150 c = Context()
3151 d = c.is_normal(Decimal(10))
3152 self.assertEqual(c.is_normal(10), d)
3153 self.assertRaises(TypeError, c.is_normal, '10')
3154
3155 def test_is_qnan(self):
3156 Decimal = self.decimal.Decimal
3157 Context = self.decimal.Context
3158
3159 c = Context()
3160 d = c.is_qnan(Decimal(10))
3161 self.assertEqual(c.is_qnan(10), d)
3162 self.assertRaises(TypeError, c.is_qnan, '10')
3163
3164 def test_is_signed(self):
3165 Decimal = self.decimal.Decimal
3166 Context = self.decimal.Context
3167
3168 c = Context()
3169 d = c.is_signed(Decimal(10))
3170 self.assertEqual(c.is_signed(10), d)
3171 self.assertRaises(TypeError, c.is_signed, '10')
3172
3173 def test_is_snan(self):
3174 Decimal = self.decimal.Decimal
3175 Context = self.decimal.Context
3176
3177 c = Context()
3178 d = c.is_snan(Decimal(10))
3179 self.assertEqual(c.is_snan(10), d)
3180 self.assertRaises(TypeError, c.is_snan, '10')
3181
3182 def test_is_subnormal(self):
3183 Decimal = self.decimal.Decimal
3184 Context = self.decimal.Context
3185
3186 c = Context()
3187 d = c.is_subnormal(Decimal(10))
3188 self.assertEqual(c.is_subnormal(10), d)
3189 self.assertRaises(TypeError, c.is_subnormal, '10')
3190
3191 def test_is_zero(self):
3192 Decimal = self.decimal.Decimal
3193 Context = self.decimal.Context
3194
3195 c = Context()
3196 d = c.is_zero(Decimal(10))
3197 self.assertEqual(c.is_zero(10), d)
3198 self.assertRaises(TypeError, c.is_zero, '10')
3199
3200 def test_ln(self):
3201 Decimal = self.decimal.Decimal
3202 Context = self.decimal.Context
3203
3204 c = Context()
3205 d = c.ln(Decimal(10))
3206 self.assertEqual(c.ln(10), d)
3207 self.assertRaises(TypeError, c.ln, '10')
3208
3209 def test_log10(self):
3210 Decimal = self.decimal.Decimal
3211 Context = self.decimal.Context
3212
3213 c = Context()
3214 d = c.log10(Decimal(10))
3215 self.assertEqual(c.log10(10), d)
3216 self.assertRaises(TypeError, c.log10, '10')
3217
3218 def test_logb(self):
3219 Decimal = self.decimal.Decimal
3220 Context = self.decimal.Context
3221
3222 c = Context()
3223 d = c.logb(Decimal(10))
3224 self.assertEqual(c.logb(10), d)
3225 self.assertRaises(TypeError, c.logb, '10')
3226
3227 def test_logical_and(self):
3228 Decimal = self.decimal.Decimal
3229 Context = self.decimal.Context
3230
3231 c = Context()
3232 d = c.logical_and(Decimal(1), Decimal(1))
3233 self.assertEqual(c.logical_and(1, 1), d)
3234 self.assertEqual(c.logical_and(Decimal(1), 1), d)
3235 self.assertEqual(c.logical_and(1, Decimal(1)), d)
3236 self.assertRaises(TypeError, c.logical_and, '1', 1)
3237 self.assertRaises(TypeError, c.logical_and, 1, '1')
3238
3239 def test_logical_invert(self):
3240 Decimal = self.decimal.Decimal
3241 Context = self.decimal.Context
3242
3243 c = Context()
3244 d = c.logical_invert(Decimal(1000))
3245 self.assertEqual(c.logical_invert(1000), d)
3246 self.assertRaises(TypeError, c.logical_invert, '1000')
3247
3248 def test_logical_or(self):
3249 Decimal = self.decimal.Decimal
3250 Context = self.decimal.Context
3251
3252 c = Context()
3253 d = c.logical_or(Decimal(1), Decimal(1))
3254 self.assertEqual(c.logical_or(1, 1), d)
3255 self.assertEqual(c.logical_or(Decimal(1), 1), d)
3256 self.assertEqual(c.logical_or(1, Decimal(1)), d)
3257 self.assertRaises(TypeError, c.logical_or, '1', 1)
3258 self.assertRaises(TypeError, c.logical_or, 1, '1')
3259
3260 def test_logical_xor(self):
3261 Decimal = self.decimal.Decimal
3262 Context = self.decimal.Context
3263
3264 c = Context()
3265 d = c.logical_xor(Decimal(1), Decimal(1))
3266 self.assertEqual(c.logical_xor(1, 1), d)
3267 self.assertEqual(c.logical_xor(Decimal(1), 1), d)
3268 self.assertEqual(c.logical_xor(1, Decimal(1)), d)
3269 self.assertRaises(TypeError, c.logical_xor, '1', 1)
3270 self.assertRaises(TypeError, c.logical_xor, 1, '1')
3271
3272 def test_max(self):
3273 Decimal = self.decimal.Decimal
3274 Context = self.decimal.Context
3275
3276 c = Context()
3277 d = c.max(Decimal(1), Decimal(2))
3278 self.assertEqual(c.max(1, 2), d)
3279 self.assertEqual(c.max(Decimal(1), 2), d)
3280 self.assertEqual(c.max(1, Decimal(2)), d)
3281 self.assertRaises(TypeError, c.max, '1', 2)
3282 self.assertRaises(TypeError, c.max, 1, '2')
3283
3284 def test_max_mag(self):
3285 Decimal = self.decimal.Decimal
3286 Context = self.decimal.Context
3287
3288 c = Context()
3289 d = c.max_mag(Decimal(1), Decimal(2))
3290 self.assertEqual(c.max_mag(1, 2), d)
3291 self.assertEqual(c.max_mag(Decimal(1), 2), d)
3292 self.assertEqual(c.max_mag(1, Decimal(2)), d)
3293 self.assertRaises(TypeError, c.max_mag, '1', 2)
3294 self.assertRaises(TypeError, c.max_mag, 1, '2')
3295
3296 def test_min(self):
3297 Decimal = self.decimal.Decimal
3298 Context = self.decimal.Context
3299
3300 c = Context()
3301 d = c.min(Decimal(1), Decimal(2))
3302 self.assertEqual(c.min(1, 2), d)
3303 self.assertEqual(c.min(Decimal(1), 2), d)
3304 self.assertEqual(c.min(1, Decimal(2)), d)
3305 self.assertRaises(TypeError, c.min, '1', 2)
3306 self.assertRaises(TypeError, c.min, 1, '2')
3307
3308 def test_min_mag(self):
3309 Decimal = self.decimal.Decimal
3310 Context = self.decimal.Context
3311
3312 c = Context()
3313 d = c.min_mag(Decimal(1), Decimal(2))
3314 self.assertEqual(c.min_mag(1, 2), d)
3315 self.assertEqual(c.min_mag(Decimal(1), 2), d)
3316 self.assertEqual(c.min_mag(1, Decimal(2)), d)
3317 self.assertRaises(TypeError, c.min_mag, '1', 2)
3318 self.assertRaises(TypeError, c.min_mag, 1, '2')
3319
3320 def test_minus(self):
3321 Decimal = self.decimal.Decimal
3322 Context = self.decimal.Context
3323
3324 c = Context()
3325 d = c.minus(Decimal(10))
3326 self.assertEqual(c.minus(10), d)
3327 self.assertRaises(TypeError, c.minus, '10')
3328
3329 def test_multiply(self):
3330 Decimal = self.decimal.Decimal
3331 Context = self.decimal.Context
3332
3333 c = Context()
3334 d = c.multiply(Decimal(1), Decimal(2))
3335 self.assertEqual(c.multiply(1, 2), d)
3336 self.assertEqual(c.multiply(Decimal(1), 2), d)
3337 self.assertEqual(c.multiply(1, Decimal(2)), d)
3338 self.assertRaises(TypeError, c.multiply, '1', 2)
3339 self.assertRaises(TypeError, c.multiply, 1, '2')
3340
3341 def test_next_minus(self):
3342 Decimal = self.decimal.Decimal
3343 Context = self.decimal.Context
3344
3345 c = Context()
3346 d = c.next_minus(Decimal(10))
3347 self.assertEqual(c.next_minus(10), d)
3348 self.assertRaises(TypeError, c.next_minus, '10')
3349
3350 def test_next_plus(self):
3351 Decimal = self.decimal.Decimal
3352 Context = self.decimal.Context
3353
3354 c = Context()
3355 d = c.next_plus(Decimal(10))
3356 self.assertEqual(c.next_plus(10), d)
3357 self.assertRaises(TypeError, c.next_plus, '10')
3358
3359 def test_next_toward(self):
3360 Decimal = self.decimal.Decimal
3361 Context = self.decimal.Context
3362
3363 c = Context()
3364 d = c.next_toward(Decimal(1), Decimal(2))
3365 self.assertEqual(c.next_toward(1, 2), d)
3366 self.assertEqual(c.next_toward(Decimal(1), 2), d)
3367 self.assertEqual(c.next_toward(1, Decimal(2)), d)
3368 self.assertRaises(TypeError, c.next_toward, '1', 2)
3369 self.assertRaises(TypeError, c.next_toward, 1, '2')
3370
3371 def test_normalize(self):
3372 Decimal = self.decimal.Decimal
3373 Context = self.decimal.Context
3374
3375 c = Context()
3376 d = c.normalize(Decimal(10))
3377 self.assertEqual(c.normalize(10), d)
3378 self.assertRaises(TypeError, c.normalize, '10')
3379
3380 def test_number_class(self):
3381 Decimal = self.decimal.Decimal
3382 Context = self.decimal.Context
3383
3384 c = Context()
3385 self.assertEqual(c.number_class(123), c.number_class(Decimal(123)))
3386 self.assertEqual(c.number_class(0), c.number_class(Decimal(0)))
3387 self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45)))
3388
3389 def test_plus(self):
3390 Decimal = self.decimal.Decimal
3391 Context = self.decimal.Context
3392
3393 c = Context()
3394 d = c.plus(Decimal(10))
3395 self.assertEqual(c.plus(10), d)
3396 self.assertRaises(TypeError, c.plus, '10')
3397
3398 def test_power(self):
3399 Decimal = self.decimal.Decimal
3400 Context = self.decimal.Context
3401
3402 c = Context()
3403 d = c.power(Decimal(1), Decimal(4))
3404 self.assertEqual(c.power(1, 4), d)
3405 self.assertEqual(c.power(Decimal(1), 4), d)
3406 self.assertEqual(c.power(1, Decimal(4)), d)
3407 self.assertEqual(c.power(Decimal(1), Decimal(4)), d)
3408 self.assertRaises(TypeError, c.power, '1', 4)
3409 self.assertRaises(TypeError, c.power, 1, '4')
3410 self.assertEqual(c.power(modulo=5, b=8, a=2), 1)
3411
3412 def test_quantize(self):
3413 Decimal = self.decimal.Decimal
3414 Context = self.decimal.Context
3415
3416 c = Context()
3417 d = c.quantize(Decimal(1), Decimal(2))
3418 self.assertEqual(c.quantize(1, 2), d)
3419 self.assertEqual(c.quantize(Decimal(1), 2), d)
3420 self.assertEqual(c.quantize(1, Decimal(2)), d)
3421 self.assertRaises(TypeError, c.quantize, '1', 2)
3422 self.assertRaises(TypeError, c.quantize, 1, '2')
3423
3424 def test_remainder(self):
3425 Decimal = self.decimal.Decimal
3426 Context = self.decimal.Context
3427
3428 c = Context()
3429 d = c.remainder(Decimal(1), Decimal(2))
3430 self.assertEqual(c.remainder(1, 2), d)
3431 self.assertEqual(c.remainder(Decimal(1), 2), d)
3432 self.assertEqual(c.remainder(1, Decimal(2)), d)
3433 self.assertRaises(TypeError, c.remainder, '1', 2)
3434 self.assertRaises(TypeError, c.remainder, 1, '2')
3435
3436 def test_remainder_near(self):
3437 Decimal = self.decimal.Decimal
3438 Context = self.decimal.Context
3439
3440 c = Context()
3441 d = c.remainder_near(Decimal(1), Decimal(2))
3442 self.assertEqual(c.remainder_near(1, 2), d)
3443 self.assertEqual(c.remainder_near(Decimal(1), 2), d)
3444 self.assertEqual(c.remainder_near(1, Decimal(2)), d)
3445 self.assertRaises(TypeError, c.remainder_near, '1', 2)
3446 self.assertRaises(TypeError, c.remainder_near, 1, '2')
3447
3448 def test_rotate(self):
3449 Decimal = self.decimal.Decimal
3450 Context = self.decimal.Context
3451
3452 c = Context()
3453 d = c.rotate(Decimal(1), Decimal(2))
3454 self.assertEqual(c.rotate(1, 2), d)
3455 self.assertEqual(c.rotate(Decimal(1), 2), d)
3456 self.assertEqual(c.rotate(1, Decimal(2)), d)
3457 self.assertRaises(TypeError, c.rotate, '1', 2)
3458 self.assertRaises(TypeError, c.rotate, 1, '2')
3459
3460 def test_sqrt(self):
3461 Decimal = self.decimal.Decimal
3462 Context = self.decimal.Context
3463
3464 c = Context()
3465 d = c.sqrt(Decimal(10))
3466 self.assertEqual(c.sqrt(10), d)
3467 self.assertRaises(TypeError, c.sqrt, '10')
3468
3469 def test_same_quantum(self):
3470 Decimal = self.decimal.Decimal
3471 Context = self.decimal.Context
3472
3473 c = Context()
3474 d = c.same_quantum(Decimal(1), Decimal(2))
3475 self.assertEqual(c.same_quantum(1, 2), d)
3476 self.assertEqual(c.same_quantum(Decimal(1), 2), d)
3477 self.assertEqual(c.same_quantum(1, Decimal(2)), d)
3478 self.assertRaises(TypeError, c.same_quantum, '1', 2)
3479 self.assertRaises(TypeError, c.same_quantum, 1, '2')
3480
3481 def test_scaleb(self):
3482 Decimal = self.decimal.Decimal
3483 Context = self.decimal.Context
3484
3485 c = Context()
3486 d = c.scaleb(Decimal(1), Decimal(2))
3487 self.assertEqual(c.scaleb(1, 2), d)
3488 self.assertEqual(c.scaleb(Decimal(1), 2), d)
3489 self.assertEqual(c.scaleb(1, Decimal(2)), d)
3490 self.assertRaises(TypeError, c.scaleb, '1', 2)
3491 self.assertRaises(TypeError, c.scaleb, 1, '2')
3492
3493 def test_shift(self):
3494 Decimal = self.decimal.Decimal
3495 Context = self.decimal.Context
3496
3497 c = Context()
3498 d = c.shift(Decimal(1), Decimal(2))
3499 self.assertEqual(c.shift(1, 2), d)
3500 self.assertEqual(c.shift(Decimal(1), 2), d)
3501 self.assertEqual(c.shift(1, Decimal(2)), d)
3502 self.assertRaises(TypeError, c.shift, '1', 2)
3503 self.assertRaises(TypeError, c.shift, 1, '2')
3504
3505 def test_subtract(self):
3506 Decimal = self.decimal.Decimal
3507 Context = self.decimal.Context
3508
3509 c = Context()
3510 d = c.subtract(Decimal(1), Decimal(2))
3511 self.assertEqual(c.subtract(1, 2), d)
3512 self.assertEqual(c.subtract(Decimal(1), 2), d)
3513 self.assertEqual(c.subtract(1, Decimal(2)), d)
3514 self.assertRaises(TypeError, c.subtract, '1', 2)
3515 self.assertRaises(TypeError, c.subtract, 1, '2')
3516
3517 def test_to_eng_string(self):
3518 Decimal = self.decimal.Decimal
3519 Context = self.decimal.Context
3520
3521 c = Context()
3522 d = c.to_eng_string(Decimal(10))
3523 self.assertEqual(c.to_eng_string(10), d)
3524 self.assertRaises(TypeError, c.to_eng_string, '10')
3525
3526 def test_to_sci_string(self):
3527 Decimal = self.decimal.Decimal
3528 Context = self.decimal.Context
3529
3530 c = Context()
3531 d = c.to_sci_string(Decimal(10))
3532 self.assertEqual(c.to_sci_string(10), d)
3533 self.assertRaises(TypeError, c.to_sci_string, '10')
3534
3535 def test_to_integral_exact(self):
3536 Decimal = self.decimal.Decimal
3537 Context = self.decimal.Context
3538
3539 c = Context()
3540 d = c.to_integral_exact(Decimal(10))
3541 self.assertEqual(c.to_integral_exact(10), d)
3542 self.assertRaises(TypeError, c.to_integral_exact, '10')
3543
3544 def test_to_integral_value(self):
3545 Decimal = self.decimal.Decimal
3546 Context = self.decimal.Context
3547
3548 c = Context()
3549 d = c.to_integral_value(Decimal(10))
3550 self.assertEqual(c.to_integral_value(10), d)
3551 self.assertRaises(TypeError, c.to_integral_value, '10')
3552 self.assertRaises(TypeError, c.to_integral_value, 10, 'x')
3553
3554class CContextAPItests(ContextAPItests):
3555 decimal = C
3556class PyContextAPItests(ContextAPItests):
3557 decimal = P
3558
3559class ContextWithStatement(unittest.TestCase):
3560 # Can't do these as docstrings until Python 2.6
3561 # as doctest can't handle __future__ statements
3562
3563 def test_localcontext(self):
3564 # Use a copy of the current context in the block
3565 getcontext = self.decimal.getcontext
3566 localcontext = self.decimal.localcontext
3567
3568 orig_ctx = getcontext()
3569 with localcontext() as enter_ctx:
3570 set_ctx = getcontext()
3571 final_ctx = getcontext()
3572 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3573 self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context')
3574 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3575
3576 def test_localcontextarg(self):
3577 # Use a copy of the supplied context in the block
3578 Context = self.decimal.Context
3579 getcontext = self.decimal.getcontext
3580 localcontext = self.decimal.localcontext
3581
3582 localcontext = self.decimal.localcontext
3583 orig_ctx = getcontext()
3584 new_ctx = Context(prec=42)
3585 with localcontext(new_ctx) as enter_ctx:
3586 set_ctx = getcontext()
3587 final_ctx = getcontext()
3588 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3589 self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context')
3590 self.assertIsNot(new_ctx, set_ctx, 'did not copy the context')
3591 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3592
3593 def test_nested_with_statements(self):
3594 # Use a copy of the supplied context in the block
3595 Decimal = self.decimal.Decimal
3596 Context = self.decimal.Context
3597 getcontext = self.decimal.getcontext
3598 localcontext = self.decimal.localcontext
3599 Clamped = self.decimal.Clamped
3600 Overflow = self.decimal.Overflow
3601
3602 orig_ctx = getcontext()
3603 orig_ctx.clear_flags()
3604 new_ctx = Context(Emax=384)
3605 with localcontext() as c1:
3606 self.assertEqual(c1.flags, orig_ctx.flags)
3607 self.assertEqual(c1.traps, orig_ctx.traps)
3608 c1.traps[Clamped] = True
3609 c1.Emin = -383
3610 self.assertNotEqual(orig_ctx.Emin, -383)
3611 self.assertRaises(Clamped, c1.create_decimal, '0e-999')
3612 self.assertTrue(c1.flags[Clamped])
3613 with localcontext(new_ctx) as c2:
3614 self.assertEqual(c2.flags, new_ctx.flags)
3615 self.assertEqual(c2.traps, new_ctx.traps)
3616 self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2)
3617 self.assertFalse(c2.flags[Clamped])
3618 self.assertTrue(c2.flags[Overflow])
3619 del c2
3620 self.assertFalse(c1.flags[Overflow])
3621 del c1
3622 self.assertNotEqual(orig_ctx.Emin, -383)
3623 self.assertFalse(orig_ctx.flags[Clamped])
3624 self.assertFalse(orig_ctx.flags[Overflow])
3625 self.assertFalse(new_ctx.flags[Clamped])
3626 self.assertFalse(new_ctx.flags[Overflow])
3627
3628 def test_with_statements_gc1(self):
3629 localcontext = self.decimal.localcontext
3630
3631 with localcontext() as c1:
3632 del c1
3633 with localcontext() as c2:
3634 del c2
3635 with localcontext() as c3:
3636 del c3
3637 with localcontext() as c4:
3638 del c4
3639
3640 def test_with_statements_gc2(self):
3641 localcontext = self.decimal.localcontext
3642
3643 with localcontext() as c1:
3644 with localcontext(c1) as c2:
3645 del c1
3646 with localcontext(c2) as c3:
3647 del c2
3648 with localcontext(c3) as c4:
3649 del c3
3650 del c4
3651
3652 def test_with_statements_gc3(self):
3653 Context = self.decimal.Context
3654 localcontext = self.decimal.localcontext
3655 getcontext = self.decimal.getcontext
3656 setcontext = self.decimal.setcontext
3657
3658 with localcontext() as c1:
3659 del c1
3660 n1 = Context(prec=1)
3661 setcontext(n1)
3662 with localcontext(n1) as c2:
3663 del n1
3664 self.assertEqual(c2.prec, 1)
3665 del c2
3666 n2 = Context(prec=2)
3667 setcontext(n2)
3668 del n2
3669 self.assertEqual(getcontext().prec, 2)
3670 n3 = Context(prec=3)
3671 setcontext(n3)
3672 self.assertEqual(getcontext().prec, 3)
3673 with localcontext(n3) as c3:
3674 del n3
3675 self.assertEqual(c3.prec, 3)
3676 del c3
3677 n4 = Context(prec=4)
3678 setcontext(n4)
3679 del n4
3680 self.assertEqual(getcontext().prec, 4)
3681 with localcontext() as c4:
3682 self.assertEqual(c4.prec, 4)
3683 del c4
3684
3685class CContextWithStatement(ContextWithStatement):
3686 decimal = C
3687class PyContextWithStatement(ContextWithStatement):
3688 decimal = P
3689
3690class ContextFlags(unittest.TestCase):
3691
3692 def test_flags_irrelevant(self):
3693 # check that the result (numeric result + flags raised) of an
3694 # arithmetic operation doesn't depend on the current flags
3695 Decimal = self.decimal.Decimal
3696 Context = self.decimal.Context
3697 Inexact = self.decimal.Inexact
3698 Rounded = self.decimal.Rounded
3699 Underflow = self.decimal.Underflow
3700 Clamped = self.decimal.Clamped
3701 Subnormal = self.decimal.Subnormal
Stefan Krah1919b7e2012-03-21 18:25:23 +01003702
3703 def raise_error(context, flag):
3704 if self.decimal == C:
3705 context.flags[flag] = True
3706 if context.traps[flag]:
3707 raise flag
3708 else:
3709 context._raise_error(flag)
3710
3711 context = Context(prec=9, Emin = -425000000, Emax = 425000000,
3712 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
3713
3714 # operations that raise various flags, in the form (function, arglist)
3715 operations = [
3716 (context._apply, [Decimal("100E-425000010")]),
3717 (context.sqrt, [Decimal(2)]),
3718 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
3719 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
3720 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
3721 ]
3722
3723 # try various flags individually, then a whole lot at once
3724 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
3725 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
3726
3727 for fn, args in operations:
3728 # find answer and flags raised using a clean context
3729 context.clear_flags()
3730 ans = fn(*args)
3731 flags = [k for k, v in context.flags.items() if v]
3732
3733 for extra_flags in flagsets:
3734 # set flags, before calling operation
3735 context.clear_flags()
3736 for flag in extra_flags:
3737 raise_error(context, flag)
3738 new_ans = fn(*args)
3739
3740 # flags that we expect to be set after the operation
3741 expected_flags = list(flags)
3742 for flag in extra_flags:
3743 if flag not in expected_flags:
3744 expected_flags.append(flag)
3745 expected_flags.sort(key=id)
3746
3747 # flags we actually got
3748 new_flags = [k for k,v in context.flags.items() if v]
3749 new_flags.sort(key=id)
3750
3751 self.assertEqual(ans, new_ans,
3752 "operation produces different answers depending on flags set: " +
3753 "expected %s, got %s." % (ans, new_ans))
3754 self.assertEqual(new_flags, expected_flags,
3755 "operation raises different flags depending on flags set: " +
3756 "expected %s, got %s" % (expected_flags, new_flags))
3757
3758 def test_flag_comparisons(self):
3759 Context = self.decimal.Context
3760 Inexact = self.decimal.Inexact
3761 Rounded = self.decimal.Rounded
3762
3763 c = Context()
3764
3765 # Valid SignalDict
3766 self.assertNotEqual(c.flags, c.traps)
3767 self.assertNotEqual(c.traps, c.flags)
3768
3769 c.flags = c.traps
3770 self.assertEqual(c.flags, c.traps)
3771 self.assertEqual(c.traps, c.flags)
3772
3773 c.flags[Rounded] = True
3774 c.traps = c.flags
3775 self.assertEqual(c.flags, c.traps)
3776 self.assertEqual(c.traps, c.flags)
3777
3778 d = {}
3779 d.update(c.flags)
3780 self.assertEqual(d, c.flags)
3781 self.assertEqual(c.flags, d)
3782
3783 d[Inexact] = True
3784 self.assertNotEqual(d, c.flags)
3785 self.assertNotEqual(c.flags, d)
3786
3787 # Invalid SignalDict
3788 d = {Inexact:False}
3789 self.assertNotEqual(d, c.flags)
3790 self.assertNotEqual(c.flags, d)
3791
3792 d = ["xyz"]
3793 self.assertNotEqual(d, c.flags)
3794 self.assertNotEqual(c.flags, d)
3795
3796 @requires_IEEE_754
3797 def test_float_operation(self):
3798 Decimal = self.decimal.Decimal
3799 FloatOperation = self.decimal.FloatOperation
3800 localcontext = self.decimal.localcontext
3801
3802 with localcontext() as c:
3803 ##### trap is off by default
3804 self.assertFalse(c.traps[FloatOperation])
3805
3806 # implicit conversion sets the flag
3807 c.clear_flags()
3808 self.assertEqual(Decimal(7.5), 7.5)
3809 self.assertTrue(c.flags[FloatOperation])
3810
3811 c.clear_flags()
3812 self.assertEqual(c.create_decimal(7.5), 7.5)
3813 self.assertTrue(c.flags[FloatOperation])
3814
3815 # explicit conversion does not set the flag
3816 c.clear_flags()
3817 x = Decimal.from_float(7.5)
3818 self.assertFalse(c.flags[FloatOperation])
3819 # comparison sets the flag
3820 self.assertEqual(x, 7.5)
3821 self.assertTrue(c.flags[FloatOperation])
3822
3823 c.clear_flags()
3824 x = c.create_decimal_from_float(7.5)
3825 self.assertFalse(c.flags[FloatOperation])
3826 self.assertEqual(x, 7.5)
3827 self.assertTrue(c.flags[FloatOperation])
3828
3829 ##### set the trap
3830 c.traps[FloatOperation] = True
3831
3832 # implicit conversion raises
3833 c.clear_flags()
3834 self.assertRaises(FloatOperation, Decimal, 7.5)
3835 self.assertTrue(c.flags[FloatOperation])
3836
3837 c.clear_flags()
3838 self.assertRaises(FloatOperation, c.create_decimal, 7.5)
3839 self.assertTrue(c.flags[FloatOperation])
3840
3841 # explicit conversion is silent
3842 c.clear_flags()
3843 x = Decimal.from_float(7.5)
3844 self.assertFalse(c.flags[FloatOperation])
3845
3846 c.clear_flags()
3847 x = c.create_decimal_from_float(7.5)
3848 self.assertFalse(c.flags[FloatOperation])
3849
3850 def test_float_comparison(self):
3851 Decimal = self.decimal.Decimal
3852 Context = self.decimal.Context
3853 FloatOperation = self.decimal.FloatOperation
3854 localcontext = self.decimal.localcontext
3855
3856 def assert_attr(a, b, attr, context, signal=None):
3857 context.clear_flags()
3858 f = getattr(a, attr)
3859 if signal == FloatOperation:
3860 self.assertRaises(signal, f, b)
3861 else:
3862 self.assertIs(f(b), True)
3863 self.assertTrue(context.flags[FloatOperation])
3864
3865 small_d = Decimal('0.25')
3866 big_d = Decimal('3.0')
3867 small_f = 0.25
3868 big_f = 3.0
3869
3870 zero_d = Decimal('0.0')
3871 neg_zero_d = Decimal('-0.0')
3872 zero_f = 0.0
3873 neg_zero_f = -0.0
3874
3875 inf_d = Decimal('Infinity')
3876 neg_inf_d = Decimal('-Infinity')
3877 inf_f = float('inf')
3878 neg_inf_f = float('-inf')
3879
3880 def doit(c, signal=None):
3881 # Order
3882 for attr in '__lt__', '__le__':
3883 assert_attr(small_d, big_f, attr, c, signal)
3884
3885 for attr in '__gt__', '__ge__':
3886 assert_attr(big_d, small_f, attr, c, signal)
3887
3888 # Equality
3889 assert_attr(small_d, small_f, '__eq__', c, None)
3890
3891 assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None)
3892 assert_attr(neg_zero_d, zero_f, '__eq__', c, None)
3893
3894 assert_attr(zero_d, neg_zero_f, '__eq__', c, None)
3895 assert_attr(zero_d, zero_f, '__eq__', c, None)
3896
3897 assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None)
3898 assert_attr(inf_d, inf_f, '__eq__', c, None)
3899
3900 # Inequality
3901 assert_attr(small_d, big_f, '__ne__', c, None)
3902
3903 assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None)
3904
3905 assert_attr(neg_inf_d, inf_f, '__ne__', c, None)
3906 assert_attr(inf_d, neg_inf_f, '__ne__', c, None)
3907
3908 assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None)
3909
3910 def test_containers(c, signal=None):
3911 c.clear_flags()
3912 s = set([100.0, Decimal('100.0')])
3913 self.assertEqual(len(s), 1)
3914 self.assertTrue(c.flags[FloatOperation])
3915
3916 c.clear_flags()
3917 if signal:
3918 self.assertRaises(signal, sorted, [1.0, Decimal('10.0')])
3919 else:
3920 s = sorted([10.0, Decimal('10.0')])
3921 self.assertTrue(c.flags[FloatOperation])
3922
3923 c.clear_flags()
3924 b = 10.0 in [Decimal('10.0'), 1.0]
3925 self.assertTrue(c.flags[FloatOperation])
3926
3927 c.clear_flags()
3928 b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'}
3929 self.assertTrue(c.flags[FloatOperation])
3930
3931 nc = Context()
3932 with localcontext(nc) as c:
3933 self.assertFalse(c.traps[FloatOperation])
3934 doit(c, signal=None)
3935 test_containers(c, signal=None)
3936
3937 c.traps[FloatOperation] = True
3938 doit(c, signal=FloatOperation)
3939 test_containers(c, signal=FloatOperation)
3940
3941 def test_float_operation_default(self):
3942 Decimal = self.decimal.Decimal
3943 Context = self.decimal.Context
3944 Inexact = self.decimal.Inexact
3945 FloatOperation= self.decimal.FloatOperation
3946
3947 context = Context()
3948 self.assertFalse(context.flags[FloatOperation])
3949 self.assertFalse(context.traps[FloatOperation])
3950
3951 context.clear_traps()
3952 context.traps[Inexact] = True
3953 context.traps[FloatOperation] = True
3954 self.assertTrue(context.traps[FloatOperation])
3955 self.assertTrue(context.traps[Inexact])
3956
3957class CContextFlags(ContextFlags):
3958 decimal = C
3959class PyContextFlags(ContextFlags):
3960 decimal = P
3961
3962class SpecialContexts(unittest.TestCase):
3963 """Test the context templates."""
3964
3965 def test_context_templates(self):
3966 BasicContext = self.decimal.BasicContext
3967 ExtendedContext = self.decimal.ExtendedContext
3968 getcontext = self.decimal.getcontext
3969 setcontext = self.decimal.setcontext
3970 InvalidOperation = self.decimal.InvalidOperation
3971 DivisionByZero = self.decimal.DivisionByZero
3972 Overflow = self.decimal.Overflow
3973 Underflow = self.decimal.Underflow
3974 Clamped = self.decimal.Clamped
3975
3976 assert_signals(self, BasicContext, 'traps',
3977 [InvalidOperation, DivisionByZero, Overflow, Underflow, Clamped]
3978 )
3979
3980 savecontext = getcontext().copy()
3981 basic_context_prec = BasicContext.prec
3982 extended_context_prec = ExtendedContext.prec
3983
3984 ex = None
3985 try:
3986 BasicContext.prec = ExtendedContext.prec = 441
3987 for template in BasicContext, ExtendedContext:
3988 setcontext(template)
3989 c = getcontext()
3990 self.assertIsNot(c, template)
3991 self.assertEqual(c.prec, 441)
3992 except Exception as e:
3993 ex = e.__class__
3994 finally:
3995 BasicContext.prec = basic_context_prec
3996 ExtendedContext.prec = extended_context_prec
3997 setcontext(savecontext)
3998 if ex:
3999 raise ex
4000
4001 def test_default_context(self):
4002 DefaultContext = self.decimal.DefaultContext
4003 BasicContext = self.decimal.BasicContext
4004 ExtendedContext = self.decimal.ExtendedContext
4005 getcontext = self.decimal.getcontext
4006 setcontext = self.decimal.setcontext
4007 InvalidOperation = self.decimal.InvalidOperation
4008 DivisionByZero = self.decimal.DivisionByZero
4009 Overflow = self.decimal.Overflow
4010
4011 self.assertEqual(BasicContext.prec, 9)
4012 self.assertEqual(ExtendedContext.prec, 9)
4013
4014 assert_signals(self, DefaultContext, 'traps',
4015 [InvalidOperation, DivisionByZero, Overflow]
4016 )
4017
4018 savecontext = getcontext().copy()
4019 default_context_prec = DefaultContext.prec
4020
4021 ex = None
4022 try:
4023 c = getcontext()
4024 saveprec = c.prec
4025
4026 DefaultContext.prec = 961
4027 c = getcontext()
4028 self.assertEqual(c.prec, saveprec)
4029
4030 setcontext(DefaultContext)
4031 c = getcontext()
4032 self.assertIsNot(c, DefaultContext)
4033 self.assertEqual(c.prec, 961)
4034 except Exception as e:
4035 ex = e.__class__
4036 finally:
4037 DefaultContext.prec = default_context_prec
4038 setcontext(savecontext)
4039 if ex:
4040 raise ex
4041
4042class CSpecialContexts(SpecialContexts):
4043 decimal = C
4044class PySpecialContexts(SpecialContexts):
4045 decimal = P
4046
4047class ContextInputValidation(unittest.TestCase):
4048
4049 def test_invalid_context(self):
4050 Context = self.decimal.Context
4051 DefaultContext = self.decimal.DefaultContext
4052
4053 c = DefaultContext.copy()
4054
4055 # prec, Emax
4056 for attr in ['prec', 'Emax']:
4057 setattr(c, attr, 999999)
4058 self.assertEqual(getattr(c, attr), 999999)
4059 self.assertRaises(ValueError, setattr, c, attr, -1)
4060 self.assertRaises(TypeError, setattr, c, attr, 'xyz')
4061
4062 # Emin
4063 setattr(c, 'Emin', -999999)
4064 self.assertEqual(getattr(c, 'Emin'), -999999)
4065 self.assertRaises(ValueError, setattr, c, 'Emin', 1)
4066 self.assertRaises(TypeError, setattr, c, 'Emin', (1,2,3))
4067
Stefan Krah1919b7e2012-03-21 18:25:23 +01004068 self.assertRaises(TypeError, setattr, c, 'rounding', -1)
4069 self.assertRaises(TypeError, setattr, c, 'rounding', 9)
4070 self.assertRaises(TypeError, setattr, c, 'rounding', 1.0)
4071 self.assertRaises(TypeError, setattr, c, 'rounding', 'xyz')
4072
4073 # capitals, clamp
4074 for attr in ['capitals', 'clamp']:
4075 self.assertRaises(ValueError, setattr, c, attr, -1)
4076 self.assertRaises(ValueError, setattr, c, attr, 2)
4077 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
4078
4079 # Invalid attribute
4080 self.assertRaises(AttributeError, setattr, c, 'emax', 100)
4081
4082 # Invalid signal dict
4083 self.assertRaises(TypeError, setattr, c, 'flags', [])
4084 self.assertRaises(KeyError, setattr, c, 'flags', {})
4085 self.assertRaises(KeyError, setattr, c, 'traps',
4086 {'InvalidOperation':0})
4087
4088 # Attributes cannot be deleted
4089 for attr in ['prec', 'Emax', 'Emin', 'rounding', 'capitals', 'clamp',
4090 'flags', 'traps']:
4091 self.assertRaises(AttributeError, c.__delattr__, attr)
4092
4093 # Invalid attributes
4094 self.assertRaises(TypeError, getattr, c, 9)
4095 self.assertRaises(TypeError, setattr, c, 9)
4096
4097 # Invalid values in constructor
4098 self.assertRaises(TypeError, Context, rounding=999999)
4099 self.assertRaises(TypeError, Context, rounding='xyz')
4100 self.assertRaises(ValueError, Context, clamp=2)
4101 self.assertRaises(ValueError, Context, capitals=-1)
4102 self.assertRaises(KeyError, Context, flags=["P"])
4103 self.assertRaises(KeyError, Context, traps=["Q"])
4104
4105 # Type error in conversion
4106 self.assertRaises(TypeError, Context, flags=(0,1))
4107 self.assertRaises(TypeError, Context, traps=(1,0))
4108
4109class CContextInputValidation(ContextInputValidation):
4110 decimal = C
4111class PyContextInputValidation(ContextInputValidation):
4112 decimal = P
4113
4114class ContextSubclassing(unittest.TestCase):
4115
4116 def test_context_subclassing(self):
4117 decimal = self.decimal
4118 Decimal = decimal.Decimal
4119 Context = decimal.Context
Stefan Krah1919b7e2012-03-21 18:25:23 +01004120 Clamped = decimal.Clamped
4121 DivisionByZero = decimal.DivisionByZero
4122 Inexact = decimal.Inexact
4123 Overflow = decimal.Overflow
4124 Rounded = decimal.Rounded
4125 Subnormal = decimal.Subnormal
4126 Underflow = decimal.Underflow
4127 InvalidOperation = decimal.InvalidOperation
4128
4129 class MyContext(Context):
4130 def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
4131 capitals=None, clamp=None, flags=None,
4132 traps=None):
4133 Context.__init__(self)
4134 if prec is not None:
4135 self.prec = prec
4136 if rounding is not None:
4137 self.rounding = rounding
4138 if Emin is not None:
4139 self.Emin = Emin
4140 if Emax is not None:
4141 self.Emax = Emax
4142 if capitals is not None:
4143 self.capitals = capitals
4144 if clamp is not None:
4145 self.clamp = clamp
4146 if flags is not None:
4147 if isinstance(flags, list):
4148 flags = {v:(v in flags) for v in OrderedSignals[decimal] + flags}
4149 self.flags = flags
4150 if traps is not None:
4151 if isinstance(traps, list):
4152 traps = {v:(v in traps) for v in OrderedSignals[decimal] + traps}
4153 self.traps = traps
4154
4155 c = Context()
4156 d = MyContext()
4157 for attr in ('prec', 'rounding', 'Emin', 'Emax', 'capitals', 'clamp',
4158 'flags', 'traps'):
4159 self.assertEqual(getattr(c, attr), getattr(d, attr))
4160
4161 # prec
4162 self.assertRaises(ValueError, MyContext, **{'prec':-1})
4163 c = MyContext(prec=1)
4164 self.assertEqual(c.prec, 1)
4165 self.assertRaises(InvalidOperation, c.quantize, Decimal('9e2'), 0)
4166
4167 # rounding
4168 self.assertRaises(TypeError, MyContext, **{'rounding':'XYZ'})
4169 c = MyContext(rounding=ROUND_DOWN, prec=1)
4170 self.assertEqual(c.rounding, ROUND_DOWN)
4171 self.assertEqual(c.plus(Decimal('9.9')), 9)
4172
4173 # Emin
4174 self.assertRaises(ValueError, MyContext, **{'Emin':5})
4175 c = MyContext(Emin=-1, prec=1)
4176 self.assertEqual(c.Emin, -1)
4177 x = c.add(Decimal('1e-99'), Decimal('2.234e-2000'))
4178 self.assertEqual(x, Decimal('0.0'))
4179 for signal in (Inexact, Underflow, Subnormal, Rounded, Clamped):
4180 self.assertTrue(c.flags[signal])
4181
4182 # Emax
4183 self.assertRaises(ValueError, MyContext, **{'Emax':-1})
4184 c = MyContext(Emax=1, prec=1)
4185 self.assertEqual(c.Emax, 1)
4186 self.assertRaises(Overflow, c.add, Decimal('1e99'), Decimal('2.234e2000'))
4187 if self.decimal == C:
4188 for signal in (Inexact, Overflow, Rounded):
4189 self.assertTrue(c.flags[signal])
4190
4191 # capitals
4192 self.assertRaises(ValueError, MyContext, **{'capitals':-1})
4193 c = MyContext(capitals=0)
4194 self.assertEqual(c.capitals, 0)
4195 x = c.create_decimal('1E222')
4196 self.assertEqual(c.to_sci_string(x), '1e+222')
4197
4198 # clamp
4199 self.assertRaises(ValueError, MyContext, **{'clamp':2})
4200 c = MyContext(clamp=1, Emax=99)
4201 self.assertEqual(c.clamp, 1)
4202 x = c.plus(Decimal('1e99'))
4203 self.assertEqual(str(x), '1.000000000000000000000000000E+99')
4204
4205 # flags
4206 self.assertRaises(TypeError, MyContext, **{'flags':'XYZ'})
4207 c = MyContext(flags=[Rounded, DivisionByZero])
4208 for signal in (Rounded, DivisionByZero):
4209 self.assertTrue(c.flags[signal])
4210 c.clear_flags()
4211 for signal in OrderedSignals[decimal]:
4212 self.assertFalse(c.flags[signal])
4213
4214 # traps
4215 self.assertRaises(TypeError, MyContext, **{'traps':'XYZ'})
4216 c = MyContext(traps=[Rounded, DivisionByZero])
4217 for signal in (Rounded, DivisionByZero):
4218 self.assertTrue(c.traps[signal])
4219 c.clear_traps()
4220 for signal in OrderedSignals[decimal]:
4221 self.assertFalse(c.traps[signal])
4222
4223class CContextSubclassing(ContextSubclassing):
4224 decimal = C
4225class PyContextSubclassing(ContextSubclassing):
4226 decimal = P
4227
4228@skip_if_extra_functionality
4229class CheckAttributes(unittest.TestCase):
4230
4231 def test_module_attributes(self):
4232
4233 # Architecture dependent context limits
4234 self.assertEqual(C.MAX_PREC, P.MAX_PREC)
4235 self.assertEqual(C.MAX_EMAX, P.MAX_EMAX)
4236 self.assertEqual(C.MIN_EMIN, P.MIN_EMIN)
4237 self.assertEqual(C.MIN_ETINY, P.MIN_ETINY)
4238
4239 self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False)
4240 self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False)
4241
4242 self.assertEqual(C.__version__, P.__version__)
4243
Stefan Krahb578f8a2014-09-10 17:58:15 +02004244 self.assertEqual(dir(C), dir(P))
Stefan Krah1919b7e2012-03-21 18:25:23 +01004245
4246 def test_context_attributes(self):
4247
4248 x = [s for s in dir(C.Context()) if '__' in s or not s.startswith('_')]
4249 y = [s for s in dir(P.Context()) if '__' in s or not s.startswith('_')]
4250 self.assertEqual(set(x) - set(y), set())
4251
4252 def test_decimal_attributes(self):
4253
4254 x = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
4255 y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
4256 self.assertEqual(set(x) - set(y), set())
4257
4258class Coverage(unittest.TestCase):
4259
4260 def test_adjusted(self):
4261 Decimal = self.decimal.Decimal
4262
4263 self.assertEqual(Decimal('1234e9999').adjusted(), 10002)
4264 # XXX raise?
4265 self.assertEqual(Decimal('nan').adjusted(), 0)
4266 self.assertEqual(Decimal('inf').adjusted(), 0)
4267
4268 def test_canonical(self):
4269 Decimal = self.decimal.Decimal
4270 getcontext = self.decimal.getcontext
4271
4272 x = Decimal(9).canonical()
4273 self.assertEqual(x, 9)
4274
4275 c = getcontext()
4276 x = c.canonical(Decimal(9))
4277 self.assertEqual(x, 9)
4278
4279 def test_context_repr(self):
4280 c = self.decimal.DefaultContext.copy()
4281
4282 c.prec = 425000000
4283 c.Emax = 425000000
4284 c.Emin = -425000000
Stefan Krah59a4a932013-01-16 12:58:59 +01004285 c.rounding = ROUND_HALF_DOWN
Stefan Krah1919b7e2012-03-21 18:25:23 +01004286 c.capitals = 0
4287 c.clamp = 1
4288 for sig in OrderedSignals[self.decimal]:
4289 c.flags[sig] = False
4290 c.traps[sig] = False
4291
4292 s = c.__repr__()
4293 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
4294 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
4295 "flags=[], traps=[])"
4296 self.assertEqual(s, t)
4297
4298 def test_implicit_context(self):
4299 Decimal = self.decimal.Decimal
4300 localcontext = self.decimal.localcontext
4301
4302 with localcontext() as c:
4303 c.prec = 1
4304 c.Emax = 1
4305 c.Emin = -1
4306
4307 # abs
4308 self.assertEqual(abs(Decimal("-10")), 10)
4309 # add
4310 self.assertEqual(Decimal("7") + 1, 8)
4311 # divide
4312 self.assertEqual(Decimal("10") / 5, 2)
4313 # divide_int
4314 self.assertEqual(Decimal("10") // 7, 1)
4315 # fma
4316 self.assertEqual(Decimal("1.2").fma(Decimal("0.01"), 1), 1)
4317 self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True)
4318 # three arg power
4319 self.assertEqual(pow(Decimal(10), 2, 7), 2)
4320 # exp
4321 self.assertEqual(Decimal("1.01").exp(), 3)
4322 # is_normal
4323 self.assertIs(Decimal("0.01").is_normal(), False)
4324 # is_subnormal
4325 self.assertIs(Decimal("0.01").is_subnormal(), True)
4326 # ln
4327 self.assertEqual(Decimal("20").ln(), 3)
4328 # log10
4329 self.assertEqual(Decimal("20").log10(), 1)
4330 # logb
4331 self.assertEqual(Decimal("580").logb(), 2)
4332 # logical_invert
4333 self.assertEqual(Decimal("10").logical_invert(), 1)
4334 # minus
4335 self.assertEqual(-Decimal("-10"), 10)
4336 # multiply
4337 self.assertEqual(Decimal("2") * 4, 8)
4338 # next_minus
4339 self.assertEqual(Decimal("10").next_minus(), 9)
4340 # next_plus
4341 self.assertEqual(Decimal("10").next_plus(), Decimal('2E+1'))
4342 # normalize
4343 self.assertEqual(Decimal("-10").normalize(), Decimal('-1E+1'))
4344 # number_class
4345 self.assertEqual(Decimal("10").number_class(), '+Normal')
4346 # plus
4347 self.assertEqual(+Decimal("-1"), -1)
4348 # remainder
4349 self.assertEqual(Decimal("10") % 7, 3)
4350 # subtract
4351 self.assertEqual(Decimal("10") - 7, 3)
4352 # to_integral_exact
4353 self.assertEqual(Decimal("1.12345").to_integral_exact(), 1)
4354
4355 # Boolean functions
4356 self.assertTrue(Decimal("1").is_canonical())
4357 self.assertTrue(Decimal("1").is_finite())
4358 self.assertTrue(Decimal("1").is_finite())
4359 self.assertTrue(Decimal("snan").is_snan())
4360 self.assertTrue(Decimal("-1").is_signed())
4361 self.assertTrue(Decimal("0").is_zero())
4362 self.assertTrue(Decimal("0").is_zero())
4363
4364 # Copy
4365 with localcontext() as c:
4366 c.prec = 10000
4367 x = 1228 ** 1523
4368 y = -Decimal(x)
4369
4370 z = y.copy_abs()
4371 self.assertEqual(z, x)
4372
4373 z = y.copy_negate()
4374 self.assertEqual(z, x)
4375
4376 z = y.copy_sign(Decimal(1))
4377 self.assertEqual(z, x)
4378
4379 def test_divmod(self):
4380 Decimal = self.decimal.Decimal
4381 localcontext = self.decimal.localcontext
4382 InvalidOperation = self.decimal.InvalidOperation
4383 DivisionByZero = self.decimal.DivisionByZero
4384
4385 with localcontext() as c:
4386 q, r = divmod(Decimal("10912837129"), 1001)
4387 self.assertEqual(q, Decimal('10901935'))
4388 self.assertEqual(r, Decimal('194'))
4389
4390 q, r = divmod(Decimal("NaN"), 7)
4391 self.assertTrue(q.is_nan() and r.is_nan())
4392
4393 c.traps[InvalidOperation] = False
4394 q, r = divmod(Decimal("NaN"), 7)
4395 self.assertTrue(q.is_nan() and r.is_nan())
4396
4397 c.traps[InvalidOperation] = False
4398 c.clear_flags()
4399 q, r = divmod(Decimal("inf"), Decimal("inf"))
4400 self.assertTrue(q.is_nan() and r.is_nan())
4401 self.assertTrue(c.flags[InvalidOperation])
4402
4403 c.clear_flags()
4404 q, r = divmod(Decimal("inf"), 101)
4405 self.assertTrue(q.is_infinite() and r.is_nan())
4406 self.assertTrue(c.flags[InvalidOperation])
4407
4408 c.clear_flags()
4409 q, r = divmod(Decimal(0), 0)
4410 self.assertTrue(q.is_nan() and r.is_nan())
4411 self.assertTrue(c.flags[InvalidOperation])
4412
4413 c.traps[DivisionByZero] = False
4414 c.clear_flags()
4415 q, r = divmod(Decimal(11), 0)
4416 self.assertTrue(q.is_infinite() and r.is_nan())
4417 self.assertTrue(c.flags[InvalidOperation] and
4418 c.flags[DivisionByZero])
4419
4420 def test_power(self):
4421 Decimal = self.decimal.Decimal
4422 localcontext = self.decimal.localcontext
4423 Overflow = self.decimal.Overflow
4424 Rounded = self.decimal.Rounded
4425
4426 with localcontext() as c:
4427 c.prec = 3
4428 c.clear_flags()
4429 self.assertEqual(Decimal("1.0") ** 100, Decimal('1.00'))
4430 self.assertTrue(c.flags[Rounded])
4431
4432 c.prec = 1
4433 c.Emax = 1
4434 c.Emin = -1
4435 c.clear_flags()
4436 c.traps[Overflow] = False
4437 self.assertEqual(Decimal(10000) ** Decimal("0.5"), Decimal('inf'))
4438 self.assertTrue(c.flags[Overflow])
4439
4440 def test_quantize(self):
4441 Decimal = self.decimal.Decimal
4442 localcontext = self.decimal.localcontext
4443 InvalidOperation = self.decimal.InvalidOperation
4444
4445 with localcontext() as c:
4446 c.prec = 1
4447 c.Emax = 1
4448 c.Emin = -1
4449 c.traps[InvalidOperation] = False
4450 x = Decimal(99).quantize(Decimal("1e1"))
4451 self.assertTrue(x.is_nan())
4452
4453 def test_radix(self):
4454 Decimal = self.decimal.Decimal
4455 getcontext = self.decimal.getcontext
4456
4457 c = getcontext()
4458 self.assertEqual(Decimal("1").radix(), 10)
4459 self.assertEqual(c.radix(), 10)
4460
4461 def test_rop(self):
4462 Decimal = self.decimal.Decimal
4463
4464 for attr in ('__radd__', '__rsub__', '__rmul__', '__rtruediv__',
4465 '__rdivmod__', '__rmod__', '__rfloordiv__', '__rpow__'):
4466 self.assertIs(getattr(Decimal("1"), attr)("xyz"), NotImplemented)
4467
4468 def test_round(self):
4469 # Python3 behavior: round() returns Decimal
4470 Decimal = self.decimal.Decimal
Stefan Krahe95dfc52018-06-03 18:40:00 +02004471 localcontext = self.decimal.localcontext
Stefan Krah1919b7e2012-03-21 18:25:23 +01004472
Stefan Krahe95dfc52018-06-03 18:40:00 +02004473 with localcontext() as c:
4474 c.prec = 28
Stefan Krah1919b7e2012-03-21 18:25:23 +01004475
Stefan Krahe95dfc52018-06-03 18:40:00 +02004476 self.assertEqual(str(Decimal("9.99").__round__()), "10")
4477 self.assertEqual(str(Decimal("9.99e-5").__round__()), "0")
4478 self.assertEqual(str(Decimal("1.23456789").__round__(5)), "1.23457")
4479 self.assertEqual(str(Decimal("1.2345").__round__(10)), "1.2345000000")
4480 self.assertEqual(str(Decimal("1.2345").__round__(-10)), "0E+10")
Stefan Krah1919b7e2012-03-21 18:25:23 +01004481
Stefan Krahe95dfc52018-06-03 18:40:00 +02004482 self.assertRaises(TypeError, Decimal("1.23").__round__, "5")
4483 self.assertRaises(TypeError, Decimal("1.23").__round__, 5, 8)
Stefan Krah1919b7e2012-03-21 18:25:23 +01004484
4485 def test_create_decimal(self):
4486 c = self.decimal.Context()
4487 self.assertRaises(ValueError, c.create_decimal, ["%"])
4488
4489 def test_int(self):
4490 Decimal = self.decimal.Decimal
4491 localcontext = self.decimal.localcontext
4492
4493 with localcontext() as c:
4494 c.prec = 9999
4495 x = Decimal(1221**1271) / 10**3923
4496 self.assertEqual(int(x), 1)
4497 self.assertEqual(x.to_integral(), 2)
4498
4499 def test_copy(self):
4500 Context = self.decimal.Context
4501
4502 c = Context()
4503 c.prec = 10000
4504 x = -(1172 ** 1712)
4505
4506 y = c.copy_abs(x)
4507 self.assertEqual(y, -x)
4508
4509 y = c.copy_negate(x)
4510 self.assertEqual(y, -x)
4511
4512 y = c.copy_sign(x, 1)
4513 self.assertEqual(y, -x)
4514
4515class CCoverage(Coverage):
4516 decimal = C
4517class PyCoverage(Coverage):
4518 decimal = P
4519
4520class PyFunctionality(unittest.TestCase):
4521 """Extra functionality in decimal.py"""
4522
Stefan Krah1919b7e2012-03-21 18:25:23 +01004523 def test_py_alternate_formatting(self):
4524 # triples giving a format, a Decimal, and the expected result
4525 Decimal = P.Decimal
4526 localcontext = P.localcontext
4527
4528 test_values = [
4529 # Issue 7094: Alternate formatting (specified by #)
4530 ('.0e', '1.0', '1e+0'),
4531 ('#.0e', '1.0', '1.e+0'),
4532 ('.0f', '1.0', '1'),
4533 ('#.0f', '1.0', '1.'),
4534 ('g', '1.1', '1.1'),
4535 ('#g', '1.1', '1.1'),
4536 ('.0g', '1', '1'),
4537 ('#.0g', '1', '1.'),
4538 ('.0%', '1.0', '100%'),
4539 ('#.0%', '1.0', '100.%'),
4540 ]
4541 for fmt, d, result in test_values:
4542 self.assertEqual(format(Decimal(d), fmt), result)
4543
4544class PyWhitebox(unittest.TestCase):
4545 """White box testing for decimal.py"""
4546
4547 def test_py_exact_power(self):
4548 # Rarely exercised lines in _power_exact.
4549 Decimal = P.Decimal
4550 localcontext = P.localcontext
4551
4552 with localcontext() as c:
4553 c.prec = 8
4554 x = Decimal(2**16) ** Decimal("-0.5")
4555 self.assertEqual(x, Decimal('0.00390625'))
4556
4557 x = Decimal(2**16) ** Decimal("-0.6")
4558 self.assertEqual(x, Decimal('0.0012885819'))
4559
4560 x = Decimal("256e7") ** Decimal("-0.5")
4561
4562 x = Decimal(152587890625) ** Decimal('-0.0625')
4563 self.assertEqual(x, Decimal("0.2"))
4564
4565 x = Decimal("152587890625e7") ** Decimal('-0.0625')
4566
4567 x = Decimal(5**2659) ** Decimal('-0.0625')
4568
4569 c.prec = 1
4570 x = Decimal("152587890625") ** Decimal('-0.5')
4571 c.prec = 201
4572 x = Decimal(2**578) ** Decimal("-0.5")
4573
4574 def test_py_immutability_operations(self):
Terry Jan Reedy0f847642013-03-11 18:34:00 -04004575 # Do operations and check that it didn't change internal objects.
Stefan Krah1919b7e2012-03-21 18:25:23 +01004576 Decimal = P.Decimal
4577 DefaultContext = P.DefaultContext
4578 setcontext = P.setcontext
4579
4580 c = DefaultContext.copy()
4581 c.traps = dict((s, 0) for s in OrderedSignals[P])
4582 setcontext(c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004583
4584 d1 = Decimal('-25e55')
4585 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004586 d2 = Decimal('33e+33')
4587 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004588
4589 def checkSameDec(operation, useOther=False):
4590 if useOther:
4591 eval("d1." + operation + "(d2)")
4592 self.assertEqual(d1._sign, b1._sign)
4593 self.assertEqual(d1._int, b1._int)
4594 self.assertEqual(d1._exp, b1._exp)
4595 self.assertEqual(d2._sign, b2._sign)
4596 self.assertEqual(d2._int, b2._int)
4597 self.assertEqual(d2._exp, b2._exp)
4598 else:
4599 eval("d1." + operation + "()")
4600 self.assertEqual(d1._sign, b1._sign)
4601 self.assertEqual(d1._int, b1._int)
4602 self.assertEqual(d1._exp, b1._exp)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004603
4604 Decimal(d1)
4605 self.assertEqual(d1._sign, b1._sign)
4606 self.assertEqual(d1._int, b1._int)
4607 self.assertEqual(d1._exp, b1._exp)
4608
4609 checkSameDec("__abs__")
4610 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004611 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00004612 checkSameDec("__eq__", True)
4613 checkSameDec("__ne__", True)
4614 checkSameDec("__le__", True)
4615 checkSameDec("__lt__", True)
4616 checkSameDec("__ge__", True)
4617 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004618 checkSameDec("__float__")
4619 checkSameDec("__floordiv__", True)
4620 checkSameDec("__hash__")
4621 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00004622 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004623 checkSameDec("__mod__", True)
4624 checkSameDec("__mul__", True)
4625 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00004626 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004627 checkSameDec("__pos__")
4628 checkSameDec("__pow__", True)
4629 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004630 checkSameDec("__rdivmod__", True)
4631 checkSameDec("__repr__")
4632 checkSameDec("__rfloordiv__", True)
4633 checkSameDec("__rmod__", True)
4634 checkSameDec("__rmul__", True)
4635 checkSameDec("__rpow__", True)
4636 checkSameDec("__rsub__", True)
4637 checkSameDec("__str__")
4638 checkSameDec("__sub__", True)
4639 checkSameDec("__truediv__", True)
4640 checkSameDec("adjusted")
4641 checkSameDec("as_tuple")
4642 checkSameDec("compare", True)
4643 checkSameDec("max", True)
4644 checkSameDec("min", True)
4645 checkSameDec("normalize")
4646 checkSameDec("quantize", True)
4647 checkSameDec("remainder_near", True)
4648 checkSameDec("same_quantum", True)
4649 checkSameDec("sqrt")
4650 checkSameDec("to_eng_string")
4651 checkSameDec("to_integral")
4652
Stefan Krah1919b7e2012-03-21 18:25:23 +01004653 def test_py_decimal_id(self):
4654 Decimal = P.Decimal
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004655
Stefan Krah1919b7e2012-03-21 18:25:23 +01004656 d = Decimal(45)
4657 e = Decimal(d)
4658 self.assertEqual(str(e), '45')
4659 self.assertNotEqual(id(d), id(e))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004660
Stefan Krah1919b7e2012-03-21 18:25:23 +01004661 def test_py_rescale(self):
4662 # Coverage
4663 Decimal = P.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01004664 localcontext = P.localcontext
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004665
Stefan Krah1919b7e2012-03-21 18:25:23 +01004666 with localcontext() as c:
4667 x = Decimal("NaN")._rescale(3, ROUND_UP)
4668 self.assertTrue(x.is_nan())
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004669
Stefan Krah1919b7e2012-03-21 18:25:23 +01004670 def test_py__round(self):
4671 # Coverage
4672 Decimal = P.Decimal
Christian Heimes0348fb62008-03-26 12:55:56 +00004673
Stefan Krah1919b7e2012-03-21 18:25:23 +01004674 self.assertRaises(ValueError, Decimal("3.1234")._round, 0, ROUND_UP)
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004675
Stefan Krah1919b7e2012-03-21 18:25:23 +01004676class CFunctionality(unittest.TestCase):
4677 """Extra functionality in _decimal"""
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004678
Stefan Krah1919b7e2012-03-21 18:25:23 +01004679 @requires_extra_functionality
4680 def test_c_ieee_context(self):
4681 # issue 8786: Add support for IEEE 754 contexts to decimal module.
4682 IEEEContext = C.IEEEContext
4683 DECIMAL32 = C.DECIMAL32
4684 DECIMAL64 = C.DECIMAL64
4685 DECIMAL128 = C.DECIMAL128
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004686
Stefan Krah1919b7e2012-03-21 18:25:23 +01004687 def assert_rest(self, context):
4688 self.assertEqual(context.clamp, 1)
4689 assert_signals(self, context, 'traps', [])
4690 assert_signals(self, context, 'flags', [])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004691
Stefan Krah1919b7e2012-03-21 18:25:23 +01004692 c = IEEEContext(DECIMAL32)
4693 self.assertEqual(c.prec, 7)
4694 self.assertEqual(c.Emax, 96)
4695 self.assertEqual(c.Emin, -95)
4696 assert_rest(self, c)
Raymond Hettinger82417ca2009-02-03 03:54:28 +00004697
Stefan Krah1919b7e2012-03-21 18:25:23 +01004698 c = IEEEContext(DECIMAL64)
4699 self.assertEqual(c.prec, 16)
4700 self.assertEqual(c.Emax, 384)
4701 self.assertEqual(c.Emin, -383)
4702 assert_rest(self, c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004703
Stefan Krah1919b7e2012-03-21 18:25:23 +01004704 c = IEEEContext(DECIMAL128)
4705 self.assertEqual(c.prec, 34)
4706 self.assertEqual(c.Emax, 6144)
4707 self.assertEqual(c.Emin, -6143)
4708 assert_rest(self, c)
Raymond Hettinger5548be22004-07-05 18:49:38 +00004709
Stefan Krah1919b7e2012-03-21 18:25:23 +01004710 # Invalid values
4711 self.assertRaises(OverflowError, IEEEContext, 2**63)
4712 self.assertRaises(ValueError, IEEEContext, -1)
4713 self.assertRaises(ValueError, IEEEContext, 1024)
Mark Dickinson825fce32009-09-07 18:08:12 +00004714
Stefan Krah1919b7e2012-03-21 18:25:23 +01004715 @requires_extra_functionality
4716 def test_c_context(self):
4717 Context = C.Context
Christian Heimes969fe572008-01-25 11:23:10 +00004718
Stefan Krah1919b7e2012-03-21 18:25:23 +01004719 c = Context(flags=C.DecClamped, traps=C.DecRounded)
4720 self.assertEqual(c._flags, C.DecClamped)
4721 self.assertEqual(c._traps, C.DecRounded)
Raymond Hettinger771ed762009-01-03 19:20:32 +00004722
Stefan Krah1919b7e2012-03-21 18:25:23 +01004723 @requires_extra_functionality
4724 def test_constants(self):
4725 # Condition flags
4726 cond = (
4727 C.DecClamped, C.DecConversionSyntax, C.DecDivisionByZero,
4728 C.DecDivisionImpossible, C.DecDivisionUndefined,
4729 C.DecFpuError, C.DecInexact, C.DecInvalidContext,
4730 C.DecInvalidOperation, C.DecMallocError,
4731 C.DecFloatOperation, C.DecOverflow, C.DecRounded,
4732 C.DecSubnormal, C.DecUnderflow
Raymond Hettinger771ed762009-01-03 19:20:32 +00004733 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01004734
4735 # IEEEContext
4736 self.assertEqual(C.DECIMAL32, 32)
4737 self.assertEqual(C.DECIMAL64, 64)
4738 self.assertEqual(C.DECIMAL128, 128)
4739 self.assertEqual(C.IEEE_CONTEXT_MAX_BITS, 512)
4740
Stefan Krah1919b7e2012-03-21 18:25:23 +01004741 # Conditions
4742 for i, v in enumerate(cond):
4743 self.assertEqual(v, 1<<i)
4744
4745 self.assertEqual(C.DecIEEEInvalidOperation,
4746 C.DecConversionSyntax|
4747 C.DecDivisionImpossible|
4748 C.DecDivisionUndefined|
4749 C.DecFpuError|
4750 C.DecInvalidContext|
4751 C.DecInvalidOperation|
4752 C.DecMallocError)
4753
4754 self.assertEqual(C.DecErrors,
4755 C.DecIEEEInvalidOperation|
4756 C.DecDivisionByZero)
4757
4758 self.assertEqual(C.DecTraps,
4759 C.DecErrors|C.DecOverflow|C.DecUnderflow)
4760
Stefan Krah39042e02020-08-10 16:32:21 +02004761 def test_decimal_api_predicates(self):
4762 # Capsule API
4763
4764 d = C.Decimal("0")
4765 self.assertFalse(decimal_is_special(d))
4766 self.assertFalse(decimal_is_nan(d))
4767 self.assertFalse(decimal_is_infinite(d))
4768
4769 d = C.Decimal("NaN")
4770 self.assertTrue(decimal_is_special(d))
4771 self.assertTrue(decimal_is_nan(d))
4772 self.assertFalse(decimal_is_infinite(d))
4773
4774 d = C.Decimal("sNaN")
4775 self.assertTrue(decimal_is_special(d))
4776 self.assertTrue(decimal_is_nan(d))
4777 self.assertFalse(decimal_is_infinite(d))
4778
4779 d = C.Decimal("inf")
4780 self.assertTrue(decimal_is_special(d))
4781 self.assertFalse(decimal_is_nan(d))
4782 self.assertTrue(decimal_is_infinite(d))
4783
4784 def test_decimal_api_get_digits(self):
4785 # Capsule API
4786
4787 d = C.Decimal("0")
4788 self.assertEqual(decimal_get_digits(d), 1)
4789
4790 d = C.Decimal("1234567890")
4791 self.assertEqual(decimal_get_digits(d), 10)
4792
4793 d = C.Decimal("inf")
4794 self.assertEqual(decimal_get_digits(d), 0)
4795
4796 d = C.Decimal("NaN")
4797 self.assertEqual(decimal_get_digits(d), 0)
4798
4799 d = C.Decimal("sNaN")
4800 self.assertEqual(decimal_get_digits(d), 0)
4801
4802 d = C.Decimal("NaN1234567890")
4803 self.assertEqual(decimal_get_digits(d), 10)
4804
4805 d = C.Decimal("sNaN1234567890")
4806 self.assertEqual(decimal_get_digits(d), 10)
4807
4808 def test_decimal_api_triple(self):
4809 # Capsule API
4810
4811 def as_triple(d):
4812 """Convert a decimal to a decimal triple with a split uint128_t
4813 coefficient:
4814
4815 (sign, hi, lo, exp)
4816
4817 It is called 'triple' because (hi, lo) are regarded as a single
4818 uint128_t that is split because not all compilers support uint128_t.
4819 """
4820 sign, digits, exp = d.as_tuple()
4821
4822 s = "".join(str(d) for d in digits)
4823 coeff = int(s) if s else 0
4824
4825 if coeff < 0 or coeff >= 2**128:
4826 raise ValueError("value out of bounds for a uint128 triple");
4827
4828 hi, lo = divmod(coeff, 2**64)
4829 return (sign, hi, lo, exp)
4830
4831 def from_triple(triple):
4832 """Convert a decimal triple with a split uint128_t coefficient to a string.
4833 """
4834 sign, hi, lo, exp = triple
4835 coeff = hi * 2**64 + lo
4836
4837 if coeff < 0 or coeff >= 2**128:
4838 raise ValueError("value out of bounds for a uint128 triple");
4839
4840 digits = tuple(int(c) for c in str(coeff))
4841
4842 return P.Decimal((sign, digits, exp))
4843
4844 signs = ["", "-"]
4845
4846 coefficients = [
4847 "000000000000000000000000000000000000000",
4848
4849 "299999999999999999999999999999999999999",
4850 "299999999999999999990000000000000000000",
4851 "200000000000000000009999999999999999999",
4852 "000000000000000000009999999999999999999",
4853
4854 "299999999999999999999999999999000000000",
4855 "299999999999999999999000000000999999999",
4856 "299999999999000000000999999999999999999",
4857 "299000000000999999999999999999999999999",
4858 "000999999999999999999999999999999999999",
4859
4860 "300000000000000000000000000000000000000",
4861 "310000000000000000001000000000000000000",
4862 "310000000000000000000000000000000000000",
4863 "300000000000000000001000000000000000000",
4864
4865 "340100000000100000000100000000100000000",
4866 "340100000000100000000100000000000000000",
4867 "340100000000100000000000000000100000000",
4868 "340100000000000000000100000000100000000",
4869 "340000000000100000000100000000100000000",
4870
4871 "340282366920938463463374607431768211455",
4872 ]
4873
4874 exponents = [
4875 "E+0", "E+1", "E-1",
4876 "E+%s" % str(C.MAX_EMAX-38),
4877 "E-%s" % str(C.MIN_ETINY+38),
4878 ]
4879
4880 for sign in signs:
4881 for coeff in coefficients:
4882 for exp in exponents:
4883 s = sign + coeff + exp
4884
4885 ctriple = decimal_as_triple(C.Decimal(s))
4886 ptriple = as_triple(P.Decimal(s))
4887 self.assertEqual(ctriple, ptriple)
4888
4889 c = decimal_from_triple(ctriple)
4890 p = decimal_from_triple(ptriple)
4891 self.assertEqual(str(c), str(p))
4892
4893 for s in ["NaN", "-NaN", "sNaN", "-sNaN", "NaN123", "sNaN123", "inf", "-inf"]:
4894 ctriple = decimal_as_triple(C.Decimal(s))
4895 ptriple = as_triple(P.Decimal(s))
4896 self.assertEqual(ctriple, ptriple)
4897
4898 c = decimal_from_triple(ctriple)
4899 p = decimal_from_triple(ptriple)
4900 self.assertEqual(str(c), str(p))
4901
4902 def test_decimal_api_errors(self):
4903 # Capsule API
4904
4905 self.assertRaises(TypeError, decimal_as_triple, "X")
4906 self.assertRaises(ValueError, decimal_as_triple, C.Decimal(2**128))
4907 self.assertRaises(ValueError, decimal_as_triple, C.Decimal(-2**128))
4908
4909 self.assertRaises(TypeError, decimal_from_triple, "X")
4910 self.assertRaises(ValueError, decimal_from_triple, ())
4911 self.assertRaises(ValueError, decimal_from_triple, (1, 2, 3, 4, 5))
4912 self.assertRaises(ValueError, decimal_from_triple, (2**8, 0, 0, 0))
4913 self.assertRaises(OverflowError, decimal_from_triple, (0, 2**64, 0, 0))
4914 self.assertRaises(OverflowError, decimal_from_triple, (0, 0, 2**64, 0))
4915 self.assertRaises(OverflowError, decimal_from_triple, (0, 0, 0, 2**63))
4916 self.assertRaises(OverflowError, decimal_from_triple, (0, 0, 0, -2**63-1))
4917 self.assertRaises(ValueError, decimal_from_triple, (0, 0, 0, "X"))
4918 self.assertRaises(TypeError, decimal_from_triple, (0, 0, 0, ()))
4919
4920 with C.localcontext(C.Context()):
4921 self.assertRaises(C.InvalidOperation, decimal_from_triple, (2, 0, 0, 0))
4922 self.assertRaises(C.InvalidOperation, decimal_from_triple, (0, 0, 0, 2**63-1))
4923 self.assertRaises(C.InvalidOperation, decimal_from_triple, (0, 0, 0, -2**63))
4924
4925 self.assertRaises(TypeError, decimal_is_special, "X")
4926 self.assertRaises(TypeError, decimal_is_nan, "X")
4927 self.assertRaises(TypeError, decimal_is_infinite, "X")
4928 self.assertRaises(TypeError, decimal_get_digits, "X")
4929
Stefan Krah1919b7e2012-03-21 18:25:23 +01004930class CWhitebox(unittest.TestCase):
4931 """Whitebox testing for _decimal"""
4932
4933 def test_bignum(self):
4934 # Not exactly whitebox, but too slow with pydecimal.
4935
4936 Decimal = C.Decimal
4937 localcontext = C.localcontext
4938
4939 b1 = 10**35
4940 b2 = 10**36
4941 with localcontext() as c:
4942 c.prec = 1000000
4943 for i in range(5):
4944 a = random.randrange(b1, b2)
4945 b = random.randrange(1000, 1200)
4946 x = a ** b
4947 y = Decimal(a) ** Decimal(b)
4948 self.assertEqual(x, y)
4949
4950 def test_invalid_construction(self):
4951 self.assertRaises(TypeError, C.Decimal, 9, "xyz")
4952
4953 def test_c_input_restriction(self):
4954 # Too large for _decimal to be converted exactly
4955 Decimal = C.Decimal
4956 InvalidOperation = C.InvalidOperation
4957 Context = C.Context
4958 localcontext = C.localcontext
4959
4960 with localcontext(Context()):
4961 self.assertRaises(InvalidOperation, Decimal,
4962 "1e9999999999999999999")
4963
4964 def test_c_context_repr(self):
4965 # This test is _decimal-only because flags are not printed
4966 # in the same order.
4967 DefaultContext = C.DefaultContext
4968 FloatOperation = C.FloatOperation
Stefan Krah1919b7e2012-03-21 18:25:23 +01004969
4970 c = DefaultContext.copy()
4971
4972 c.prec = 425000000
4973 c.Emax = 425000000
4974 c.Emin = -425000000
4975 c.rounding = ROUND_HALF_DOWN
4976 c.capitals = 0
4977 c.clamp = 1
4978 for sig in OrderedSignals[C]:
4979 c.flags[sig] = True
4980 c.traps[sig] = True
4981 c.flags[FloatOperation] = True
4982 c.traps[FloatOperation] = True
4983
4984 s = c.__repr__()
4985 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
4986 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
4987 "flags=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4988 "FloatOperation, Overflow, Rounded, Subnormal, Underflow], " \
4989 "traps=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4990 "FloatOperation, Overflow, Rounded, Subnormal, Underflow])"
4991 self.assertEqual(s, t)
4992
4993 def test_c_context_errors(self):
4994 Context = C.Context
4995 InvalidOperation = C.InvalidOperation
4996 Overflow = C.Overflow
4997 FloatOperation = C.FloatOperation
4998 localcontext = C.localcontext
4999 getcontext = C.getcontext
5000 setcontext = C.setcontext
5001 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
5002
5003 c = Context()
5004
5005 # SignalDict: input validation
5006 self.assertRaises(KeyError, c.flags.__setitem__, 801, 0)
5007 self.assertRaises(KeyError, c.traps.__setitem__, 801, 0)
5008 self.assertRaises(ValueError, c.flags.__delitem__, Overflow)
5009 self.assertRaises(ValueError, c.traps.__delitem__, InvalidOperation)
5010 self.assertRaises(TypeError, setattr, c, 'flags', ['x'])
5011 self.assertRaises(TypeError, setattr, c,'traps', ['y'])
5012 self.assertRaises(KeyError, setattr, c, 'flags', {0:1})
5013 self.assertRaises(KeyError, setattr, c, 'traps', {0:1})
5014
5015 # Test assignment from a signal dict with the correct length but
5016 # one invalid key.
5017 d = c.flags.copy()
5018 del d[FloatOperation]
5019 d["XYZ"] = 91283719
5020 self.assertRaises(KeyError, setattr, c, 'flags', d)
5021 self.assertRaises(KeyError, setattr, c, 'traps', d)
5022
5023 # Input corner cases
5024 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
5025 gt_max_emax = 10**18 if HAVE_CONFIG_64 else 10**9
5026
5027 # prec, Emax, Emin
5028 for attr in ['prec', 'Emax']:
5029 self.assertRaises(ValueError, setattr, c, attr, gt_max_emax)
5030 self.assertRaises(ValueError, setattr, c, 'Emin', -gt_max_emax)
5031
5032 # prec, Emax, Emin in context constructor
5033 self.assertRaises(ValueError, Context, prec=gt_max_emax)
5034 self.assertRaises(ValueError, Context, Emax=gt_max_emax)
5035 self.assertRaises(ValueError, Context, Emin=-gt_max_emax)
5036
5037 # Overflow in conversion
5038 self.assertRaises(OverflowError, Context, prec=int_max+1)
5039 self.assertRaises(OverflowError, Context, Emax=int_max+1)
5040 self.assertRaises(OverflowError, Context, Emin=-int_max-2)
Stefan Krah1919b7e2012-03-21 18:25:23 +01005041 self.assertRaises(OverflowError, Context, clamp=int_max+1)
5042 self.assertRaises(OverflowError, Context, capitals=int_max+1)
5043
5044 # OverflowError, general ValueError
5045 for attr in ('prec', 'Emin', 'Emax', 'capitals', 'clamp'):
5046 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
5047 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
5048 if sys.platform != 'win32':
5049 self.assertRaises(ValueError, setattr, c, attr, int_max)
5050 self.assertRaises(ValueError, setattr, c, attr, -int_max-1)
5051
Stefan Krah1919b7e2012-03-21 18:25:23 +01005052 # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
5053 if C.MAX_PREC == 425000000:
5054 self.assertRaises(OverflowError, getattr(c, '_unsafe_setprec'),
5055 int_max+1)
5056 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemax'),
5057 int_max+1)
5058 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemin'),
5059 -int_max-2)
5060
5061 # ValueError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
5062 if C.MAX_PREC == 425000000:
5063 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), 0)
5064 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'),
5065 1070000001)
5066 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), -1)
5067 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'),
5068 1070000001)
5069 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'),
5070 -1070000001)
5071 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), 1)
5072
5073 # capitals, clamp
5074 for attr in ['capitals', 'clamp']:
5075 self.assertRaises(ValueError, setattr, c, attr, -1)
5076 self.assertRaises(ValueError, setattr, c, attr, 2)
5077 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
5078 if HAVE_CONFIG_64:
5079 self.assertRaises(ValueError, setattr, c, attr, 2**32)
5080 self.assertRaises(ValueError, setattr, c, attr, 2**32+1)
5081
5082 # Invalid local context
5083 self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass',
5084 locals())
Stefan Krah040e3112012-12-15 22:33:33 +01005085 self.assertRaises(TypeError, exec,
5086 'with localcontext(context=getcontext()): pass',
5087 locals())
Stefan Krah1919b7e2012-03-21 18:25:23 +01005088
5089 # setcontext
5090 saved_context = getcontext()
5091 self.assertRaises(TypeError, setcontext, "xyz")
5092 setcontext(saved_context)
5093
Stefan Krah59a4a932013-01-16 12:58:59 +01005094 def test_rounding_strings_interned(self):
5095
5096 self.assertIs(C.ROUND_UP, P.ROUND_UP)
5097 self.assertIs(C.ROUND_DOWN, P.ROUND_DOWN)
5098 self.assertIs(C.ROUND_CEILING, P.ROUND_CEILING)
5099 self.assertIs(C.ROUND_FLOOR, P.ROUND_FLOOR)
5100 self.assertIs(C.ROUND_HALF_UP, P.ROUND_HALF_UP)
5101 self.assertIs(C.ROUND_HALF_DOWN, P.ROUND_HALF_DOWN)
5102 self.assertIs(C.ROUND_HALF_EVEN, P.ROUND_HALF_EVEN)
5103 self.assertIs(C.ROUND_05UP, P.ROUND_05UP)
5104
Stefan Krah1919b7e2012-03-21 18:25:23 +01005105 @requires_extra_functionality
5106 def test_c_context_errors_extra(self):
5107 Context = C.Context
5108 InvalidOperation = C.InvalidOperation
5109 Overflow = C.Overflow
5110 localcontext = C.localcontext
5111 getcontext = C.getcontext
5112 setcontext = C.setcontext
5113 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
5114
5115 c = Context()
5116
5117 # Input corner cases
5118 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
5119
5120 # OverflowError, general ValueError
5121 self.assertRaises(OverflowError, setattr, c, '_allcr', int_max+1)
5122 self.assertRaises(OverflowError, setattr, c, '_allcr', -int_max-2)
5123 if sys.platform != 'win32':
5124 self.assertRaises(ValueError, setattr, c, '_allcr', int_max)
5125 self.assertRaises(ValueError, setattr, c, '_allcr', -int_max-1)
5126
5127 # OverflowError, general TypeError
5128 for attr in ('_flags', '_traps'):
5129 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
5130 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
5131 if sys.platform != 'win32':
5132 self.assertRaises(TypeError, setattr, c, attr, int_max)
5133 self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
5134
5135 # _allcr
5136 self.assertRaises(ValueError, setattr, c, '_allcr', -1)
5137 self.assertRaises(ValueError, setattr, c, '_allcr', 2)
5138 self.assertRaises(TypeError, setattr, c, '_allcr', [1,2,3])
5139 if HAVE_CONFIG_64:
5140 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32)
5141 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32+1)
5142
5143 # _flags, _traps
5144 for attr in ['_flags', '_traps']:
5145 self.assertRaises(TypeError, setattr, c, attr, 999999)
5146 self.assertRaises(TypeError, setattr, c, attr, 'x')
5147
5148 def test_c_valid_context(self):
5149 # These tests are for code coverage in _decimal.
5150 DefaultContext = C.DefaultContext
Stefan Krah1919b7e2012-03-21 18:25:23 +01005151 Clamped = C.Clamped
5152 Underflow = C.Underflow
5153 Inexact = C.Inexact
5154 Rounded = C.Rounded
5155 Subnormal = C.Subnormal
5156
5157 c = DefaultContext.copy()
5158
5159 # Exercise all getters and setters
5160 c.prec = 34
5161 c.rounding = ROUND_HALF_UP
5162 c.Emax = 3000
5163 c.Emin = -3000
5164 c.capitals = 1
5165 c.clamp = 0
5166
5167 self.assertEqual(c.prec, 34)
5168 self.assertEqual(c.rounding, ROUND_HALF_UP)
5169 self.assertEqual(c.Emin, -3000)
5170 self.assertEqual(c.Emax, 3000)
5171 self.assertEqual(c.capitals, 1)
5172 self.assertEqual(c.clamp, 0)
5173
5174 self.assertEqual(c.Etiny(), -3033)
5175 self.assertEqual(c.Etop(), 2967)
5176
5177 # Exercise all unsafe setters
5178 if C.MAX_PREC == 425000000:
5179 c._unsafe_setprec(999999999)
5180 c._unsafe_setemax(999999999)
5181 c._unsafe_setemin(-999999999)
5182 self.assertEqual(c.prec, 999999999)
5183 self.assertEqual(c.Emax, 999999999)
5184 self.assertEqual(c.Emin, -999999999)
5185
5186 @requires_extra_functionality
5187 def test_c_valid_context_extra(self):
5188 DefaultContext = C.DefaultContext
5189
5190 c = DefaultContext.copy()
5191 self.assertEqual(c._allcr, 1)
5192 c._allcr = 0
5193 self.assertEqual(c._allcr, 0)
5194
5195 def test_c_round(self):
5196 # Restricted input.
5197 Decimal = C.Decimal
5198 InvalidOperation = C.InvalidOperation
5199 localcontext = C.localcontext
5200 MAX_EMAX = C.MAX_EMAX
5201 MIN_ETINY = C.MIN_ETINY
5202 int_max = 2**63-1 if C.MAX_PREC > 425000000 else 2**31-1
5203
5204 with localcontext() as c:
5205 c.traps[InvalidOperation] = True
5206 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
5207 -int_max-1)
5208 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
5209 int_max)
5210 self.assertRaises(InvalidOperation, Decimal("1").__round__,
5211 int(MAX_EMAX+1))
5212 self.assertRaises(C.InvalidOperation, Decimal("1").__round__,
5213 -int(MIN_ETINY-1))
5214 self.assertRaises(OverflowError, Decimal("1.23").__round__,
5215 -int_max-2)
5216 self.assertRaises(OverflowError, Decimal("1.23").__round__,
5217 int_max+1)
5218
5219 def test_c_format(self):
5220 # Restricted input
5221 Decimal = C.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01005222 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
5223
5224 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", [], 9)
5225 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", 9)
5226 self.assertRaises(TypeError, Decimal(1).__format__, [])
5227
Stefan Kraheb8c4512013-01-24 15:22:33 +01005228 self.assertRaises(ValueError, Decimal(1).__format__, "<>=10.10")
5229 maxsize = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
5230 self.assertRaises(ValueError, Decimal("1.23456789").__format__,
5231 "=%d.1" % maxsize)
Stefan Krah1919b7e2012-03-21 18:25:23 +01005232
5233 def test_c_integral(self):
5234 Decimal = C.Decimal
5235 Inexact = C.Inexact
Stefan Krah1919b7e2012-03-21 18:25:23 +01005236 localcontext = C.localcontext
5237
5238 x = Decimal(10)
5239 self.assertEqual(x.to_integral(), 10)
5240 self.assertRaises(TypeError, x.to_integral, '10')
5241 self.assertRaises(TypeError, x.to_integral, 10, 'x')
5242 self.assertRaises(TypeError, x.to_integral, 10)
5243
5244 self.assertEqual(x.to_integral_value(), 10)
5245 self.assertRaises(TypeError, x.to_integral_value, '10')
5246 self.assertRaises(TypeError, x.to_integral_value, 10, 'x')
5247 self.assertRaises(TypeError, x.to_integral_value, 10)
5248
5249 self.assertEqual(x.to_integral_exact(), 10)
5250 self.assertRaises(TypeError, x.to_integral_exact, '10')
5251 self.assertRaises(TypeError, x.to_integral_exact, 10, 'x')
5252 self.assertRaises(TypeError, x.to_integral_exact, 10)
5253
5254 with localcontext() as c:
5255 x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP)
5256 self.assertEqual(x, Decimal('100000000000000000000000000'))
5257
5258 x = Decimal("99999999999999999999999999.9").to_integral_exact(ROUND_UP)
5259 self.assertEqual(x, Decimal('100000000000000000000000000'))
5260
5261 c.traps[Inexact] = True
5262 self.assertRaises(Inexact, Decimal("999.9").to_integral_exact, ROUND_UP)
5263
5264 def test_c_funcs(self):
5265 # Invalid arguments
5266 Decimal = C.Decimal
5267 InvalidOperation = C.InvalidOperation
5268 DivisionByZero = C.DivisionByZero
Stefan Krah1919b7e2012-03-21 18:25:23 +01005269 getcontext = C.getcontext
5270 localcontext = C.localcontext
5271
5272 self.assertEqual(Decimal('9.99e10').to_eng_string(), '99.9E+9')
5273
5274 self.assertRaises(TypeError, pow, Decimal(1), 2, "3")
5275 self.assertRaises(TypeError, Decimal(9).number_class, "x", "y")
5276 self.assertRaises(TypeError, Decimal(9).same_quantum, 3, "x", "y")
5277
Raymond Hettinger771ed762009-01-03 19:20:32 +00005278 self.assertRaises(
Stefan Krah1919b7e2012-03-21 18:25:23 +01005279 TypeError,
5280 Decimal("1.23456789").quantize, Decimal('1e-100000'), []
Raymond Hettinger771ed762009-01-03 19:20:32 +00005281 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01005282 self.assertRaises(
5283 TypeError,
5284 Decimal("1.23456789").quantize, Decimal('1e-100000'), getcontext()
5285 )
5286 self.assertRaises(
5287 TypeError,
5288 Decimal("1.23456789").quantize, Decimal('1e-100000'), 10
5289 )
5290 self.assertRaises(
5291 TypeError,
5292 Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000
5293 )
Raymond Hettinger771ed762009-01-03 19:20:32 +00005294
Stefan Krah1919b7e2012-03-21 18:25:23 +01005295 with localcontext() as c:
5296 c.clear_traps()
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00005297
Stefan Krah1919b7e2012-03-21 18:25:23 +01005298 # Invalid arguments
5299 self.assertRaises(TypeError, c.copy_sign, Decimal(1), "x", "y")
5300 self.assertRaises(TypeError, c.canonical, 200)
5301 self.assertRaises(TypeError, c.is_canonical, 200)
5302 self.assertRaises(TypeError, c.divmod, 9, 8, "x", "y")
5303 self.assertRaises(TypeError, c.same_quantum, 9, 3, "x", "y")
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00005304
Stefan Krah1919b7e2012-03-21 18:25:23 +01005305 self.assertEqual(str(c.canonical(Decimal(200))), '200')
5306 self.assertEqual(c.radix(), 10)
Raymond Hettinger0aeac102004-07-05 22:53:03 +00005307
Stefan Krah1919b7e2012-03-21 18:25:23 +01005308 c.traps[DivisionByZero] = True
5309 self.assertRaises(DivisionByZero, Decimal(9).__divmod__, 0)
5310 self.assertRaises(DivisionByZero, c.divmod, 9, 0)
5311 self.assertTrue(c.flags[InvalidOperation])
Raymond Hettinger955d2b22004-08-08 20:17:45 +00005312
Stefan Krah1919b7e2012-03-21 18:25:23 +01005313 c.clear_flags()
5314 c.traps[InvalidOperation] = True
5315 self.assertRaises(InvalidOperation, Decimal(9).__divmod__, 0)
5316 self.assertRaises(InvalidOperation, c.divmod, 9, 0)
5317 self.assertTrue(c.flags[DivisionByZero])
Mark Dickinsonb1d8e322010-05-22 18:35:36 +00005318
Stefan Krah1919b7e2012-03-21 18:25:23 +01005319 c.traps[InvalidOperation] = True
5320 c.prec = 2
5321 self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501)
Mark Dickinson84230a12010-02-18 14:49:50 +00005322
Stefan Krah040e3112012-12-15 22:33:33 +01005323 def test_va_args_exceptions(self):
5324 Decimal = C.Decimal
5325 Context = C.Context
5326
5327 x = Decimal("10001111111")
5328
5329 for attr in ['exp', 'is_normal', 'is_subnormal', 'ln', 'log10',
5330 'logb', 'logical_invert', 'next_minus', 'next_plus',
5331 'normalize', 'number_class', 'sqrt', 'to_eng_string']:
5332 func = getattr(x, attr)
5333 self.assertRaises(TypeError, func, context="x")
5334 self.assertRaises(TypeError, func, "x", context=None)
5335
5336 for attr in ['compare', 'compare_signal', 'logical_and',
5337 'logical_or', 'max', 'max_mag', 'min', 'min_mag',
5338 'remainder_near', 'rotate', 'scaleb', 'shift']:
5339 func = getattr(x, attr)
5340 self.assertRaises(TypeError, func, context="x")
5341 self.assertRaises(TypeError, func, "x", context=None)
5342
5343 self.assertRaises(TypeError, x.to_integral, rounding=None, context=[])
5344 self.assertRaises(TypeError, x.to_integral, rounding={}, context=[])
5345 self.assertRaises(TypeError, x.to_integral, [], [])
5346
5347 self.assertRaises(TypeError, x.to_integral_value, rounding=None, context=[])
5348 self.assertRaises(TypeError, x.to_integral_value, rounding={}, context=[])
5349 self.assertRaises(TypeError, x.to_integral_value, [], [])
5350
5351 self.assertRaises(TypeError, x.to_integral_exact, rounding=None, context=[])
5352 self.assertRaises(TypeError, x.to_integral_exact, rounding={}, context=[])
5353 self.assertRaises(TypeError, x.to_integral_exact, [], [])
5354
5355 self.assertRaises(TypeError, x.fma, 1, 2, context="x")
5356 self.assertRaises(TypeError, x.fma, 1, 2, "x", context=None)
5357
5358 self.assertRaises(TypeError, x.quantize, 1, [], context=None)
5359 self.assertRaises(TypeError, x.quantize, 1, [], rounding=None)
5360 self.assertRaises(TypeError, x.quantize, 1, [], [])
5361
5362 c = Context()
5363 self.assertRaises(TypeError, c.power, 1, 2, mod="x")
5364 self.assertRaises(TypeError, c.power, 1, "x", mod=None)
5365 self.assertRaises(TypeError, c.power, "x", 2, mod=None)
5366
Stefan Krah1919b7e2012-03-21 18:25:23 +01005367 @requires_extra_functionality
5368 def test_c_context_templates(self):
5369 self.assertEqual(
5370 C.BasicContext._traps,
5371 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow|
5372 C.DecUnderflow|C.DecClamped
5373 )
5374 self.assertEqual(
5375 C.DefaultContext._traps,
5376 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow
5377 )
Mark Dickinson84230a12010-02-18 14:49:50 +00005378
Stefan Krah1919b7e2012-03-21 18:25:23 +01005379 @requires_extra_functionality
5380 def test_c_signal_dict(self):
Mark Dickinson84230a12010-02-18 14:49:50 +00005381
Stefan Krah1919b7e2012-03-21 18:25:23 +01005382 # SignalDict coverage
5383 Context = C.Context
5384 DefaultContext = C.DefaultContext
Mark Dickinson84230a12010-02-18 14:49:50 +00005385
Stefan Krah1919b7e2012-03-21 18:25:23 +01005386 InvalidOperation = C.InvalidOperation
Stefan Krah5fe1df12020-06-05 22:01:18 +02005387 FloatOperation = C.FloatOperation
Stefan Krah1919b7e2012-03-21 18:25:23 +01005388 DivisionByZero = C.DivisionByZero
5389 Overflow = C.Overflow
5390 Subnormal = C.Subnormal
5391 Underflow = C.Underflow
5392 Rounded = C.Rounded
5393 Inexact = C.Inexact
5394 Clamped = C.Clamped
Mark Dickinson84230a12010-02-18 14:49:50 +00005395
Stefan Krah1919b7e2012-03-21 18:25:23 +01005396 DecClamped = C.DecClamped
5397 DecInvalidOperation = C.DecInvalidOperation
5398 DecIEEEInvalidOperation = C.DecIEEEInvalidOperation
Mark Dickinson84230a12010-02-18 14:49:50 +00005399
Stefan Krah1919b7e2012-03-21 18:25:23 +01005400 def assertIsExclusivelySet(signal, signal_dict):
5401 for sig in signal_dict:
5402 if sig == signal:
5403 self.assertTrue(signal_dict[sig])
5404 else:
5405 self.assertFalse(signal_dict[sig])
Mark Dickinson84230a12010-02-18 14:49:50 +00005406
Stefan Krah1919b7e2012-03-21 18:25:23 +01005407 c = DefaultContext.copy()
Mark Dickinson84230a12010-02-18 14:49:50 +00005408
Stefan Krah1919b7e2012-03-21 18:25:23 +01005409 # Signal dict methods
5410 self.assertTrue(Overflow in c.traps)
5411 c.clear_traps()
5412 for k in c.traps.keys():
5413 c.traps[k] = True
5414 for v in c.traps.values():
5415 self.assertTrue(v)
5416 c.clear_traps()
5417 for k, v in c.traps.items():
5418 self.assertFalse(v)
Mark Dickinson84230a12010-02-18 14:49:50 +00005419
Stefan Krah1919b7e2012-03-21 18:25:23 +01005420 self.assertFalse(c.flags.get(Overflow))
5421 self.assertIs(c.flags.get("x"), None)
5422 self.assertEqual(c.flags.get("x", "y"), "y")
5423 self.assertRaises(TypeError, c.flags.get, "x", "y", "z")
Mark Dickinson84230a12010-02-18 14:49:50 +00005424
Stefan Krah1919b7e2012-03-21 18:25:23 +01005425 self.assertEqual(len(c.flags), len(c.traps))
5426 s = sys.getsizeof(c.flags)
5427 s = sys.getsizeof(c.traps)
5428 s = c.flags.__repr__()
Mark Dickinson84230a12010-02-18 14:49:50 +00005429
Stefan Krah1919b7e2012-03-21 18:25:23 +01005430 # Set flags/traps.
5431 c.clear_flags()
5432 c._flags = DecClamped
5433 self.assertTrue(c.flags[Clamped])
Mark Dickinson84230a12010-02-18 14:49:50 +00005434
Stefan Krah1919b7e2012-03-21 18:25:23 +01005435 c.clear_traps()
5436 c._traps = DecInvalidOperation
5437 self.assertTrue(c.traps[InvalidOperation])
Mark Dickinson84230a12010-02-18 14:49:50 +00005438
Stefan Krah1919b7e2012-03-21 18:25:23 +01005439 # Set flags/traps from dictionary.
5440 c.clear_flags()
5441 d = c.flags.copy()
5442 d[DivisionByZero] = True
5443 c.flags = d
5444 assertIsExclusivelySet(DivisionByZero, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00005445
Stefan Krah1919b7e2012-03-21 18:25:23 +01005446 c.clear_traps()
5447 d = c.traps.copy()
5448 d[Underflow] = True
5449 c.traps = d
5450 assertIsExclusivelySet(Underflow, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00005451
Stefan Krah1919b7e2012-03-21 18:25:23 +01005452 # Random constructors
5453 IntSignals = {
5454 Clamped: C.DecClamped,
5455 Rounded: C.DecRounded,
5456 Inexact: C.DecInexact,
5457 Subnormal: C.DecSubnormal,
5458 Underflow: C.DecUnderflow,
5459 Overflow: C.DecOverflow,
5460 DivisionByZero: C.DecDivisionByZero,
Stefan Krah5fe1df12020-06-05 22:01:18 +02005461 FloatOperation: C.DecFloatOperation,
Stefan Krah1919b7e2012-03-21 18:25:23 +01005462 InvalidOperation: C.DecIEEEInvalidOperation
5463 }
5464 IntCond = [
5465 C.DecDivisionImpossible, C.DecDivisionUndefined, C.DecFpuError,
5466 C.DecInvalidContext, C.DecInvalidOperation, C.DecMallocError,
5467 C.DecConversionSyntax,
5468 ]
Mark Dickinsonb455e582011-05-22 12:53:18 +01005469
Stefan Krah1919b7e2012-03-21 18:25:23 +01005470 lim = len(OrderedSignals[C])
5471 for r in range(lim):
5472 for t in range(lim):
Stefan Krah59a4a932013-01-16 12:58:59 +01005473 for round in RoundingModes:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005474 flags = random.sample(OrderedSignals[C], r)
5475 traps = random.sample(OrderedSignals[C], t)
5476 prec = random.randrange(1, 10000)
5477 emin = random.randrange(-10000, 0)
5478 emax = random.randrange(0, 10000)
5479 clamp = random.randrange(0, 2)
5480 caps = random.randrange(0, 2)
5481 cr = random.randrange(0, 2)
5482 c = Context(prec=prec, rounding=round, Emin=emin, Emax=emax,
5483 capitals=caps, clamp=clamp, flags=list(flags),
5484 traps=list(traps))
Mark Dickinson84230a12010-02-18 14:49:50 +00005485
Stefan Krah1919b7e2012-03-21 18:25:23 +01005486 self.assertEqual(c.prec, prec)
5487 self.assertEqual(c.rounding, round)
5488 self.assertEqual(c.Emin, emin)
5489 self.assertEqual(c.Emax, emax)
5490 self.assertEqual(c.capitals, caps)
5491 self.assertEqual(c.clamp, clamp)
Mark Dickinson84230a12010-02-18 14:49:50 +00005492
Stefan Krah1919b7e2012-03-21 18:25:23 +01005493 f = 0
5494 for x in flags:
5495 f |= IntSignals[x]
5496 self.assertEqual(c._flags, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00005497
Stefan Krah1919b7e2012-03-21 18:25:23 +01005498 f = 0
5499 for x in traps:
5500 f |= IntSignals[x]
5501 self.assertEqual(c._traps, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00005502
Stefan Krah1919b7e2012-03-21 18:25:23 +01005503 for cond in IntCond:
5504 c._flags = cond
5505 self.assertTrue(c._flags&DecIEEEInvalidOperation)
5506 assertIsExclusivelySet(InvalidOperation, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00005507
Stefan Krah1919b7e2012-03-21 18:25:23 +01005508 for cond in IntCond:
5509 c._traps = cond
5510 self.assertTrue(c._traps&DecIEEEInvalidOperation)
5511 assertIsExclusivelySet(InvalidOperation, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00005512
Stefan Krah1919b7e2012-03-21 18:25:23 +01005513 def test_invalid_override(self):
5514 Decimal = C.Decimal
Mark Dickinson84230a12010-02-18 14:49:50 +00005515
Stefan Krah1919b7e2012-03-21 18:25:23 +01005516 try:
5517 from locale import CHAR_MAX
5518 except ImportError:
Zachary Ware9fe6d862013-12-08 00:20:35 -06005519 self.skipTest('locale.CHAR_MAX not available')
Mark Dickinson84230a12010-02-18 14:49:50 +00005520
Stefan Krah1919b7e2012-03-21 18:25:23 +01005521 def make_grouping(lst):
5522 return ''.join([chr(x) for x in lst])
Mark Dickinson84230a12010-02-18 14:49:50 +00005523
Stefan Krah1919b7e2012-03-21 18:25:23 +01005524 def get_fmt(x, override=None, fmt='n'):
5525 return Decimal(x).__format__(fmt, override)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005526
Stefan Krah1919b7e2012-03-21 18:25:23 +01005527 invalid_grouping = {
5528 'decimal_point' : ',',
5529 'grouping' : make_grouping([255, 255, 0]),
5530 'thousands_sep' : ','
5531 }
5532 invalid_dot = {
5533 'decimal_point' : 'xxxxx',
5534 'grouping' : make_grouping([3, 3, 0]),
5535 'thousands_sep' : ','
5536 }
5537 invalid_sep = {
5538 'decimal_point' : '.',
5539 'grouping' : make_grouping([3, 3, 0]),
5540 'thousands_sep' : 'yyyyy'
5541 }
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005542
Stefan Krah1919b7e2012-03-21 18:25:23 +01005543 if CHAR_MAX == 127: # negative grouping in override
5544 self.assertRaises(ValueError, get_fmt, 12345,
5545 invalid_grouping, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005546
Stefan Krah1919b7e2012-03-21 18:25:23 +01005547 self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g')
5548 self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005549
Stefan Krah0774e9b2012-04-05 15:21:58 +02005550 def test_exact_conversion(self):
5551 Decimal = C.Decimal
5552 localcontext = C.localcontext
5553 InvalidOperation = C.InvalidOperation
5554
5555 with localcontext() as c:
5556
5557 c.traps[InvalidOperation] = True
5558
5559 # Clamped
5560 x = "0e%d" % sys.maxsize
5561 self.assertRaises(InvalidOperation, Decimal, x)
5562
5563 x = "0e%d" % (-sys.maxsize-1)
5564 self.assertRaises(InvalidOperation, Decimal, x)
5565
5566 # Overflow
5567 x = "1e%d" % sys.maxsize
5568 self.assertRaises(InvalidOperation, Decimal, x)
5569
5570 # Underflow
5571 x = "1e%d" % (-sys.maxsize-1)
5572 self.assertRaises(InvalidOperation, Decimal, x)
5573
Stefan Krahff3eca02012-04-05 15:46:19 +02005574 def test_from_tuple(self):
5575 Decimal = C.Decimal
5576 localcontext = C.localcontext
5577 InvalidOperation = C.InvalidOperation
5578 Overflow = C.Overflow
5579 Underflow = C.Underflow
5580
5581 with localcontext() as c:
5582
5583 c.traps[InvalidOperation] = True
5584 c.traps[Overflow] = True
5585 c.traps[Underflow] = True
5586
5587 # SSIZE_MAX
5588 x = (1, (), sys.maxsize)
5589 self.assertEqual(str(c.create_decimal(x)), '-0E+999999')
5590 self.assertRaises(InvalidOperation, Decimal, x)
5591
5592 x = (1, (0, 1, 2), sys.maxsize)
5593 self.assertRaises(Overflow, c.create_decimal, x)
5594 self.assertRaises(InvalidOperation, Decimal, x)
5595
5596 # SSIZE_MIN
5597 x = (1, (), -sys.maxsize-1)
Stefan Krahe95dfc52018-06-03 18:40:00 +02005598 self.assertEqual(str(c.create_decimal(x)), '-0E-1000007')
Stefan Krahff3eca02012-04-05 15:46:19 +02005599 self.assertRaises(InvalidOperation, Decimal, x)
5600
5601 x = (1, (0, 1, 2), -sys.maxsize-1)
5602 self.assertRaises(Underflow, c.create_decimal, x)
5603 self.assertRaises(InvalidOperation, Decimal, x)
5604
5605 # OverflowError
5606 x = (1, (), sys.maxsize+1)
5607 self.assertRaises(OverflowError, c.create_decimal, x)
5608 self.assertRaises(OverflowError, Decimal, x)
5609
5610 x = (1, (), -sys.maxsize-2)
5611 self.assertRaises(OverflowError, c.create_decimal, x)
5612 self.assertRaises(OverflowError, Decimal, x)
5613
5614 # Specials
5615 x = (1, (), "N")
5616 self.assertEqual(str(Decimal(x)), '-sNaN')
5617 x = (1, (0,), "N")
5618 self.assertEqual(str(Decimal(x)), '-sNaN')
5619 x = (1, (0, 1), "N")
5620 self.assertEqual(str(Decimal(x)), '-sNaN1')
5621
Stefan Krah891ca9e2013-05-29 19:14:17 +02005622 def test_sizeof(self):
5623 Decimal = C.Decimal
5624 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
5625
5626 self.assertGreater(Decimal(0).__sizeof__(), 0)
5627 if HAVE_CONFIG_64:
5628 x = Decimal(10**(19*24)).__sizeof__()
5629 y = Decimal(10**(19*25)).__sizeof__()
5630 self.assertEqual(y, x+8)
5631 else:
5632 x = Decimal(10**(9*24)).__sizeof__()
5633 y = Decimal(10**(9*25)).__sizeof__()
5634 self.assertEqual(y, x+4)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005635
Stefan Krah8c126f12016-07-17 14:01:42 +02005636 def test_internal_use_of_overridden_methods(self):
5637 Decimal = C.Decimal
5638
5639 # Unsound subtyping
5640 class X(float):
5641 def as_integer_ratio(self):
5642 return 1
5643 def __abs__(self):
5644 return self
5645
5646 class Y(float):
5647 def __abs__(self):
5648 return [1]*200
5649
5650 class I(int):
5651 def bit_length(self):
5652 return [1]*200
5653
5654 class Z(float):
5655 def as_integer_ratio(self):
5656 return (I(1), I(1))
5657 def __abs__(self):
5658 return self
5659
5660 for cls in X, Y, Z:
5661 self.assertEqual(Decimal.from_float(cls(101.1)),
5662 Decimal.from_float(101.1))
5663
Stefan Krah39dab242020-08-15 20:19:07 +02005664 # Issue 41540:
5665 @unittest.skipIf(sys.platform.startswith("aix"),
5666 "AIX: default ulimit: test is flaky because of extreme over-allocation")
Stefan Krah90930e62020-02-21 01:52:47 +01005667 def test_maxcontext_exact_arith(self):
5668
5669 # Make sure that exact operations do not raise MemoryError due
5670 # to huge intermediate values when the context precision is very
5671 # large.
5672
5673 # The following functions fill the available precision and are
5674 # therefore not suitable for large precisions (by design of the
5675 # specification).
5676 MaxContextSkip = ['logical_invert', 'next_minus', 'next_plus',
5677 'logical_and', 'logical_or', 'logical_xor',
5678 'next_toward', 'rotate', 'shift']
5679
5680 Decimal = C.Decimal
5681 Context = C.Context
5682 localcontext = C.localcontext
5683
5684 # Here only some functions that are likely candidates for triggering a
5685 # MemoryError are tested. deccheck.py has an exhaustive test.
5686 maxcontext = Context(prec=C.MAX_PREC, Emin=C.MIN_EMIN, Emax=C.MAX_EMAX)
5687 with localcontext(maxcontext):
5688 self.assertEqual(Decimal(0).exp(), 1)
5689 self.assertEqual(Decimal(1).ln(), 0)
5690 self.assertEqual(Decimal(1).log10(), 0)
5691 self.assertEqual(Decimal(10**2).log10(), 2)
5692 self.assertEqual(Decimal(10**223).log10(), 223)
5693 self.assertEqual(Decimal(10**19).logb(), 19)
5694 self.assertEqual(Decimal(4).sqrt(), 2)
5695 self.assertEqual(Decimal("40E9").sqrt(), Decimal('2.0E+5'))
5696 self.assertEqual(divmod(Decimal(10), 3), (3, 1))
5697 self.assertEqual(Decimal(10) // 3, 3)
5698 self.assertEqual(Decimal(4) / 2, 2)
5699 self.assertEqual(Decimal(400) ** -1, Decimal('0.0025'))
5700
5701
Stefan Krah6b794b82014-05-01 17:42:33 +02005702@requires_docstrings
5703@unittest.skipUnless(C, "test requires C version")
Stefan Krah5de1f822014-05-01 15:53:42 +02005704class SignatureTest(unittest.TestCase):
5705 """Function signatures"""
5706
5707 def test_inspect_module(self):
5708 for attr in dir(P):
5709 if attr.startswith('_'):
5710 continue
5711 p_func = getattr(P, attr)
5712 c_func = getattr(C, attr)
5713 if (attr == 'Decimal' or attr == 'Context' or
5714 inspect.isfunction(p_func)):
5715 p_sig = inspect.signature(p_func)
5716 c_sig = inspect.signature(c_func)
5717
5718 # parameter names:
5719 c_names = list(c_sig.parameters.keys())
5720 p_names = [x for x in p_sig.parameters.keys() if not
5721 x.startswith('_')]
5722
5723 self.assertEqual(c_names, p_names,
5724 msg="parameter name mismatch in %s" % p_func)
5725
5726 c_kind = [x.kind for x in c_sig.parameters.values()]
5727 p_kind = [x[1].kind for x in p_sig.parameters.items() if not
5728 x[0].startswith('_')]
5729
5730 # parameters:
5731 if attr != 'setcontext':
5732 self.assertEqual(c_kind, p_kind,
5733 msg="parameter kind mismatch in %s" % p_func)
5734
5735 def test_inspect_types(self):
5736
5737 POS = inspect._ParameterKind.POSITIONAL_ONLY
5738 POS_KWD = inspect._ParameterKind.POSITIONAL_OR_KEYWORD
5739
5740 # Type heuristic (type annotations would help!):
5741 pdict = {C: {'other': C.Decimal(1),
5742 'third': C.Decimal(1),
5743 'x': C.Decimal(1),
5744 'y': C.Decimal(1),
5745 'z': C.Decimal(1),
5746 'a': C.Decimal(1),
5747 'b': C.Decimal(1),
5748 'c': C.Decimal(1),
5749 'exp': C.Decimal(1),
5750 'modulo': C.Decimal(1),
5751 'num': "1",
5752 'f': 1.0,
5753 'rounding': C.ROUND_HALF_UP,
5754 'context': C.getcontext()},
5755 P: {'other': P.Decimal(1),
5756 'third': P.Decimal(1),
5757 'a': P.Decimal(1),
5758 'b': P.Decimal(1),
5759 'c': P.Decimal(1),
5760 'exp': P.Decimal(1),
5761 'modulo': P.Decimal(1),
5762 'num': "1",
5763 'f': 1.0,
5764 'rounding': P.ROUND_HALF_UP,
5765 'context': P.getcontext()}}
5766
5767 def mkargs(module, sig):
5768 args = []
5769 kwargs = {}
5770 for name, param in sig.parameters.items():
5771 if name == 'self': continue
5772 if param.kind == POS:
5773 args.append(pdict[module][name])
5774 elif param.kind == POS_KWD:
5775 kwargs[name] = pdict[module][name]
5776 else:
5777 raise TestFailed("unexpected parameter kind")
5778 return args, kwargs
5779
5780 def tr(s):
5781 """The C Context docstrings use 'x' in order to prevent confusion
5782 with the article 'a' in the descriptions."""
5783 if s == 'x': return 'a'
5784 if s == 'y': return 'b'
5785 if s == 'z': return 'c'
5786 return s
5787
5788 def doit(ty):
5789 p_type = getattr(P, ty)
5790 c_type = getattr(C, ty)
5791 for attr in dir(p_type):
5792 if attr.startswith('_'):
5793 continue
5794 p_func = getattr(p_type, attr)
5795 c_func = getattr(c_type, attr)
5796 if inspect.isfunction(p_func):
5797 p_sig = inspect.signature(p_func)
5798 c_sig = inspect.signature(c_func)
5799
5800 # parameter names:
5801 p_names = list(p_sig.parameters.keys())
5802 c_names = [tr(x) for x in c_sig.parameters.keys()]
5803
5804 self.assertEqual(c_names, p_names,
5805 msg="parameter name mismatch in %s" % p_func)
5806
5807 p_kind = [x.kind for x in p_sig.parameters.values()]
5808 c_kind = [x.kind for x in c_sig.parameters.values()]
5809
5810 # 'self' parameter:
5811 self.assertIs(p_kind[0], POS_KWD)
5812 self.assertIs(c_kind[0], POS)
5813
5814 # remaining parameters:
5815 if ty == 'Decimal':
5816 self.assertEqual(c_kind[1:], p_kind[1:],
5817 msg="parameter kind mismatch in %s" % p_func)
5818 else: # Context methods are positional only in the C version.
5819 self.assertEqual(len(c_kind), len(p_kind),
5820 msg="parameter kind mismatch in %s" % p_func)
5821
5822 # Run the function:
5823 args, kwds = mkargs(C, c_sig)
5824 try:
5825 getattr(c_type(9), attr)(*args, **kwds)
Pablo Galindo293dd232019-11-19 21:34:03 +00005826 except Exception:
Stefan Krah5de1f822014-05-01 15:53:42 +02005827 raise TestFailed("invalid signature for %s: %s %s" % (c_func, args, kwds))
5828
5829 args, kwds = mkargs(P, p_sig)
5830 try:
5831 getattr(p_type(9), attr)(*args, **kwds)
Pablo Galindo293dd232019-11-19 21:34:03 +00005832 except Exception:
Stefan Krah5de1f822014-05-01 15:53:42 +02005833 raise TestFailed("invalid signature for %s: %s %s" % (p_func, args, kwds))
5834
5835 doit('Decimal')
5836 doit('Context')
5837
5838
Stefan Krah1919b7e2012-03-21 18:25:23 +01005839all_tests = [
5840 CExplicitConstructionTest, PyExplicitConstructionTest,
5841 CImplicitConstructionTest, PyImplicitConstructionTest,
5842 CFormatTest, PyFormatTest,
5843 CArithmeticOperatorsTest, PyArithmeticOperatorsTest,
5844 CThreadingTest, PyThreadingTest,
5845 CUsabilityTest, PyUsabilityTest,
5846 CPythonAPItests, PyPythonAPItests,
5847 CContextAPItests, PyContextAPItests,
5848 CContextWithStatement, PyContextWithStatement,
5849 CContextFlags, PyContextFlags,
5850 CSpecialContexts, PySpecialContexts,
5851 CContextInputValidation, PyContextInputValidation,
5852 CContextSubclassing, PyContextSubclassing,
5853 CCoverage, PyCoverage,
5854 CFunctionality, PyFunctionality,
5855 CWhitebox, PyWhitebox,
5856 CIBMTestCases, PyIBMTestCases,
5857]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005858
Stefan Krah1919b7e2012-03-21 18:25:23 +01005859# Delete C tests if _decimal.so is not present.
5860if not C:
5861 all_tests = all_tests[1::2]
5862else:
5863 all_tests.insert(0, CheckAttributes)
Stefan Krah5de1f822014-05-01 15:53:42 +02005864 all_tests.insert(1, SignatureTest)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005865
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005866
Zachary Ware66f29282014-06-02 16:01:29 -05005867def test_main(arith=None, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005868 """ Execute the tests.
5869
Raymond Hettingered20ad82004-09-04 20:09:13 +00005870 Runs all arithmetic tests if arith is True or if the "decimal" resource
5871 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005872 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00005873
Stefan Krah1919b7e2012-03-21 18:25:23 +01005874 init(C)
5875 init(P)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005876 global TEST_ALL, DEBUG
Zachary Ware66f29282014-06-02 16:01:29 -05005877 TEST_ALL = arith if arith is not None else is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005878 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00005879
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005880 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005881 test_classes = all_tests
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005882 else:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005883 test_classes = [CIBMTestCases, PyIBMTestCases]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005884
5885 # Dynamically build custom test definition for each file in the test
5886 # directory and add the definitions to the DecimalTest class. This
5887 # procedure insures that new files do not get skipped.
5888 for filename in os.listdir(directory):
5889 if '.decTest' not in filename or filename.startswith("."):
5890 continue
5891 head, tail = filename.split('.')
5892 if todo_tests is not None and head not in todo_tests:
5893 continue
5894 tester = lambda self, f=filename: self.eval_file(directory + f)
Stefan Krah1919b7e2012-03-21 18:25:23 +01005895 setattr(CIBMTestCases, 'test_' + head, tester)
5896 setattr(PyIBMTestCases, 'test_' + head, tester)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005897 del filename, head, tail, tester
5898
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005899
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005900 try:
5901 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005902 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005903 from doctest import IGNORE_EXCEPTION_DETAIL
5904 savedecimal = sys.modules['decimal']
5905 if C:
5906 sys.modules['decimal'] = C
5907 run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL)
5908 sys.modules['decimal'] = P
5909 run_doctest(P, verbose)
5910 sys.modules['decimal'] = savedecimal
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005911 finally:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005912 if C: C.setcontext(ORIGINAL_CONTEXT[C])
5913 P.setcontext(ORIGINAL_CONTEXT[P])
5914 if not C:
5915 warnings.warn('C tests skipped: no module named _decimal.',
5916 UserWarning)
5917 if not orig_sys_decimal is sys.modules['decimal']:
5918 raise TestFailed("Internal error: unbalanced number of changes to "
5919 "sys.modules['decimal'].")
5920
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005921
5922if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005923 import optparse
5924 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
5925 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
5926 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
5927 (opt, args) = p.parse_args()
5928
5929 if opt.skip:
5930 test_main(arith=False, verbose=True)
5931 elif args:
5932 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005933 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005934 test_main(arith=True, verbose=True)