blob: 6aa4a9b31a5f246c94df72705dc00beff1d58b38 [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
Raymond Hettingerfed52962004-07-14 15:41:57 +000046
Stefan Krah1919b7e2012-03-21 18:25:23 +010047C = import_fresh_module('decimal', fresh=['_decimal'])
48P = import_fresh_module('decimal', blocked=['_decimal'])
49orig_sys_decimal = sys.modules['decimal']
50
51# fractions module must import the correct decimal module.
52cfractions = import_fresh_module('fractions', fresh=['fractions'])
53sys.modules['decimal'] = P
54pfractions = import_fresh_module('fractions', fresh=['fractions'])
55sys.modules['decimal'] = C
56fractions = {C:cfractions, P:pfractions}
57sys.modules['decimal'] = orig_sys_decimal
58
59
60# Useful Test Constant
61Signals = {
62 C: tuple(C.getcontext().flags.keys()) if C else None,
63 P: tuple(P.getcontext().flags.keys())
64}
Mark Dickinsonc69160e2010-05-04 14:35:33 +000065# Signals ordered with respect to precedence: when an operation
66# produces multiple signals, signals occurring later in the list
67# should be handled before those occurring earlier in the list.
Stefan Krah1919b7e2012-03-21 18:25:23 +010068OrderedSignals = {
69 C: [C.Clamped, C.Rounded, C.Inexact, C.Subnormal, C.Underflow,
70 C.Overflow, C.DivisionByZero, C.InvalidOperation,
71 C.FloatOperation] if C else None,
72 P: [P.Clamped, P.Rounded, P.Inexact, P.Subnormal, P.Underflow,
73 P.Overflow, P.DivisionByZero, P.InvalidOperation,
74 P.FloatOperation]
75}
76def assert_signals(cls, context, attr, expected):
77 d = getattr(context, attr)
78 cls.assertTrue(all(d[s] if s in expected else not d[s] for s in d))
79
Stefan Krah59a4a932013-01-16 12:58:59 +010080ROUND_UP = P.ROUND_UP
81ROUND_DOWN = P.ROUND_DOWN
82ROUND_CEILING = P.ROUND_CEILING
83ROUND_FLOOR = P.ROUND_FLOOR
84ROUND_HALF_UP = P.ROUND_HALF_UP
85ROUND_HALF_DOWN = P.ROUND_HALF_DOWN
86ROUND_HALF_EVEN = P.ROUND_HALF_EVEN
87ROUND_05UP = P.ROUND_05UP
88
89RoundingModes = [
90 ROUND_UP, ROUND_DOWN, ROUND_CEILING, ROUND_FLOOR,
91 ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN,
92 ROUND_05UP
93]
Mark Dickinsonc69160e2010-05-04 14:35:33 +000094
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000095# Tests are built around these assumed context defaults.
96# test_main() restores the original context.
Stefan Krah1919b7e2012-03-21 18:25:23 +010097ORIGINAL_CONTEXT = {
98 C: C.getcontext().copy() if C else None,
99 P: P.getcontext().copy()
100}
101def init(m):
102 if not m: return
103 DefaultTestContext = m.Context(
Stefan Krah59a4a932013-01-16 12:58:59 +0100104 prec=9, rounding=ROUND_HALF_EVEN, traps=dict.fromkeys(Signals[m], 0)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100105 )
106 m.setcontext(DefaultTestContext)
Raymond Hettinger6ea48452004-07-03 12:26:21 +0000107
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000108TESTDATADIR = 'decimaltestdata'
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +0000109if __name__ == '__main__':
110 file = sys.argv[0]
111else:
112 file = __file__
113testdir = os.path.dirname(file) or os.curdir
Raymond Hettinger267b8682005-03-27 10:47:39 +0000114directory = testdir + os.sep + TESTDATADIR + os.sep
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000115
Raymond Hettinger267b8682005-03-27 10:47:39 +0000116skip_expected = not os.path.isdir(directory)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000117
118# Make sure it actually raises errors when not expected and caught in flags
119# Slower, since it runs some things several times.
120EXTENDEDERRORTEST = False
121
Stefan Krah1919b7e2012-03-21 18:25:23 +0100122# Test extra functionality in the C version (-DEXTRA_FUNCTIONALITY).
123EXTRA_FUNCTIONALITY = True if hasattr(C, 'DecClamped') else False
124requires_extra_functionality = unittest.skipUnless(
125 EXTRA_FUNCTIONALITY, "test requires build with -DEXTRA_FUNCTIONALITY")
126skip_if_extra_functionality = unittest.skipIf(
127 EXTRA_FUNCTIONALITY, "test requires regular build")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000128
129
Stefan Krah1919b7e2012-03-21 18:25:23 +0100130class IBMTestCases(unittest.TestCase):
131 """Class which tests the Decimal class against the IBM test cases."""
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000132
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000133 def setUp(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100134 self.context = self.decimal.Context()
135 self.readcontext = self.decimal.Context()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000136 self.ignore_list = ['#']
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000137
Stefan Krah1919b7e2012-03-21 18:25:23 +0100138 # List of individual .decTest test ids that correspond to tests that
139 # we're skipping for one reason or another.
140 self.skipped_test_ids = set([
141 # Skip implementation-specific scaleb tests.
142 'scbx164',
143 'scbx165',
144
145 # For some operations (currently exp, ln, log10, power), the decNumber
146 # reference implementation imposes additional restrictions on the context
147 # and operands. These restrictions are not part of the specification;
148 # however, the effect of these restrictions does show up in some of the
149 # testcases. We skip testcases that violate these restrictions, since
150 # Decimal behaves differently from decNumber for these testcases so these
151 # testcases would otherwise fail.
152 'expx901',
153 'expx902',
154 'expx903',
155 'expx905',
156 'lnx901',
157 'lnx902',
158 'lnx903',
159 'lnx905',
160 'logx901',
161 'logx902',
162 'logx903',
163 'logx905',
164 'powx1183',
165 'powx1184',
166 'powx4001',
167 'powx4002',
168 'powx4003',
169 'powx4005',
170 'powx4008',
171 'powx4010',
172 'powx4012',
173 'powx4014',
174 ])
175
176 if self.decimal == C:
177 # status has additional Subnormal, Underflow
178 self.skipped_test_ids.add('pwsx803')
179 self.skipped_test_ids.add('pwsx805')
180 # Correct rounding (skipped for decNumber, too)
181 self.skipped_test_ids.add('powx4302')
182 self.skipped_test_ids.add('powx4303')
183 self.skipped_test_ids.add('powx4342')
184 self.skipped_test_ids.add('powx4343')
185 # http://bugs.python.org/issue7049
186 self.skipped_test_ids.add('pwmx325')
187 self.skipped_test_ids.add('pwmx326')
188
189 # Map test directives to setter functions.
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000190 self.ChangeDict = {'precision' : self.change_precision,
Stefan Krah1919b7e2012-03-21 18:25:23 +0100191 'rounding' : self.change_rounding_method,
192 'maxexponent' : self.change_max_exponent,
193 'minexponent' : self.change_min_exponent,
194 'clamp' : self.change_clamp}
195
196 # Name adapter to be able to change the Decimal and Context
197 # interface without changing the test files from Cowlishaw.
198 self.NameAdapter = {'and':'logical_and',
199 'apply':'_apply',
200 'class':'number_class',
201 'comparesig':'compare_signal',
202 'comparetotal':'compare_total',
203 'comparetotmag':'compare_total_mag',
204 'copy':'copy_decimal',
205 'copyabs':'copy_abs',
206 'copynegate':'copy_negate',
207 'copysign':'copy_sign',
208 'divideint':'divide_int',
209 'invert':'logical_invert',
210 'iscanonical':'is_canonical',
211 'isfinite':'is_finite',
212 'isinfinite':'is_infinite',
213 'isnan':'is_nan',
214 'isnormal':'is_normal',
215 'isqnan':'is_qnan',
216 'issigned':'is_signed',
217 'issnan':'is_snan',
218 'issubnormal':'is_subnormal',
219 'iszero':'is_zero',
220 'maxmag':'max_mag',
221 'minmag':'min_mag',
222 'nextminus':'next_minus',
223 'nextplus':'next_plus',
224 'nexttoward':'next_toward',
225 'or':'logical_or',
226 'reduce':'normalize',
227 'remaindernear':'remainder_near',
228 'samequantum':'same_quantum',
229 'squareroot':'sqrt',
230 'toeng':'to_eng_string',
231 'tointegral':'to_integral_value',
232 'tointegralx':'to_integral_exact',
233 'tosci':'to_sci_string',
234 'xor':'logical_xor'}
235
236 # Map test-case names to roundings.
Stefan Krah59a4a932013-01-16 12:58:59 +0100237 self.RoundingDict = {'ceiling' : ROUND_CEILING,
238 'down' : ROUND_DOWN,
239 'floor' : ROUND_FLOOR,
240 'half_down' : ROUND_HALF_DOWN,
241 'half_even' : ROUND_HALF_EVEN,
242 'half_up' : ROUND_HALF_UP,
243 'up' : ROUND_UP,
244 '05up' : ROUND_05UP}
Stefan Krah1919b7e2012-03-21 18:25:23 +0100245
246 # Map the test cases' error names to the actual errors.
247 self.ErrorNames = {'clamped' : self.decimal.Clamped,
248 'conversion_syntax' : self.decimal.InvalidOperation,
249 'division_by_zero' : self.decimal.DivisionByZero,
250 'division_impossible' : self.decimal.InvalidOperation,
251 'division_undefined' : self.decimal.InvalidOperation,
252 'inexact' : self.decimal.Inexact,
253 'invalid_context' : self.decimal.InvalidOperation,
254 'invalid_operation' : self.decimal.InvalidOperation,
255 'overflow' : self.decimal.Overflow,
256 'rounded' : self.decimal.Rounded,
257 'subnormal' : self.decimal.Subnormal,
258 'underflow' : self.decimal.Underflow}
259
260 # The following functions return True/False rather than a
261 # Decimal instance.
262 self.LogicalFunctions = ('is_canonical',
263 'is_finite',
264 'is_infinite',
265 'is_nan',
266 'is_normal',
267 'is_qnan',
268 'is_signed',
269 'is_snan',
270 'is_subnormal',
271 'is_zero',
272 'same_quantum')
273
274 def read_unlimited(self, v, context):
275 """Work around the limitations of the 32-bit _decimal version. The
276 guaranteed maximum values for prec, Emax etc. are 425000000,
277 but higher values usually work, except for rare corner cases.
278 In particular, all of the IBM tests pass with maximum values
279 of 1070000000."""
280 if self.decimal == C and self.decimal.MAX_EMAX == 425000000:
281 self.readcontext._unsafe_setprec(1070000000)
282 self.readcontext._unsafe_setemax(1070000000)
283 self.readcontext._unsafe_setemin(-1070000000)
284 return self.readcontext.create_decimal(v)
285 else:
286 return self.decimal.Decimal(v, context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000287
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000288 def eval_file(self, file):
289 global skip_expected
290 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +0000291 raise unittest.SkipTest
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000292 with open(file) as f:
293 for line in f:
294 line = line.replace('\r\n', '').replace('\n', '')
295 #print line
296 try:
297 t = self.eval_line(line)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100298 except self.decimal.DecimalException as exception:
Ezio Melotti13925002011-03-16 11:05:33 +0200299 #Exception raised where there shouldn't have been one.
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000300 self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000301
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000302
303 def eval_line(self, s):
304 if s.find(' -> ') >= 0 and s[:2] != '--' and not s.startswith(' --'):
305 s = (s.split('->')[0] + '->' +
306 s.split('->')[1].split('--')[0]).strip()
307 else:
308 s = s.split('--')[0].strip()
309
310 for ignore in self.ignore_list:
311 if s.find(ignore) >= 0:
312 #print s.split()[0], 'NotImplemented--', ignore
313 return
314 if not s:
315 return
316 elif ':' in s:
317 return self.eval_directive(s)
318 else:
319 return self.eval_equation(s)
320
321 def eval_directive(self, s):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000322 funct, value = (x.strip().lower() for x in s.split(':'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000323 if funct == 'rounding':
Stefan Krah1919b7e2012-03-21 18:25:23 +0100324 value = self.RoundingDict[value]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000325 else:
326 try:
327 value = int(value)
328 except ValueError:
329 pass
330
Stefan Krah1919b7e2012-03-21 18:25:23 +0100331 funct = self.ChangeDict.get(funct, (lambda *args: None))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000332 funct(value)
333
334 def eval_equation(self, s):
Raymond Hettingered20ad82004-09-04 20:09:13 +0000335
336 if not TEST_ALL and random.random() < 0.90:
337 return
338
Stefan Krah1919b7e2012-03-21 18:25:23 +0100339 self.context.clear_flags()
340
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000341 try:
342 Sides = s.split('->')
343 L = Sides[0].strip().split()
344 id = L[0]
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000345 if DEBUG:
346 print("Test ", id, end=" ")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000347 funct = L[1].lower()
348 valstemp = L[2:]
349 L = Sides[1].strip().split()
350 ans = L[0]
351 exceptions = L[1:]
352 except (TypeError, AttributeError, IndexError):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100353 raise self.decimal.InvalidOperation
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000354 def FixQuotes(val):
355 val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
356 val = val.replace("'", '').replace('"', '')
357 val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
358 return val
Mark Dickinson8a546532009-10-08 16:30:38 +0000359
Stefan Krah1919b7e2012-03-21 18:25:23 +0100360 if id in self.skipped_test_ids:
Mark Dickinson8a546532009-10-08 16:30:38 +0000361 return
362
Stefan Krah1919b7e2012-03-21 18:25:23 +0100363 fname = self.NameAdapter.get(funct, funct)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000364 if fname == 'rescale':
365 return
366 funct = getattr(self.context, fname)
367 vals = []
368 conglomerate = ''
369 quote = 0
Stefan Krah1919b7e2012-03-21 18:25:23 +0100370 theirexceptions = [self.ErrorNames[x.lower()] for x in exceptions]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000371
Stefan Krah1919b7e2012-03-21 18:25:23 +0100372 for exception in Signals[self.decimal]:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000373 self.context.traps[exception] = 1 #Catch these bugs...
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000374 for exception in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000375 self.context.traps[exception] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000376 for i, val in enumerate(valstemp):
377 if val.count("'") % 2 == 1:
378 quote = 1 - quote
379 if quote:
380 conglomerate = conglomerate + ' ' + val
381 continue
382 else:
383 val = conglomerate + val
384 conglomerate = ''
385 v = FixQuotes(val)
386 if fname in ('to_sci_string', 'to_eng_string'):
387 if EXTENDEDERRORTEST:
388 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000389 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000390 try:
391 funct(self.context.create_decimal(v))
392 except error:
393 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100394 except Signals[self.decimal] as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000395 self.fail("Raised %s in %s when %s disabled" % \
396 (e, s, error))
397 else:
398 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000399 self.context.traps[error] = 0
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000400 v = self.context.create_decimal(v)
401 else:
Stefan Krah1919b7e2012-03-21 18:25:23 +0100402 v = self.read_unlimited(v, self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000403 vals.append(v)
404
405 ans = FixQuotes(ans)
406
407 if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
408 for error in theirexceptions:
Raymond Hettingerbf440692004-07-10 14:14:37 +0000409 self.context.traps[error] = 1
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000410 try:
411 funct(*vals)
412 except error:
413 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100414 except Signals[self.decimal] as e:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000415 self.fail("Raised %s in %s when %s disabled" % \
416 (e, s, error))
417 else:
418 self.fail("Did not raise %s in %s" % (error, s))
Raymond Hettingerbf440692004-07-10 14:14:37 +0000419 self.context.traps[error] = 0
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000420
421 # as above, but add traps cumulatively, to check precedence
Stefan Krah1919b7e2012-03-21 18:25:23 +0100422 ordered_errors = [e for e in OrderedSignals[self.decimal] if e in theirexceptions]
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000423 for error in ordered_errors:
424 self.context.traps[error] = 1
425 try:
426 funct(*vals)
427 except error:
428 pass
Stefan Krah1919b7e2012-03-21 18:25:23 +0100429 except Signals[self.decimal] as e:
Mark Dickinsonc69160e2010-05-04 14:35:33 +0000430 self.fail("Raised %s in %s; expected %s" %
431 (type(e), s, error))
432 else:
433 self.fail("Did not raise %s in %s" % (error, s))
434 # reset traps
435 for error in ordered_errors:
436 self.context.traps[error] = 0
437
438
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000439 if DEBUG:
440 print("--", self.context)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000441 try:
442 result = str(funct(*vals))
Stefan Krah1919b7e2012-03-21 18:25:23 +0100443 if fname in self.LogicalFunctions:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000444 result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
Stefan Krah1919b7e2012-03-21 18:25:23 +0100445 except Signals[self.decimal] as error:
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000446 self.fail("Raised %s in %s" % (error, s))
447 except: #Catch any error long enough to state the test case.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000448 print("ERROR:", s)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000449 raise
450
451 myexceptions = self.getexceptions()
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000452
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000453 myexceptions.sort(key=repr)
454 theirexceptions.sort(key=repr)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000455
456 self.assertEqual(result, ans,
457 'Incorrect answer for ' + s + ' -- got ' + result)
Stefan Krah1919b7e2012-03-21 18:25:23 +0100458
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000459 self.assertEqual(myexceptions, theirexceptions,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000460 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000461
462 def getexceptions(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100463 return [e for e in Signals[self.decimal] if self.context.flags[e]]
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000464
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000465 def change_precision(self, prec):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100466 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
467 self.context._unsafe_setprec(prec)
468 else:
469 self.context.prec = prec
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000470 def change_rounding_method(self, rounding):
471 self.context.rounding = rounding
472 def change_min_exponent(self, exp):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100473 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
474 self.context._unsafe_setemin(exp)
475 else:
476 self.context.Emin = exp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000477 def change_max_exponent(self, exp):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100478 if self.decimal == C and self.decimal.MAX_PREC == 425000000:
479 self.context._unsafe_setemax(exp)
480 else:
481 self.context.Emax = exp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000482 def change_clamp(self, clamp):
Mark Dickinsonb1d8e322010-05-22 18:35:36 +0000483 self.context.clamp = clamp
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000484
Stefan Krah1919b7e2012-03-21 18:25:23 +0100485class CIBMTestCases(IBMTestCases):
486 decimal = C
487class PyIBMTestCases(IBMTestCases):
488 decimal = P
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000489
490# The following classes test the behaviour of Decimal according to PEP 327
491
Stefan Krah1919b7e2012-03-21 18:25:23 +0100492class ExplicitConstructionTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000493 '''Unit tests for Explicit Construction cases of Decimal.'''
494
495 def test_explicit_empty(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100496 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000497 self.assertEqual(Decimal(), Decimal("0"))
498
499 def test_explicit_from_None(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100500 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000501 self.assertRaises(TypeError, Decimal, None)
502
503 def test_explicit_from_int(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100504 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000505
506 #positive
507 d = Decimal(45)
508 self.assertEqual(str(d), '45')
509
510 #very large positive
511 d = Decimal(500000123)
512 self.assertEqual(str(d), '500000123')
513
514 #negative
515 d = Decimal(-45)
516 self.assertEqual(str(d), '-45')
517
518 #zero
519 d = Decimal(0)
520 self.assertEqual(str(d), '0')
521
Stefan Krah1919b7e2012-03-21 18:25:23 +0100522 # single word longs
523 for n in range(0, 32):
524 for sign in (-1, 1):
525 for x in range(-5, 5):
526 i = sign * (2**n + x)
527 d = Decimal(i)
528 self.assertEqual(str(d), str(i))
529
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000530 def test_explicit_from_string(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100531 Decimal = self.decimal.Decimal
532 InvalidOperation = self.decimal.InvalidOperation
533 localcontext = self.decimal.localcontext
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000534
535 #empty
536 self.assertEqual(str(Decimal('')), 'NaN')
537
538 #int
539 self.assertEqual(str(Decimal('45')), '45')
540
541 #float
542 self.assertEqual(str(Decimal('45.34')), '45.34')
543
544 #engineer notation
545 self.assertEqual(str(Decimal('45e2')), '4.5E+3')
546
547 #just not a number
548 self.assertEqual(str(Decimal('ugly')), 'NaN')
549
Christian Heimesa62da1d2008-01-12 19:39:10 +0000550 #leading and trailing whitespace permitted
551 self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
552 self.assertEqual(str(Decimal(' -7.89')), '-7.89')
Stefan Krah1919b7e2012-03-21 18:25:23 +0100553 self.assertEqual(str(Decimal(" 3.45679 ")), '3.45679')
554
Brett Cannona721aba2016-09-09 14:57:09 -0700555 # underscores
556 self.assertEqual(str(Decimal('1_3.3e4_0')), '1.33E+41')
557 self.assertEqual(str(Decimal('1_0_0_0')), '1000')
558
Stefan Krah1919b7e2012-03-21 18:25:23 +0100559 # unicode whitespace
560 for lead in ["", ' ', '\u00a0', '\u205f']:
561 for trail in ["", ' ', '\u00a0', '\u205f']:
562 self.assertEqual(str(Decimal(lead + '9.311E+28' + trail)),
563 '9.311E+28')
564
565 with localcontext() as c:
566 c.traps[InvalidOperation] = True
567 # Invalid string
568 self.assertRaises(InvalidOperation, Decimal, "xyz")
569 # Two arguments max
570 self.assertRaises(TypeError, Decimal, "1234", "x", "y")
571
572 # space within the numeric part
573 self.assertRaises(InvalidOperation, Decimal, "1\u00a02\u00a03")
574 self.assertRaises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0")
575
576 # unicode whitespace
577 self.assertRaises(InvalidOperation, Decimal, "\u00a0")
578 self.assertRaises(InvalidOperation, Decimal, "\u00a0\u00a0")
579
580 # embedded NUL
581 self.assertRaises(InvalidOperation, Decimal, "12\u00003")
582
Brett Cannona721aba2016-09-09 14:57:09 -0700583 # underscores don't prevent errors
584 self.assertRaises(InvalidOperation, Decimal, "1_2_\u00003")
585
Stefan Krah6e467042012-11-10 23:09:04 +0100586 @cpython_only
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +0300587 @requires_legacy_unicode_capi
Inada Naoki902356a2020-07-20 12:02:50 +0900588 @warnings_helper.ignore_warnings(category=DeprecationWarning)
Stefan Krah6e467042012-11-10 23:09:04 +0100589 def test_from_legacy_strings(self):
590 import _testcapi
591 Decimal = self.decimal.Decimal
592 context = self.decimal.Context()
593
594 s = _testcapi.unicode_legacy_string('9.999999')
595 self.assertEqual(str(Decimal(s)), '9.999999')
596 self.assertEqual(str(context.create_decimal(s)), '9.999999')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000597
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000598 def test_explicit_from_tuples(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100599 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000600
601 #zero
602 d = Decimal( (0, (0,), 0) )
603 self.assertEqual(str(d), '0')
604
605 #int
606 d = Decimal( (1, (4, 5), 0) )
607 self.assertEqual(str(d), '-45')
608
609 #float
610 d = Decimal( (0, (4, 5, 3, 4), -2) )
611 self.assertEqual(str(d), '45.34')
612
613 #weird
614 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
615 self.assertEqual(str(d), '-4.34913534E-17')
616
Stefan Krah1919b7e2012-03-21 18:25:23 +0100617 #inf
618 d = Decimal( (0, (), "F") )
619 self.assertEqual(str(d), 'Infinity')
620
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000621 #wrong number of items
622 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
623
624 #bad sign
625 self.assertRaises(ValueError, Decimal, (8, (4, 3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000626 self.assertRaises(ValueError, Decimal, (0., (4, 3, 4, 9, 1), 2) )
627 self.assertRaises(ValueError, Decimal, (Decimal(1), (4, 3, 4, 9, 1), 2))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000628
629 #bad exp
630 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 'wrong!') )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000631 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), 0.) )
632 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000633
634 #bad coefficients
Stefan Krah1919b7e2012-03-21 18:25:23 +0100635 self.assertRaises(ValueError, Decimal, (1, "xyz", 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000636 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
637 self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000638 self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
Guido van Rossum0d3fb8a2007-11-26 23:23:18 +0000639 self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000640
Stefan Krah1919b7e2012-03-21 18:25:23 +0100641 def test_explicit_from_list(self):
642 Decimal = self.decimal.Decimal
643
644 d = Decimal([0, [0], 0])
645 self.assertEqual(str(d), '0')
646
647 d = Decimal([1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25])
648 self.assertEqual(str(d), '-4.34913534E-17')
649
650 d = Decimal([1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25])
651 self.assertEqual(str(d), '-4.34913534E-17')
652
653 d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25))
654 self.assertEqual(str(d), '-4.34913534E-17')
655
Antoine Pitrou503ab332010-03-30 18:56:19 +0000656 def test_explicit_from_bool(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100657 Decimal = self.decimal.Decimal
658
Antoine Pitrou503ab332010-03-30 18:56:19 +0000659 self.assertIs(bool(Decimal(0)), False)
660 self.assertIs(bool(Decimal(1)), True)
661 self.assertEqual(Decimal(False), Decimal(0))
662 self.assertEqual(Decimal(True), Decimal(1))
663
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000664 def test_explicit_from_Decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100665 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000666
667 #positive
668 d = Decimal(45)
669 e = Decimal(d)
670 self.assertEqual(str(e), '45')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000671
672 #very large positive
673 d = Decimal(500000123)
674 e = Decimal(d)
675 self.assertEqual(str(e), '500000123')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000676
677 #negative
678 d = Decimal(-45)
679 e = Decimal(d)
680 self.assertEqual(str(e), '-45')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000681
682 #zero
683 d = Decimal(0)
684 e = Decimal(d)
685 self.assertEqual(str(e), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000686
Raymond Hettinger96798592010-04-02 16:58:27 +0000687 @requires_IEEE_754
688 def test_explicit_from_float(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100689
690 Decimal = self.decimal.Decimal
691
Raymond Hettinger96798592010-04-02 16:58:27 +0000692 r = Decimal(0.1)
693 self.assertEqual(type(r), Decimal)
694 self.assertEqual(str(r),
695 '0.1000000000000000055511151231257827021181583404541015625')
696 self.assertTrue(Decimal(float('nan')).is_qnan())
697 self.assertTrue(Decimal(float('inf')).is_infinite())
698 self.assertTrue(Decimal(float('-inf')).is_infinite())
699 self.assertEqual(str(Decimal(float('nan'))),
700 str(Decimal('NaN')))
701 self.assertEqual(str(Decimal(float('inf'))),
702 str(Decimal('Infinity')))
703 self.assertEqual(str(Decimal(float('-inf'))),
704 str(Decimal('-Infinity')))
705 self.assertEqual(str(Decimal(float('-0.0'))),
706 str(Decimal('-0')))
707 for i in range(200):
708 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
709 self.assertEqual(x, float(Decimal(x))) # roundtrip
710
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000711 def test_explicit_context_create_decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100712 Decimal = self.decimal.Decimal
713 InvalidOperation = self.decimal.InvalidOperation
714 Rounded = self.decimal.Rounded
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000715
Stefan Krah1919b7e2012-03-21 18:25:23 +0100716 nc = copy.copy(self.decimal.getcontext())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000717 nc.prec = 3
718
719 # empty
Raymond Hettingerfed52962004-07-14 15:41:57 +0000720 d = Decimal()
721 self.assertEqual(str(d), '0')
722 d = nc.create_decimal()
723 self.assertEqual(str(d), '0')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000724
725 # from None
726 self.assertRaises(TypeError, nc.create_decimal, None)
727
728 # from int
729 d = nc.create_decimal(456)
Ezio Melottie9615932010-01-24 19:26:24 +0000730 self.assertIsInstance(d, Decimal)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000731 self.assertEqual(nc.create_decimal(45678),
732 nc.create_decimal('457E+2'))
733
734 # from string
735 d = Decimal('456789')
736 self.assertEqual(str(d), '456789')
737 d = nc.create_decimal('456789')
738 self.assertEqual(str(d), '4.57E+5')
Christian Heimesa62da1d2008-01-12 19:39:10 +0000739 # leading and trailing whitespace should result in a NaN;
740 # spaces are already checked in Cowlishaw's test-suite, so
741 # here we just check that a trailing newline results in a NaN
742 self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000743
744 # from tuples
745 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
746 self.assertEqual(str(d), '-4.34913534E-17')
747 d = nc.create_decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
748 self.assertEqual(str(d), '-4.35E-17')
749
750 # from Decimal
751 prevdec = Decimal(500000123)
752 d = Decimal(prevdec)
753 self.assertEqual(str(d), '500000123')
754 d = nc.create_decimal(prevdec)
755 self.assertEqual(str(d), '5.00E+8')
756
Stefan Krah1919b7e2012-03-21 18:25:23 +0100757 # more integers
758 nc.prec = 28
759 nc.traps[InvalidOperation] = True
760
761 for v in [-2**63-1, -2**63, -2**31-1, -2**31, 0,
762 2**31-1, 2**31, 2**63-1, 2**63]:
763 d = nc.create_decimal(v)
764 self.assertTrue(isinstance(d, Decimal))
765 self.assertEqual(int(d), v)
766
767 nc.prec = 3
768 nc.traps[Rounded] = True
769 self.assertRaises(Rounded, nc.create_decimal, 1234)
770
771 # from string
772 nc.prec = 28
773 self.assertEqual(str(nc.create_decimal('0E-017')), '0E-17')
774 self.assertEqual(str(nc.create_decimal('45')), '45')
775 self.assertEqual(str(nc.create_decimal('-Inf')), '-Infinity')
776 self.assertEqual(str(nc.create_decimal('NaN123')), 'NaN123')
777
778 # invalid arguments
779 self.assertRaises(InvalidOperation, nc.create_decimal, "xyz")
780 self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25))
781 self.assertRaises(TypeError, nc.create_decimal, "1234", "5678")
Brett Cannona721aba2016-09-09 14:57:09 -0700782 # no whitespace and underscore stripping is done with this method
783 self.assertRaises(InvalidOperation, nc.create_decimal, " 1234")
784 self.assertRaises(InvalidOperation, nc.create_decimal, "12_34")
Stefan Krah1919b7e2012-03-21 18:25:23 +0100785
786 # too many NaN payload digits
787 nc.prec = 3
788 self.assertRaises(InvalidOperation, nc.create_decimal, 'NaN12345')
789 self.assertRaises(InvalidOperation, nc.create_decimal,
790 Decimal('NaN12345'))
791
792 nc.traps[InvalidOperation] = False
793 self.assertEqual(str(nc.create_decimal('NaN12345')), 'NaN')
794 self.assertTrue(nc.flags[InvalidOperation])
795
796 nc.flags[InvalidOperation] = False
797 self.assertEqual(str(nc.create_decimal(Decimal('NaN12345'))), 'NaN')
798 self.assertTrue(nc.flags[InvalidOperation])
799
800 def test_explicit_context_create_from_float(self):
801
802 Decimal = self.decimal.Decimal
803
804 nc = self.decimal.Context()
805 r = nc.create_decimal(0.1)
806 self.assertEqual(type(r), Decimal)
807 self.assertEqual(str(r), '0.1000000000000000055511151231')
808 self.assertTrue(nc.create_decimal(float('nan')).is_qnan())
809 self.assertTrue(nc.create_decimal(float('inf')).is_infinite())
810 self.assertTrue(nc.create_decimal(float('-inf')).is_infinite())
811 self.assertEqual(str(nc.create_decimal(float('nan'))),
812 str(nc.create_decimal('NaN')))
813 self.assertEqual(str(nc.create_decimal(float('inf'))),
814 str(nc.create_decimal('Infinity')))
815 self.assertEqual(str(nc.create_decimal(float('-inf'))),
816 str(nc.create_decimal('-Infinity')))
817 self.assertEqual(str(nc.create_decimal(float('-0.0'))),
818 str(nc.create_decimal('-0')))
819 nc.prec = 100
820 for i in range(200):
821 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
822 self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip
823
Mark Dickinson345adc42009-08-02 10:14:23 +0000824 def test_unicode_digits(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100825 Decimal = self.decimal.Decimal
826
Mark Dickinson345adc42009-08-02 10:14:23 +0000827 test_values = {
828 '\uff11': '1',
829 '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
830 '-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
831 }
832 for input, expected in test_values.items():
833 self.assertEqual(str(Decimal(input)), expected)
834
Stefan Krah1919b7e2012-03-21 18:25:23 +0100835class CExplicitConstructionTest(ExplicitConstructionTest):
836 decimal = C
837class PyExplicitConstructionTest(ExplicitConstructionTest):
838 decimal = P
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000839
Stefan Krah1919b7e2012-03-21 18:25:23 +0100840class ImplicitConstructionTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000841 '''Unit tests for Implicit Construction cases of Decimal.'''
842
843 def test_implicit_from_None(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100844 Decimal = self.decimal.Decimal
845 self.assertRaises(TypeError, eval, 'Decimal(5) + None', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000846
847 def test_implicit_from_int(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100848 Decimal = self.decimal.Decimal
849
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000850 #normal
851 self.assertEqual(str(Decimal(5) + 45), '50')
852 #exceeding precision
853 self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
854
855 def test_implicit_from_string(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100856 Decimal = self.decimal.Decimal
857 self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000858
859 def test_implicit_from_float(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100860 Decimal = self.decimal.Decimal
861 self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', locals())
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000862
863 def test_implicit_from_Decimal(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100864 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000865 self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
866
Raymond Hettinger267b8682005-03-27 10:47:39 +0000867 def test_rop(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100868 Decimal = self.decimal.Decimal
869
Raymond Hettinger267b8682005-03-27 10:47:39 +0000870 # Allow other classes to be trained to interact with Decimals
871 class E:
872 def __divmod__(self, other):
873 return 'divmod ' + str(other)
874 def __rdivmod__(self, other):
875 return str(other) + ' rdivmod'
876 def __lt__(self, other):
877 return 'lt ' + str(other)
878 def __gt__(self, other):
879 return 'gt ' + str(other)
880 def __le__(self, other):
881 return 'le ' + str(other)
882 def __ge__(self, other):
883 return 'ge ' + str(other)
884 def __eq__(self, other):
885 return 'eq ' + str(other)
886 def __ne__(self, other):
887 return 'ne ' + str(other)
888
889 self.assertEqual(divmod(E(), Decimal(10)), 'divmod 10')
890 self.assertEqual(divmod(Decimal(10), E()), '10 rdivmod')
891 self.assertEqual(eval('Decimal(10) < E()'), 'gt 10')
892 self.assertEqual(eval('Decimal(10) > E()'), 'lt 10')
893 self.assertEqual(eval('Decimal(10) <= E()'), 'ge 10')
894 self.assertEqual(eval('Decimal(10) >= E()'), 'le 10')
895 self.assertEqual(eval('Decimal(10) == E()'), 'eq 10')
896 self.assertEqual(eval('Decimal(10) != E()'), 'ne 10')
897
898 # insert operator methods and then exercise them
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000899 oplist = [
900 ('+', '__add__', '__radd__'),
901 ('-', '__sub__', '__rsub__'),
902 ('*', '__mul__', '__rmul__'),
Thomas Woutersdcc6d322006-04-21 11:30:52 +0000903 ('/', '__truediv__', '__rtruediv__'),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000904 ('%', '__mod__', '__rmod__'),
905 ('//', '__floordiv__', '__rfloordiv__'),
906 ('**', '__pow__', '__rpow__')
907 ]
Raymond Hettinger267b8682005-03-27 10:47:39 +0000908
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000909 for sym, lop, rop in oplist:
Raymond Hettinger267b8682005-03-27 10:47:39 +0000910 setattr(E, lop, lambda self, other: 'str' + lop + str(other))
911 setattr(E, rop, lambda self, other: str(other) + rop + 'str')
912 self.assertEqual(eval('E()' + sym + 'Decimal(10)'),
913 'str' + lop + '10')
914 self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
915 '10' + rop + 'str')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +0000916
Stefan Krah1919b7e2012-03-21 18:25:23 +0100917class CImplicitConstructionTest(ImplicitConstructionTest):
918 decimal = C
919class PyImplicitConstructionTest(ImplicitConstructionTest):
920 decimal = P
Mark Dickinson79f52032009-03-17 23:12:51 +0000921
Stefan Krah1919b7e2012-03-21 18:25:23 +0100922class FormatTest(unittest.TestCase):
Christian Heimesf16baeb2008-02-29 14:57:44 +0000923 '''Unit tests for the format function.'''
924 def test_formatting(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +0100925 Decimal = self.decimal.Decimal
926
Christian Heimesf16baeb2008-02-29 14:57:44 +0000927 # triples giving a format, a Decimal, and the expected result
928 test_values = [
929 ('e', '0E-15', '0e-15'),
930 ('e', '2.3E-15', '2.3e-15'),
931 ('e', '2.30E+2', '2.30e+2'), # preserve significant zeros
932 ('e', '2.30000E-15', '2.30000e-15'),
933 ('e', '1.23456789123456789e40', '1.23456789123456789e+40'),
934 ('e', '1.5', '1.5e+0'),
935 ('e', '0.15', '1.5e-1'),
936 ('e', '0.015', '1.5e-2'),
937 ('e', '0.0000000000015', '1.5e-12'),
938 ('e', '15.0', '1.50e+1'),
939 ('e', '-15', '-1.5e+1'),
940 ('e', '0', '0e+0'),
941 ('e', '0E1', '0e+1'),
942 ('e', '0.0', '0e-1'),
943 ('e', '0.00', '0e-2'),
944 ('.6e', '0E-15', '0.000000e-9'),
945 ('.6e', '0', '0.000000e+6'),
946 ('.6e', '9.999999', '9.999999e+0'),
947 ('.6e', '9.9999999', '1.000000e+1'),
948 ('.6e', '-1.23e5', '-1.230000e+5'),
949 ('.6e', '1.23456789e-3', '1.234568e-3'),
950 ('f', '0', '0'),
951 ('f', '0.0', '0.0'),
952 ('f', '0E-2', '0.00'),
953 ('f', '0.00E-8', '0.0000000000'),
954 ('f', '0E1', '0'), # loses exponent information
955 ('f', '3.2E1', '32'),
956 ('f', '3.2E2', '320'),
957 ('f', '3.20E2', '320'),
958 ('f', '3.200E2', '320.0'),
959 ('f', '3.2E-6', '0.0000032'),
960 ('.6f', '0E-15', '0.000000'), # all zeros treated equally
961 ('.6f', '0E1', '0.000000'),
962 ('.6f', '0', '0.000000'),
963 ('.0f', '0', '0'), # no decimal point
964 ('.0f', '0e-2', '0'),
965 ('.0f', '3.14159265', '3'),
966 ('.1f', '3.14159265', '3.1'),
967 ('.4f', '3.14159265', '3.1416'),
968 ('.6f', '3.14159265', '3.141593'),
969 ('.7f', '3.14159265', '3.1415926'), # round-half-even!
970 ('.8f', '3.14159265', '3.14159265'),
971 ('.9f', '3.14159265', '3.141592650'),
972
973 ('g', '0', '0'),
974 ('g', '0.0', '0.0'),
975 ('g', '0E1', '0e+1'),
976 ('G', '0E1', '0E+1'),
977 ('g', '0E-5', '0.00000'),
978 ('g', '0E-6', '0.000000'),
979 ('g', '0E-7', '0e-7'),
980 ('g', '-0E2', '-0e+2'),
981 ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
Stefan Krah1919b7e2012-03-21 18:25:23 +0100982 ('.0n', '3.14159265', '3'), # same for 'n'
Christian Heimesf16baeb2008-02-29 14:57:44 +0000983 ('.1g', '3.14159265', '3'),
984 ('.2g', '3.14159265', '3.1'),
985 ('.5g', '3.14159265', '3.1416'),
986 ('.7g', '3.14159265', '3.141593'),
987 ('.8g', '3.14159265', '3.1415926'), # round-half-even!
988 ('.9g', '3.14159265', '3.14159265'),
989 ('.10g', '3.14159265', '3.14159265'), # don't pad
990
991 ('%', '0E1', '0%'),
992 ('%', '0E0', '0%'),
993 ('%', '0E-1', '0%'),
994 ('%', '0E-2', '0%'),
995 ('%', '0E-3', '0.0%'),
996 ('%', '0E-4', '0.00%'),
997
998 ('.3%', '0', '0.000%'), # all zeros treated equally
999 ('.3%', '0E10', '0.000%'),
1000 ('.3%', '0E-10', '0.000%'),
1001 ('.3%', '2.34', '234.000%'),
1002 ('.3%', '1.234567', '123.457%'),
1003 ('.0%', '1.23', '123%'),
1004
1005 ('e', 'NaN', 'NaN'),
1006 ('f', '-NaN123', '-NaN123'),
1007 ('+g', 'NaN456', '+NaN456'),
1008 ('.3e', 'Inf', 'Infinity'),
1009 ('.16f', '-Inf', '-Infinity'),
1010 ('.0g', '-sNaN', '-sNaN'),
1011
1012 ('', '1.00', '1.00'),
Mark Dickinsonad416342009-03-17 18:10:15 +00001013
Mark Dickinson79f52032009-03-17 23:12:51 +00001014 # test alignment and padding
Mark Dickinson46ab5d02009-09-08 20:22:46 +00001015 ('6', '123', ' 123'),
Mark Dickinsonad416342009-03-17 18:10:15 +00001016 ('<6', '123', '123 '),
1017 ('>6', '123', ' 123'),
1018 ('^6', '123', ' 123 '),
1019 ('=+6', '123', '+ 123'),
Mark Dickinson79f52032009-03-17 23:12:51 +00001020 ('#<10', 'NaN', 'NaN#######'),
1021 ('#<10', '-4.3', '-4.3######'),
1022 ('#<+10', '0.0130', '+0.0130###'),
1023 ('#< 10', '0.0130', ' 0.0130###'),
1024 ('@>10', '-Inf', '@-Infinity'),
1025 ('#>5', '-Inf', '-Infinity'),
1026 ('?^5', '123', '?123?'),
1027 ('%^6', '123', '%123%%'),
1028 (' ^6', '-45.6', '-45.6 '),
1029 ('/=10', '-45.6', '-/////45.6'),
1030 ('/=+10', '45.6', '+/////45.6'),
1031 ('/= 10', '45.6', ' /////45.6'),
Stefan Krah6edda142013-05-29 15:45:38 +02001032 ('\x00=10', '-inf', '-\x00Infinity'),
1033 ('\x00^16', '-inf', '\x00\x00\x00-Infinity\x00\x00\x00\x00'),
1034 ('\x00>10', '1.2345', '\x00\x00\x00\x001.2345'),
1035 ('\x00<10', '1.2345', '1.2345\x00\x00\x00\x00'),
Mark Dickinson79f52032009-03-17 23:12:51 +00001036
1037 # thousands separator
1038 (',', '1234567', '1,234,567'),
1039 (',', '123456', '123,456'),
1040 (',', '12345', '12,345'),
1041 (',', '1234', '1,234'),
1042 (',', '123', '123'),
1043 (',', '12', '12'),
1044 (',', '1', '1'),
1045 (',', '0', '0'),
1046 (',', '-1234567', '-1,234,567'),
1047 (',', '-123456', '-123,456'),
1048 ('7,', '123456', '123,456'),
Mark Dickinson46ab5d02009-09-08 20:22:46 +00001049 ('8,', '123456', ' 123,456'),
Mark Dickinson79f52032009-03-17 23:12:51 +00001050 ('08,', '123456', '0,123,456'), # special case: extra 0 needed
1051 ('+08,', '123456', '+123,456'), # but not if there's a sign
1052 (' 08,', '123456', ' 123,456'),
1053 ('08,', '-123456', '-123,456'),
1054 ('+09,', '123456', '+0,123,456'),
1055 # ... with fractional part...
1056 ('07,', '1234.56', '1,234.56'),
1057 ('08,', '1234.56', '1,234.56'),
1058 ('09,', '1234.56', '01,234.56'),
1059 ('010,', '1234.56', '001,234.56'),
1060 ('011,', '1234.56', '0,001,234.56'),
1061 ('012,', '1234.56', '0,001,234.56'),
1062 ('08,.1f', '1234.5', '01,234.5'),
1063 # no thousands separators in fraction part
1064 (',', '1.23456789', '1.23456789'),
1065 (',%', '123.456789', '12,345.6789%'),
1066 (',e', '123456', '1.23456e+5'),
1067 (',E', '123456', '1.23456E+5'),
Mark Dickinson7718d2b2009-09-07 16:21:56 +00001068
1069 # issue 6850
1070 ('a=-7.0', '0.12345', 'aaaa0.1'),
Stefan Krah298131a2014-08-26 20:46:49 +02001071
1072 # issue 22090
1073 ('<^+15.20%', 'inf', '<<+Infinity%<<<'),
1074 ('\x07>,%', 'sNaN1234567', 'sNaN1234567%'),
1075 ('=10.10%', 'NaN123', ' NaN123%'),
Christian Heimesf16baeb2008-02-29 14:57:44 +00001076 ]
1077 for fmt, d, result in test_values:
1078 self.assertEqual(format(Decimal(d), fmt), result)
1079
Stefan Krah1919b7e2012-03-21 18:25:23 +01001080 # bytes format argument
1081 self.assertRaises(TypeError, Decimal(1).__format__, b'-020')
1082
Mark Dickinson79f52032009-03-17 23:12:51 +00001083 def test_n_format(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001084 Decimal = self.decimal.Decimal
1085
Mark Dickinson79f52032009-03-17 23:12:51 +00001086 try:
1087 from locale import CHAR_MAX
1088 except ImportError:
Zachary Ware9fe6d862013-12-08 00:20:35 -06001089 self.skipTest('locale.CHAR_MAX not available')
Mark Dickinson79f52032009-03-17 23:12:51 +00001090
Stefan Krah1919b7e2012-03-21 18:25:23 +01001091 def make_grouping(lst):
1092 return ''.join([chr(x) for x in lst]) if self.decimal == C else lst
1093
1094 def get_fmt(x, override=None, fmt='n'):
1095 if self.decimal == C:
1096 return Decimal(x).__format__(fmt, override)
1097 else:
1098 return Decimal(x).__format__(fmt, _localeconv=override)
1099
Mark Dickinson79f52032009-03-17 23:12:51 +00001100 # Set up some localeconv-like dictionaries
1101 en_US = {
1102 'decimal_point' : '.',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001103 'grouping' : make_grouping([3, 3, 0]),
1104 'thousands_sep' : ','
Mark Dickinson79f52032009-03-17 23:12:51 +00001105 }
1106
1107 fr_FR = {
1108 'decimal_point' : ',',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001109 'grouping' : make_grouping([CHAR_MAX]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001110 'thousands_sep' : ''
1111 }
1112
1113 ru_RU = {
1114 'decimal_point' : ',',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001115 'grouping': make_grouping([3, 3, 0]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001116 'thousands_sep' : ' '
1117 }
1118
1119 crazy = {
1120 'decimal_point' : '&',
Stefan Krah1919b7e2012-03-21 18:25:23 +01001121 'grouping': make_grouping([1, 4, 2, CHAR_MAX]),
Mark Dickinson79f52032009-03-17 23:12:51 +00001122 'thousands_sep' : '-'
1123 }
1124
Stefan Krah1919b7e2012-03-21 18:25:23 +01001125 dotsep_wide = {
1126 'decimal_point' : b'\xc2\xbf'.decode('utf-8'),
1127 'grouping': make_grouping([3, 3, 0]),
1128 'thousands_sep' : b'\xc2\xb4'.decode('utf-8')
1129 }
Mark Dickinson79f52032009-03-17 23:12:51 +00001130
1131 self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
1132 self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
1133 self.assertEqual(get_fmt(Decimal('12.7'), ru_RU), '12,7')
1134 self.assertEqual(get_fmt(Decimal('12.7'), crazy), '1-2&7')
1135
1136 self.assertEqual(get_fmt(123456789, en_US), '123,456,789')
1137 self.assertEqual(get_fmt(123456789, fr_FR), '123456789')
1138 self.assertEqual(get_fmt(123456789, ru_RU), '123 456 789')
1139 self.assertEqual(get_fmt(1234567890123, crazy), '123456-78-9012-3')
1140
1141 self.assertEqual(get_fmt(123456789, en_US, '.6n'), '1.23457e+8')
1142 self.assertEqual(get_fmt(123456789, fr_FR, '.6n'), '1,23457e+8')
1143 self.assertEqual(get_fmt(123456789, ru_RU, '.6n'), '1,23457e+8')
1144 self.assertEqual(get_fmt(123456789, crazy, '.6n'), '1&23457e+8')
1145
Mark Dickinson7303b592009-03-18 08:25:36 +00001146 # zero padding
1147 self.assertEqual(get_fmt(1234, fr_FR, '03n'), '1234')
1148 self.assertEqual(get_fmt(1234, fr_FR, '04n'), '1234')
1149 self.assertEqual(get_fmt(1234, fr_FR, '05n'), '01234')
1150 self.assertEqual(get_fmt(1234, fr_FR, '06n'), '001234')
1151
1152 self.assertEqual(get_fmt(12345, en_US, '05n'), '12,345')
1153 self.assertEqual(get_fmt(12345, en_US, '06n'), '12,345')
1154 self.assertEqual(get_fmt(12345, en_US, '07n'), '012,345')
1155 self.assertEqual(get_fmt(12345, en_US, '08n'), '0,012,345')
1156 self.assertEqual(get_fmt(12345, en_US, '09n'), '0,012,345')
1157 self.assertEqual(get_fmt(12345, en_US, '010n'), '00,012,345')
1158
1159 self.assertEqual(get_fmt(123456, crazy, '06n'), '1-2345-6')
1160 self.assertEqual(get_fmt(123456, crazy, '07n'), '1-2345-6')
1161 self.assertEqual(get_fmt(123456, crazy, '08n'), '1-2345-6')
1162 self.assertEqual(get_fmt(123456, crazy, '09n'), '01-2345-6')
1163 self.assertEqual(get_fmt(123456, crazy, '010n'), '0-01-2345-6')
1164 self.assertEqual(get_fmt(123456, crazy, '011n'), '0-01-2345-6')
1165 self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
1166 self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
1167
Stefan Krah1919b7e2012-03-21 18:25:23 +01001168 # wide char separator and decimal point
1169 self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'),
1170 '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5')
Mark Dickinson79f52032009-03-17 23:12:51 +00001171
Stefan Krah6fb204a2012-09-28 16:18:54 +02001172 @run_with_locale('LC_ALL', 'ps_AF')
Stefan Krah1919b7e2012-03-21 18:25:23 +01001173 def test_wide_char_separator_decimal_point(self):
1174 # locale with wide char separator and decimal point
1175 Decimal = self.decimal.Decimal
1176
Stefan Krah8a491a82012-09-28 17:17:11 +02001177 decimal_point = locale.localeconv()['decimal_point']
1178 thousands_sep = locale.localeconv()['thousands_sep']
Zachary Ware9fe6d862013-12-08 00:20:35 -06001179 if decimal_point != '\u066b':
Serhiy Storchaka34fd4c22018-11-05 16:20:25 +02001180 self.skipTest('inappropriate decimal point separator '
Zachary Ware0f533ac2013-12-12 10:32:16 -06001181 '({!a} not {!a})'.format(decimal_point, '\u066b'))
Zachary Ware9fe6d862013-12-08 00:20:35 -06001182 if thousands_sep != '\u066c':
Serhiy Storchaka34fd4c22018-11-05 16:20:25 +02001183 self.skipTest('inappropriate thousands separator '
Zachary Ware0f533ac2013-12-12 10:32:16 -06001184 '({!a} not {!a})'.format(thousands_sep, '\u066c'))
Stefan Krah8a491a82012-09-28 17:17:11 +02001185
Stefan Krah1919b7e2012-03-21 18:25:23 +01001186 self.assertEqual(format(Decimal('100000000.123'), 'n'),
1187 '100\u066c000\u066c000\u066b123')
Stefan Krah1919b7e2012-03-21 18:25:23 +01001188
Andrew Nester6d1dece2017-02-14 21:22:55 +03001189 def test_decimal_from_float_argument_type(self):
1190 class A(self.decimal.Decimal):
1191 def __init__(self, a):
1192 self.a_type = type(a)
1193 a = A.from_float(42.5)
1194 self.assertEqual(self.decimal.Decimal, a.a_type)
1195
1196 a = A.from_float(42)
1197 self.assertEqual(self.decimal.Decimal, a.a_type)
1198
Stefan Krah1919b7e2012-03-21 18:25:23 +01001199class CFormatTest(FormatTest):
1200 decimal = C
1201class PyFormatTest(FormatTest):
1202 decimal = P
1203
1204class ArithmeticOperatorsTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001205 '''Unit tests for all arithmetic operators, binary and unary.'''
1206
1207 def test_addition(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001208 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001209
1210 d1 = Decimal('-11.1')
1211 d2 = Decimal('22.2')
1212
1213 #two Decimals
1214 self.assertEqual(d1+d2, Decimal('11.1'))
1215 self.assertEqual(d2+d1, Decimal('11.1'))
1216
1217 #with other type, left
1218 c = d1 + 5
1219 self.assertEqual(c, Decimal('-6.1'))
1220 self.assertEqual(type(c), type(d1))
1221
1222 #with other type, right
1223 c = 5 + d1
1224 self.assertEqual(c, Decimal('-6.1'))
1225 self.assertEqual(type(c), type(d1))
1226
1227 #inline with decimal
1228 d1 += d2
1229 self.assertEqual(d1, Decimal('11.1'))
1230
1231 #inline with other type
1232 d1 += 5
1233 self.assertEqual(d1, Decimal('16.1'))
1234
1235 def test_subtraction(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001236 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001237
1238 d1 = Decimal('-11.1')
1239 d2 = Decimal('22.2')
1240
1241 #two Decimals
1242 self.assertEqual(d1-d2, Decimal('-33.3'))
1243 self.assertEqual(d2-d1, Decimal('33.3'))
1244
1245 #with other type, left
1246 c = d1 - 5
1247 self.assertEqual(c, Decimal('-16.1'))
1248 self.assertEqual(type(c), type(d1))
1249
1250 #with other type, right
1251 c = 5 - d1
1252 self.assertEqual(c, Decimal('16.1'))
1253 self.assertEqual(type(c), type(d1))
1254
1255 #inline with decimal
1256 d1 -= d2
1257 self.assertEqual(d1, Decimal('-33.3'))
1258
1259 #inline with other type
1260 d1 -= 5
1261 self.assertEqual(d1, Decimal('-38.3'))
1262
1263 def test_multiplication(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001264 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001265
1266 d1 = Decimal('-5')
1267 d2 = Decimal('3')
1268
1269 #two Decimals
1270 self.assertEqual(d1*d2, Decimal('-15'))
1271 self.assertEqual(d2*d1, Decimal('-15'))
1272
1273 #with other type, left
1274 c = d1 * 5
1275 self.assertEqual(c, Decimal('-25'))
1276 self.assertEqual(type(c), type(d1))
1277
1278 #with other type, right
1279 c = 5 * d1
1280 self.assertEqual(c, Decimal('-25'))
1281 self.assertEqual(type(c), type(d1))
1282
1283 #inline with decimal
1284 d1 *= d2
1285 self.assertEqual(d1, Decimal('-15'))
1286
1287 #inline with other type
1288 d1 *= 5
1289 self.assertEqual(d1, Decimal('-75'))
1290
1291 def test_division(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001292 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001293
1294 d1 = Decimal('-5')
1295 d2 = Decimal('2')
1296
1297 #two Decimals
1298 self.assertEqual(d1/d2, Decimal('-2.5'))
1299 self.assertEqual(d2/d1, Decimal('-0.4'))
1300
1301 #with other type, left
1302 c = d1 / 4
1303 self.assertEqual(c, Decimal('-1.25'))
1304 self.assertEqual(type(c), type(d1))
1305
1306 #with other type, right
1307 c = 4 / d1
1308 self.assertEqual(c, Decimal('-0.8'))
1309 self.assertEqual(type(c), type(d1))
1310
1311 #inline with decimal
1312 d1 /= d2
1313 self.assertEqual(d1, Decimal('-2.5'))
1314
1315 #inline with other type
1316 d1 /= 4
1317 self.assertEqual(d1, Decimal('-0.625'))
1318
1319 def test_floor_division(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001320 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001321
1322 d1 = Decimal('5')
1323 d2 = Decimal('2')
1324
1325 #two Decimals
1326 self.assertEqual(d1//d2, Decimal('2'))
1327 self.assertEqual(d2//d1, Decimal('0'))
1328
1329 #with other type, left
1330 c = d1 // 4
1331 self.assertEqual(c, Decimal('1'))
1332 self.assertEqual(type(c), type(d1))
1333
1334 #with other type, right
1335 c = 7 // d1
1336 self.assertEqual(c, Decimal('1'))
1337 self.assertEqual(type(c), type(d1))
1338
1339 #inline with decimal
1340 d1 //= d2
1341 self.assertEqual(d1, Decimal('2'))
1342
1343 #inline with other type
1344 d1 //= 2
1345 self.assertEqual(d1, Decimal('1'))
1346
1347 def test_powering(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001348 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001349
1350 d1 = Decimal('5')
1351 d2 = Decimal('2')
1352
1353 #two Decimals
1354 self.assertEqual(d1**d2, Decimal('25'))
1355 self.assertEqual(d2**d1, Decimal('32'))
1356
1357 #with other type, left
1358 c = d1 ** 4
1359 self.assertEqual(c, Decimal('625'))
1360 self.assertEqual(type(c), type(d1))
1361
1362 #with other type, right
1363 c = 7 ** d1
1364 self.assertEqual(c, Decimal('16807'))
1365 self.assertEqual(type(c), type(d1))
1366
1367 #inline with decimal
1368 d1 **= d2
1369 self.assertEqual(d1, Decimal('25'))
1370
1371 #inline with other type
1372 d1 **= 4
1373 self.assertEqual(d1, Decimal('390625'))
1374
1375 def test_module(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001376 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001377
1378 d1 = Decimal('5')
1379 d2 = Decimal('2')
1380
1381 #two Decimals
1382 self.assertEqual(d1%d2, Decimal('1'))
1383 self.assertEqual(d2%d1, Decimal('2'))
1384
1385 #with other type, left
1386 c = d1 % 4
1387 self.assertEqual(c, Decimal('1'))
1388 self.assertEqual(type(c), type(d1))
1389
1390 #with other type, right
1391 c = 7 % d1
1392 self.assertEqual(c, Decimal('2'))
1393 self.assertEqual(type(c), type(d1))
1394
1395 #inline with decimal
1396 d1 %= d2
1397 self.assertEqual(d1, Decimal('1'))
1398
1399 #inline with other type
1400 d1 %= 4
1401 self.assertEqual(d1, Decimal('1'))
1402
1403 def test_floor_div_module(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001404 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001405
1406 d1 = Decimal('5')
1407 d2 = Decimal('2')
1408
1409 #two Decimals
1410 (p, q) = divmod(d1, d2)
1411 self.assertEqual(p, Decimal('2'))
1412 self.assertEqual(q, Decimal('1'))
1413 self.assertEqual(type(p), type(d1))
1414 self.assertEqual(type(q), type(d1))
1415
1416 #with other type, left
1417 (p, q) = divmod(d1, 4)
1418 self.assertEqual(p, Decimal('1'))
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, right
1424 (p, q) = divmod(7, d1)
1425 self.assertEqual(p, Decimal('1'))
1426 self.assertEqual(q, Decimal('2'))
1427 self.assertEqual(type(p), type(d1))
1428 self.assertEqual(type(q), type(d1))
1429
1430 def test_unary_operators(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001431 Decimal = self.decimal.Decimal
1432
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001433 self.assertEqual(+Decimal(45), Decimal(+45)) # +
1434 self.assertEqual(-Decimal(45), Decimal(-45)) # -
1435 self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
1436
Christian Heimes77c02eb2008-02-09 02:18:51 +00001437 def test_nan_comparisons(self):
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001438 # comparisons involving signaling nans signal InvalidOperation
1439
1440 # order comparisons (<, <=, >, >=) involving only quiet nans
1441 # also signal InvalidOperation
1442
1443 # equality comparisons (==, !=) involving only quiet nans
1444 # don't signal, but return False or True respectively.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001445 Decimal = self.decimal.Decimal
1446 InvalidOperation = self.decimal.InvalidOperation
1447 localcontext = self.decimal.localcontext
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001448
Christian Heimes77c02eb2008-02-09 02:18:51 +00001449 n = Decimal('NaN')
1450 s = Decimal('sNaN')
1451 i = Decimal('Inf')
1452 f = Decimal('2')
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001453
1454 qnan_pairs = (n, n), (n, i), (i, n), (n, f), (f, n)
1455 snan_pairs = (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)
1456 order_ops = operator.lt, operator.le, operator.gt, operator.ge
1457 equality_ops = operator.eq, operator.ne
1458
1459 # results when InvalidOperation is not trapped
1460 for x, y in qnan_pairs + snan_pairs:
1461 for op in order_ops + equality_ops:
1462 got = op(x, y)
1463 expected = True if op is operator.ne else False
1464 self.assertIs(expected, got,
1465 "expected {0!r} for operator.{1}({2!r}, {3!r}); "
1466 "got {4!r}".format(
1467 expected, op.__name__, x, y, got))
1468
1469 # repeat the above, but this time trap the InvalidOperation
1470 with localcontext() as ctx:
1471 ctx.traps[InvalidOperation] = 1
1472
1473 for x, y in qnan_pairs:
1474 for op in equality_ops:
1475 got = op(x, y)
1476 expected = True if op is operator.ne else False
1477 self.assertIs(expected, got,
1478 "expected {0!r} for "
1479 "operator.{1}({2!r}, {3!r}); "
1480 "got {4!r}".format(
1481 expected, op.__name__, x, y, got))
1482
1483 for x, y in snan_pairs:
1484 for op in equality_ops:
1485 self.assertRaises(InvalidOperation, operator.eq, x, y)
1486 self.assertRaises(InvalidOperation, operator.ne, x, y)
1487
1488 for x, y in qnan_pairs + snan_pairs:
1489 for op in order_ops:
1490 self.assertRaises(InvalidOperation, op, x, y)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001491
Mark Dickinson84230a12010-02-18 14:49:50 +00001492 def test_copy_sign(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001493 Decimal = self.decimal.Decimal
Mark Dickinson84230a12010-02-18 14:49:50 +00001494
Stefan Krah1919b7e2012-03-21 18:25:23 +01001495 d = Decimal(1).copy_sign(Decimal(-2))
Mark Dickinson84230a12010-02-18 14:49:50 +00001496 self.assertEqual(Decimal(1).copy_sign(-2), d)
1497 self.assertRaises(TypeError, Decimal(1).copy_sign, '-2')
1498
Stefan Krah1919b7e2012-03-21 18:25:23 +01001499class CArithmeticOperatorsTest(ArithmeticOperatorsTest):
1500 decimal = C
1501class PyArithmeticOperatorsTest(ArithmeticOperatorsTest):
1502 decimal = P
1503
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001504# The following are two functions used to test threading in the next class
1505
1506def thfunc1(cls):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001507 Decimal = cls.decimal.Decimal
1508 InvalidOperation = cls.decimal.InvalidOperation
1509 DivisionByZero = cls.decimal.DivisionByZero
1510 Overflow = cls.decimal.Overflow
1511 Underflow = cls.decimal.Underflow
1512 Inexact = cls.decimal.Inexact
1513 getcontext = cls.decimal.getcontext
1514 localcontext = cls.decimal.localcontext
1515
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001516 d1 = Decimal(1)
1517 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001518 test1 = d1/d3
Christian Heimesfe337bf2008-03-23 21:54:12 +00001519
Stefan Krah1919b7e2012-03-21 18:25:23 +01001520 cls.finish1.set()
1521 cls.synchro.wait()
1522
1523 test2 = d1/d3
1524 with localcontext() as c2:
1525 cls.assertTrue(c2.flags[Inexact])
1526 cls.assertRaises(DivisionByZero, c2.divide, d1, 0)
1527 cls.assertTrue(c2.flags[DivisionByZero])
1528 with localcontext() as c3:
1529 cls.assertTrue(c3.flags[Inexact])
1530 cls.assertTrue(c3.flags[DivisionByZero])
1531 cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN'))
1532 cls.assertTrue(c3.flags[InvalidOperation])
1533 del c3
1534 cls.assertFalse(c2.flags[InvalidOperation])
1535 del c2
1536
1537 cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
1538 cls.assertEqual(test2, Decimal('0.333333333333333333333333'))
1539
1540 c1 = getcontext()
1541 cls.assertTrue(c1.flags[Inexact])
1542 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
1543 cls.assertFalse(c1.flags[sig])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001544
1545def thfunc2(cls):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001546 Decimal = cls.decimal.Decimal
1547 InvalidOperation = cls.decimal.InvalidOperation
1548 DivisionByZero = cls.decimal.DivisionByZero
1549 Overflow = cls.decimal.Overflow
1550 Underflow = cls.decimal.Underflow
1551 Inexact = cls.decimal.Inexact
1552 getcontext = cls.decimal.getcontext
1553 localcontext = cls.decimal.localcontext
1554
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001555 d1 = Decimal(1)
1556 d3 = Decimal(3)
Christian Heimesfe337bf2008-03-23 21:54:12 +00001557 test1 = d1/d3
Stefan Krah1919b7e2012-03-21 18:25:23 +01001558
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001559 thiscontext = getcontext()
1560 thiscontext.prec = 18
Christian Heimesfe337bf2008-03-23 21:54:12 +00001561 test2 = d1/d3
Stefan Krah1919b7e2012-03-21 18:25:23 +01001562
1563 with localcontext() as c2:
1564 cls.assertTrue(c2.flags[Inexact])
1565 cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999)
1566 cls.assertTrue(c2.flags[Overflow])
1567 with localcontext(thiscontext) as c3:
1568 cls.assertTrue(c3.flags[Inexact])
1569 cls.assertFalse(c3.flags[Overflow])
1570 c3.traps[Underflow] = True
1571 cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999)
1572 cls.assertTrue(c3.flags[Underflow])
1573 del c3
1574 cls.assertFalse(c2.flags[Underflow])
1575 cls.assertFalse(c2.traps[Underflow])
1576 del c2
1577
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001578 cls.synchro.set()
1579 cls.finish2.set()
Christian Heimesfe337bf2008-03-23 21:54:12 +00001580
Stefan Krah1919b7e2012-03-21 18:25:23 +01001581 cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
Christian Heimesfe337bf2008-03-23 21:54:12 +00001582 cls.assertEqual(test2, Decimal('0.333333333333333333'))
Stefan Krah1919b7e2012-03-21 18:25:23 +01001583
1584 cls.assertFalse(thiscontext.traps[Underflow])
1585 cls.assertTrue(thiscontext.flags[Inexact])
1586 for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
1587 cls.assertFalse(thiscontext.flags[sig])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001588
Stefan Krah1919b7e2012-03-21 18:25:23 +01001589class ThreadingTest(unittest.TestCase):
1590 '''Unit tests for thread local contexts in Decimal.'''
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001591
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001592 # Take care executing this test from IDLE, there's an issue in threading
1593 # that hangs IDLE and I couldn't find it
1594
1595 def test_threading(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001596 DefaultContext = self.decimal.DefaultContext
1597
1598 if self.decimal == C and not self.decimal.HAVE_THREADS:
1599 self.skipTest("compiled without threading")
1600 # Test the "threading isolation" of a Context. Also test changing
1601 # the DefaultContext, which acts as a template for the thread-local
1602 # contexts.
1603 save_prec = DefaultContext.prec
1604 save_emax = DefaultContext.Emax
1605 save_emin = DefaultContext.Emin
1606 DefaultContext.prec = 24
1607 DefaultContext.Emax = 425000000
1608 DefaultContext.Emin = -425000000
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001609
1610 self.synchro = threading.Event()
1611 self.finish1 = threading.Event()
1612 self.finish2 = threading.Event()
1613
1614 th1 = threading.Thread(target=thfunc1, args=(self,))
1615 th2 = threading.Thread(target=thfunc2, args=(self,))
1616
1617 th1.start()
1618 th2.start()
1619
1620 self.finish1.wait()
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001621 self.finish2.wait()
Stefan Krah1919b7e2012-03-21 18:25:23 +01001622
1623 for sig in Signals[self.decimal]:
1624 self.assertFalse(DefaultContext.flags[sig])
1625
Victor Stinner18e95b42017-09-14 08:43:04 -07001626 th1.join()
1627 th2.join()
1628
Stefan Krah1919b7e2012-03-21 18:25:23 +01001629 DefaultContext.prec = save_prec
1630 DefaultContext.Emax = save_emax
1631 DefaultContext.Emin = save_emin
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001632
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001633
Stefan Krah1919b7e2012-03-21 18:25:23 +01001634class CThreadingTest(ThreadingTest):
1635 decimal = C
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001636
Stefan Krah1919b7e2012-03-21 18:25:23 +01001637class PyThreadingTest(ThreadingTest):
1638 decimal = P
Raymond Hettinger7e71fa52004-12-18 19:07:19 +00001639
Stefan Krah1919b7e2012-03-21 18:25:23 +01001640class UsabilityTest(unittest.TestCase):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001641 '''Unit tests for Usability cases of Decimal.'''
1642
1643 def test_comparison_operators(self):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001644
Stefan Krah1919b7e2012-03-21 18:25:23 +01001645 Decimal = self.decimal.Decimal
1646
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001647 da = Decimal('23.42')
1648 db = Decimal('23.42')
1649 dc = Decimal('45')
1650
1651 #two Decimals
Ezio Melotti6607d512010-04-03 14:59:49 +00001652 self.assertGreater(dc, da)
1653 self.assertGreaterEqual(dc, da)
1654 self.assertLess(da, dc)
1655 self.assertLessEqual(da, dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001656 self.assertEqual(da, db)
Ezio Melotti6607d512010-04-03 14:59:49 +00001657 self.assertNotEqual(da, dc)
1658 self.assertLessEqual(da, db)
1659 self.assertGreaterEqual(da, db)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001660
1661 #a Decimal and an int
Ezio Melotti6607d512010-04-03 14:59:49 +00001662 self.assertGreater(dc, 23)
1663 self.assertLess(23, dc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +00001664 self.assertEqual(dc, 45)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001665
1666 #a Decimal and uncomparable
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001667 self.assertNotEqual(da, 'ugly')
1668 self.assertNotEqual(da, 32.7)
1669 self.assertNotEqual(da, object())
1670 self.assertNotEqual(da, object)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001671
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001672 # sortable
Guido van Rossumc1f779c2007-07-03 08:25:58 +00001673 a = list(map(Decimal, range(100)))
Raymond Hettinger0aeac102004-07-05 22:53:03 +00001674 b = a[:]
1675 random.shuffle(a)
1676 a.sort()
1677 self.assertEqual(a, b)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001678
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001679 def test_decimal_float_comparison(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001680 Decimal = self.decimal.Decimal
1681
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001682 da = Decimal('0.25')
1683 db = Decimal('3.0')
Ezio Melotti6607d512010-04-03 14:59:49 +00001684 self.assertLess(da, 3.0)
1685 self.assertLessEqual(da, 3.0)
1686 self.assertGreater(db, 0.25)
1687 self.assertGreaterEqual(db, 0.25)
1688 self.assertNotEqual(da, 1.5)
1689 self.assertEqual(da, 0.25)
1690 self.assertGreater(3.0, da)
1691 self.assertGreaterEqual(3.0, da)
1692 self.assertLess(0.25, db)
1693 self.assertLessEqual(0.25, db)
1694 self.assertNotEqual(0.25, db)
1695 self.assertEqual(3.0, db)
1696 self.assertNotEqual(0.1, Decimal('0.1'))
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001697
Stefan Krah1919b7e2012-03-21 18:25:23 +01001698 def test_decimal_complex_comparison(self):
1699 Decimal = self.decimal.Decimal
1700
1701 da = Decimal('0.25')
1702 db = Decimal('3.0')
1703 self.assertNotEqual(da, (1.5+0j))
1704 self.assertNotEqual((1.5+0j), da)
1705 self.assertEqual(da, (0.25+0j))
1706 self.assertEqual((0.25+0j), da)
1707 self.assertEqual((3.0+0j), db)
1708 self.assertEqual(db, (3.0+0j))
1709
1710 self.assertNotEqual(db, (3.0+1j))
1711 self.assertNotEqual((3.0+1j), db)
1712
1713 self.assertIs(db.__lt__(3.0+0j), NotImplemented)
1714 self.assertIs(db.__le__(3.0+0j), NotImplemented)
1715 self.assertIs(db.__gt__(3.0+0j), NotImplemented)
1716 self.assertIs(db.__le__(3.0+0j), NotImplemented)
1717
1718 def test_decimal_fraction_comparison(self):
1719 D = self.decimal.Decimal
1720 F = fractions[self.decimal].Fraction
1721 Context = self.decimal.Context
1722 localcontext = self.decimal.localcontext
1723 InvalidOperation = self.decimal.InvalidOperation
1724
1725
1726 emax = C.MAX_EMAX if C else 999999999
1727 emin = C.MIN_EMIN if C else -999999999
1728 etiny = C.MIN_ETINY if C else -1999999997
1729 c = Context(Emax=emax, Emin=emin)
1730
1731 with localcontext(c):
1732 c.prec = emax
1733 self.assertLess(D(0), F(1,9999999999999999999999999999999999999))
1734 self.assertLess(F(-1,9999999999999999999999999999999999999), D(0))
1735 self.assertLess(F(0,1), D("1e" + str(etiny)))
1736 self.assertLess(D("-1e" + str(etiny)), F(0,1))
1737 self.assertLess(F(0,9999999999999999999999999), D("1e" + str(etiny)))
1738 self.assertLess(D("-1e" + str(etiny)), F(0,9999999999999999999999999))
1739
1740 self.assertEqual(D("0.1"), F(1,10))
1741 self.assertEqual(F(1,10), D("0.1"))
1742
1743 c.prec = 300
1744 self.assertNotEqual(D(1)/3, F(1,3))
1745 self.assertNotEqual(F(1,3), D(1)/3)
1746
1747 self.assertLessEqual(F(120984237, 9999999999), D("9e" + str(emax)))
1748 self.assertGreaterEqual(D("9e" + str(emax)), F(120984237, 9999999999))
1749
1750 self.assertGreater(D('inf'), F(99999999999,123))
1751 self.assertGreater(D('inf'), F(-99999999999,123))
1752 self.assertLess(D('-inf'), F(99999999999,123))
1753 self.assertLess(D('-inf'), F(-99999999999,123))
1754
1755 self.assertRaises(InvalidOperation, D('nan').__gt__, F(-9,123))
1756 self.assertIs(NotImplemented, F(-9,123).__lt__(D('nan')))
1757 self.assertNotEqual(D('nan'), F(-9,123))
1758 self.assertNotEqual(F(-9,123), D('nan'))
1759
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001760 def test_copy_and_deepcopy_methods(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001761 Decimal = self.decimal.Decimal
1762
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001763 d = Decimal('43.24')
1764 c = copy.copy(d)
1765 self.assertEqual(id(c), id(d))
1766 dc = copy.deepcopy(d)
1767 self.assertEqual(id(dc), id(d))
1768
1769 def test_hash_method(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001770
1771 Decimal = self.decimal.Decimal
1772 localcontext = self.decimal.localcontext
1773
Stefan Krahdc817b22010-11-17 11:16:34 +00001774 def hashit(d):
1775 a = hash(d)
1776 b = d.__hash__()
1777 self.assertEqual(a, b)
1778 return a
1779
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001780 #just that it's hashable
Stefan Krahdc817b22010-11-17 11:16:34 +00001781 hashit(Decimal(23))
1782 hashit(Decimal('Infinity'))
1783 hashit(Decimal('-Infinity'))
1784 hashit(Decimal('nan123'))
1785 hashit(Decimal('-NaN'))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001786
1787 test_values = [Decimal(sign*(2**m + n))
1788 for m in [0, 14, 15, 16, 17, 30, 31,
Stefan Krahdc817b22010-11-17 11:16:34 +00001789 32, 33, 61, 62, 63, 64, 65, 66]
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001790 for n in range(-10, 10)
1791 for sign in [-1, 1]]
1792 test_values.extend([
Stefan Krahdc817b22010-11-17 11:16:34 +00001793 Decimal("-1"), # ==> -2
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001794 Decimal("-0"), # zeros
1795 Decimal("0.00"),
1796 Decimal("-0.000"),
1797 Decimal("0E10"),
1798 Decimal("-0E12"),
1799 Decimal("10.0"), # negative exponent
1800 Decimal("-23.00000"),
1801 Decimal("1230E100"), # positive exponent
1802 Decimal("-4.5678E50"),
1803 # a value for which hash(n) != hash(n % (2**64-1))
1804 # in Python pre-2.6
1805 Decimal(2**64 + 2**32 - 1),
1806 # selection of values which fail with the old (before
1807 # version 2.6) long.__hash__
1808 Decimal("1.634E100"),
1809 Decimal("90.697E100"),
1810 Decimal("188.83E100"),
1811 Decimal("1652.9E100"),
1812 Decimal("56531E100"),
1813 ])
1814
1815 # check that hash(d) == hash(int(d)) for integral values
1816 for value in test_values:
Stefan Krahdc817b22010-11-17 11:16:34 +00001817 self.assertEqual(hashit(value), hashit(int(value)))
Thomas Wouters8ce81f72007-09-20 18:22:40 +00001818
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001819 #the same hash that to an int
Stefan Krahdc817b22010-11-17 11:16:34 +00001820 self.assertEqual(hashit(Decimal(23)), hashit(23))
Raymond Hettingerd325c4b2010-11-21 04:08:28 +00001821 self.assertRaises(TypeError, hash, Decimal('sNaN'))
Stefan Krahdc817b22010-11-17 11:16:34 +00001822 self.assertTrue(hashit(Decimal('Inf')))
1823 self.assertTrue(hashit(Decimal('-Inf')))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001824
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001825 # check that the hashes of a Decimal float match when they
1826 # represent exactly the same values
1827 test_strings = ['inf', '-Inf', '0.0', '-.0e1',
1828 '34.0', '2.5', '112390.625', '-0.515625']
1829 for s in test_strings:
1830 f = float(s)
1831 d = Decimal(s)
Stefan Krahdc817b22010-11-17 11:16:34 +00001832 self.assertEqual(hashit(f), hashit(d))
Mark Dickinsonac256ab2010-04-03 11:08:14 +00001833
Stefan Krah1919b7e2012-03-21 18:25:23 +01001834 with localcontext() as c:
1835 # check that the value of the hash doesn't depend on the
1836 # current context (issue #1757)
1837 x = Decimal("123456789.1")
Christian Heimes2380ac72008-01-09 00:17:24 +00001838
Stefan Krah1919b7e2012-03-21 18:25:23 +01001839 c.prec = 6
1840 h1 = hashit(x)
1841 c.prec = 10
1842 h2 = hashit(x)
1843 c.prec = 16
1844 h3 = hashit(x)
Christian Heimes2380ac72008-01-09 00:17:24 +00001845
Stefan Krah1919b7e2012-03-21 18:25:23 +01001846 self.assertEqual(h1, h2)
1847 self.assertEqual(h1, h3)
1848
1849 c.prec = 10000
1850 x = 1100 ** 1248
1851 self.assertEqual(hashit(Decimal(x)), hashit(x))
Christian Heimes2380ac72008-01-09 00:17:24 +00001852
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001853 def test_min_and_max_methods(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001854 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001855
1856 d1 = Decimal('15.32')
1857 d2 = Decimal('28.5')
1858 l1 = 15
1859 l2 = 28
1860
1861 #between Decimals
Ezio Melotti6607d512010-04-03 14:59:49 +00001862 self.assertIs(min(d1,d2), d1)
1863 self.assertIs(min(d2,d1), d1)
1864 self.assertIs(max(d1,d2), d2)
1865 self.assertIs(max(d2,d1), d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001866
Serhiy Storchaka95949422013-08-27 19:40:23 +03001867 #between Decimal and int
Ezio Melotti6607d512010-04-03 14:59:49 +00001868 self.assertIs(min(d1,l2), d1)
1869 self.assertIs(min(l2,d1), d1)
1870 self.assertIs(max(l1,d2), d2)
1871 self.assertIs(max(d2,l1), d2)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001872
1873 def test_as_nonzero(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01001874 Decimal = self.decimal.Decimal
1875
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001876 #as false
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001877 self.assertFalse(Decimal(0))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001878 #as true
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001879 self.assertTrue(Decimal('0.372'))
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001880
1881 def test_tostring_methods(self):
1882 #Test str and repr methods.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001883 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001884
1885 d = Decimal('15.32')
1886 self.assertEqual(str(d), '15.32') # str
Christian Heimes68f5fbe2008-02-14 08:27:37 +00001887 self.assertEqual(repr(d), "Decimal('15.32')") # repr
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001888
1889 def test_tonum_methods(self):
Mark Dickinson5c2db372009-12-05 20:28:34 +00001890 #Test float and int methods.
Stefan Krah1919b7e2012-03-21 18:25:23 +01001891 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001892
1893 d1 = Decimal('66')
1894 d2 = Decimal('15.32')
1895
1896 #int
1897 self.assertEqual(int(d1), 66)
1898 self.assertEqual(int(d2), 15)
1899
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00001900 #float
1901 self.assertEqual(float(d1), 66)
1902 self.assertEqual(float(d2), 15.32)
1903
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001904 #floor
1905 test_pairs = [
1906 ('123.00', 123),
1907 ('3.2', 3),
1908 ('3.54', 3),
1909 ('3.899', 3),
1910 ('-2.3', -3),
1911 ('-11.0', -11),
1912 ('0.0', 0),
1913 ('-0E3', 0),
Stefan Krah1919b7e2012-03-21 18:25:23 +01001914 ('89891211712379812736.1', 89891211712379812736),
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001915 ]
1916 for d, i in test_pairs:
1917 self.assertEqual(math.floor(Decimal(d)), i)
1918 self.assertRaises(ValueError, math.floor, Decimal('-NaN'))
1919 self.assertRaises(ValueError, math.floor, Decimal('sNaN'))
1920 self.assertRaises(ValueError, math.floor, Decimal('NaN123'))
1921 self.assertRaises(OverflowError, math.floor, Decimal('Inf'))
1922 self.assertRaises(OverflowError, math.floor, Decimal('-Inf'))
1923
1924 #ceiling
1925 test_pairs = [
1926 ('123.00', 123),
1927 ('3.2', 4),
1928 ('3.54', 4),
1929 ('3.899', 4),
1930 ('-2.3', -2),
1931 ('-11.0', -11),
1932 ('0.0', 0),
1933 ('-0E3', 0),
Stefan Krah1919b7e2012-03-21 18:25:23 +01001934 ('89891211712379812736.1', 89891211712379812737),
Mark Dickinsonb27406c2008-05-09 13:42:33 +00001935 ]
1936 for d, i in test_pairs:
1937 self.assertEqual(math.ceil(Decimal(d)), i)
1938 self.assertRaises(ValueError, math.ceil, Decimal('-NaN'))
1939 self.assertRaises(ValueError, math.ceil, Decimal('sNaN'))
1940 self.assertRaises(ValueError, math.ceil, Decimal('NaN123'))
1941 self.assertRaises(OverflowError, math.ceil, Decimal('Inf'))
1942 self.assertRaises(OverflowError, math.ceil, Decimal('-Inf'))
1943
1944 #round, single argument
1945 test_pairs = [
1946 ('123.00', 123),
1947 ('3.2', 3),
1948 ('3.54', 4),
1949 ('3.899', 4),
1950 ('-2.3', -2),
1951 ('-11.0', -11),
1952 ('0.0', 0),
1953 ('-0E3', 0),
1954 ('-3.5', -4),
1955 ('-2.5', -2),
1956 ('-1.5', -2),
1957 ('-0.5', 0),
1958 ('0.5', 0),
1959 ('1.5', 2),
1960 ('2.5', 2),
1961 ('3.5', 4),
1962 ]
1963 for d, i in test_pairs:
1964 self.assertEqual(round(Decimal(d)), i)
1965 self.assertRaises(ValueError, round, Decimal('-NaN'))
1966 self.assertRaises(ValueError, round, Decimal('sNaN'))
1967 self.assertRaises(ValueError, round, Decimal('NaN123'))
1968 self.assertRaises(OverflowError, round, Decimal('Inf'))
1969 self.assertRaises(OverflowError, round, Decimal('-Inf'))
1970
1971 #round, two arguments; this is essentially equivalent
1972 #to quantize, which is already extensively tested
1973 test_triples = [
1974 ('123.456', -4, '0E+4'),
1975 ('123.456', -3, '0E+3'),
1976 ('123.456', -2, '1E+2'),
1977 ('123.456', -1, '1.2E+2'),
1978 ('123.456', 0, '123'),
1979 ('123.456', 1, '123.5'),
1980 ('123.456', 2, '123.46'),
1981 ('123.456', 3, '123.456'),
1982 ('123.456', 4, '123.4560'),
1983 ('123.455', 2, '123.46'),
1984 ('123.445', 2, '123.44'),
1985 ('Inf', 4, 'NaN'),
1986 ('-Inf', -23, 'NaN'),
1987 ('sNaN314', 3, 'NaN314'),
1988 ]
1989 for d, n, r in test_triples:
1990 self.assertEqual(str(round(Decimal(d), n)), r)
1991
Mark Dickinsonfc33d4c2012-08-24 18:53:10 +01001992 def test_nan_to_float(self):
1993 # Test conversions of decimal NANs to float.
1994 # See http://bugs.python.org/issue15544
1995 Decimal = self.decimal.Decimal
1996 for s in ('nan', 'nan1234', '-nan', '-nan2468'):
1997 f = float(Decimal(s))
1998 self.assertTrue(math.isnan(f))
1999 sign = math.copysign(1.0, f)
2000 self.assertEqual(sign, -1.0 if s.startswith('-') else 1.0)
2001
2002 def test_snan_to_float(self):
2003 Decimal = self.decimal.Decimal
2004 for s in ('snan', '-snan', 'snan1357', '-snan1234'):
2005 d = Decimal(s)
2006 self.assertRaises(ValueError, float, d)
2007
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002008 def test_eval_round_trip(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01002009 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002010
2011 #with zero
2012 d = Decimal( (0, (0,), 0) )
2013 self.assertEqual(d, eval(repr(d)))
2014
2015 #int
2016 d = Decimal( (1, (4, 5), 0) )
2017 self.assertEqual(d, eval(repr(d)))
2018
2019 #float
2020 d = Decimal( (0, (4, 5, 3, 4), -2) )
2021 self.assertEqual(d, eval(repr(d)))
2022
2023 #weird
2024 d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
2025 self.assertEqual(d, eval(repr(d)))
2026
2027 def test_as_tuple(self):
Stefan Krah1919b7e2012-03-21 18:25:23 +01002028 Decimal = self.decimal.Decimal
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002029
2030 #with zero
2031 d = Decimal(0)
2032 self.assertEqual(d.as_tuple(), (0, (0,), 0) )
2033
2034 #int
2035 d = Decimal(-45)
2036 self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
2037
2038 #complicated string
2039 d = Decimal("-4.34913534E-17")
2040 self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
2041
Stefan Krah76e12172012-09-10 19:34:58 +02002042 # The '0' coefficient is implementation specific to decimal.py.
2043 # It has no meaning in the C-version and is ignored there.
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00002044 d = Decimal("Infinity")
2045 self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
2046
Guido van Rossum8ce8a782007-11-01 19:42:39 +00002047 #leading zeros in coefficient should be stripped
2048 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
2049 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), -2) )
2050 d = Decimal( (1, (0, 0, 0), 37) )
2051 self.assertEqual(d.as_tuple(), (1, (0,), 37))
2052 d = Decimal( (1, (), 37) )
2053 self.assertEqual(d.as_tuple(), (1, (0,), 37))
2054
2055 #leading zeros in NaN diagnostic info should be stripped
2056 d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
2057 self.assertEqual(d.as_tuple(), (0, (4, 0, 5, 3, 4), 'n') )
2058 d = Decimal( (1, (0, 0, 0), 'N') )
2059 self.assertEqual(d.as_tuple(), (1, (), 'N') )
2060 d = Decimal( (1, (), 'n') )
2061 self.assertEqual(d.as_tuple(), (1, (), 'n') )
2062
Stefan Krah76e12172012-09-10 19:34:58 +02002063 # For infinities, decimal.py has always silently accepted any
2064 # coefficient tuple.
2065 d = Decimal( (0, (0,), 'F') )
2066 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
2067 d = Decimal( (0, (4, 5, 3, 4), 'F') )
2068 self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
2069 d = Decimal( (1, (0, 2, 7, 1), 'F') )
2070 self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
Guido van Rossum8ce8a782007-11-01 19:42:39 +00002071
Stefan Krah53f2e0a2015-12-28 23:02:02 +01002072 def test_as_integer_ratio(self):
2073 Decimal = self.decimal.Decimal
2074
2075 # exceptional cases
2076 self.assertRaises(OverflowError,
2077 Decimal.as_integer_ratio, Decimal('inf'))
2078 self.assertRaises(OverflowError,
2079 Decimal.as_integer_ratio, Decimal('-inf'))
2080 self.assertRaises(ValueError,
2081 Decimal.as_integer_ratio, Decimal('-nan'))
2082 self.assertRaises(ValueError,
2083 Decimal.as_integer_ratio, Decimal('snan123'))
2084
2085 for exp in range(-4, 2):
2086 for coeff in range(1000):
2087 for sign in '+', '-':
2088 d = Decimal('%s%dE%d' % (sign, coeff, exp))
2089 pq = d.as_integer_ratio()
2090 p, q = pq
2091
2092 # check return type
2093 self.assertIsInstance(pq, tuple)
2094 self.assertIsInstance(p, int)
2095 self.assertIsInstance(q, int)
2096
2097 # check normalization: q should be positive;
2098 # p should be relatively prime to q.
2099 self.assertGreater(q, 0)
2100 self.assertEqual(math.gcd(p, q), 1)
2101
2102 # check that p/q actually gives the correct value
2103 self.assertEqual(Decimal(p) / Decimal(q), d)
2104
Stefan Krah1919b7e2012-03-21 18:25:23 +01002105 def test_subclassing(self):
2106 # Different behaviours when subclassing Decimal
2107 Decimal = self.decimal.Decimal
2108
2109 class MyDecimal(Decimal):
Stefan Krah0f82b762012-11-08 11:17:29 +01002110 y = None
Stefan Krah1919b7e2012-03-21 18:25:23 +01002111
2112 d1 = MyDecimal(1)
2113 d2 = MyDecimal(2)
2114 d = d1 + d2
2115 self.assertIs(type(d), Decimal)
2116
2117 d = d1.max(d2)
2118 self.assertIs(type(d), Decimal)
2119
2120 d = copy.copy(d1)
2121 self.assertIs(type(d), MyDecimal)
2122 self.assertEqual(d, d1)
2123
2124 d = copy.deepcopy(d1)
2125 self.assertIs(type(d), MyDecimal)
2126 self.assertEqual(d, d1)
2127
Stefan Krah0f82b762012-11-08 11:17:29 +01002128 # Decimal(Decimal)
2129 d = Decimal('1.0')
2130 x = Decimal(d)
2131 self.assertIs(type(x), Decimal)
2132 self.assertEqual(x, d)
Stefan Krahf4abc7b2012-11-07 23:12:25 +01002133
Stefan Krah0f82b762012-11-08 11:17:29 +01002134 # MyDecimal(Decimal)
2135 m = MyDecimal(d)
2136 self.assertIs(type(m), MyDecimal)
2137 self.assertEqual(m, d)
2138 self.assertIs(m.y, None)
2139
2140 # Decimal(MyDecimal)
2141 x = Decimal(m)
2142 self.assertIs(type(x), Decimal)
2143 self.assertEqual(x, d)
2144
2145 # MyDecimal(MyDecimal)
2146 m.y = 9
2147 x = MyDecimal(m)
2148 self.assertIs(type(x), MyDecimal)
2149 self.assertEqual(x, d)
2150 self.assertIs(x.y, None)
Stefan Krahed16eff2012-11-07 23:47:19 +01002151
Stefan Krah1919b7e2012-03-21 18:25:23 +01002152 def test_implicit_context(self):
2153 Decimal = self.decimal.Decimal
2154 getcontext = self.decimal.getcontext
2155
2156 # Check results when context given implicitly. (Issue 2478)
2157 c = getcontext()
2158 self.assertEqual(str(Decimal(0).sqrt()),
2159 str(c.sqrt(Decimal(0))))
2160
Stefan Krah040e3112012-12-15 22:33:33 +01002161 def test_none_args(self):
2162 Decimal = self.decimal.Decimal
2163 Context = self.decimal.Context
2164 localcontext = self.decimal.localcontext
2165 InvalidOperation = self.decimal.InvalidOperation
2166 DivisionByZero = self.decimal.DivisionByZero
2167 Overflow = self.decimal.Overflow
2168 Underflow = self.decimal.Underflow
2169 Subnormal = self.decimal.Subnormal
2170 Inexact = self.decimal.Inexact
2171 Rounded = self.decimal.Rounded
2172 Clamped = self.decimal.Clamped
Stefan Krah040e3112012-12-15 22:33:33 +01002173
2174 with localcontext(Context()) as c:
2175 c.prec = 7
2176 c.Emax = 999
2177 c.Emin = -999
2178
2179 x = Decimal("111")
2180 y = Decimal("1e9999")
2181 z = Decimal("1e-9999")
2182
2183 ##### Unary functions
2184 c.clear_flags()
2185 self.assertEqual(str(x.exp(context=None)), '1.609487E+48')
2186 self.assertTrue(c.flags[Inexact])
2187 self.assertTrue(c.flags[Rounded])
2188 c.clear_flags()
2189 self.assertRaises(Overflow, y.exp, context=None)
2190 self.assertTrue(c.flags[Overflow])
2191
2192 self.assertIs(z.is_normal(context=None), False)
2193 self.assertIs(z.is_subnormal(context=None), True)
2194
2195 c.clear_flags()
2196 self.assertEqual(str(x.ln(context=None)), '4.709530')
2197 self.assertTrue(c.flags[Inexact])
2198 self.assertTrue(c.flags[Rounded])
2199 c.clear_flags()
2200 self.assertRaises(InvalidOperation, Decimal(-1).ln, context=None)
2201 self.assertTrue(c.flags[InvalidOperation])
2202
2203 c.clear_flags()
2204 self.assertEqual(str(x.log10(context=None)), '2.045323')
2205 self.assertTrue(c.flags[Inexact])
2206 self.assertTrue(c.flags[Rounded])
2207 c.clear_flags()
2208 self.assertRaises(InvalidOperation, Decimal(-1).log10, context=None)
2209 self.assertTrue(c.flags[InvalidOperation])
2210
2211 c.clear_flags()
2212 self.assertEqual(str(x.logb(context=None)), '2')
2213 self.assertRaises(DivisionByZero, Decimal(0).logb, context=None)
2214 self.assertTrue(c.flags[DivisionByZero])
2215
2216 c.clear_flags()
2217 self.assertEqual(str(x.logical_invert(context=None)), '1111000')
2218 self.assertRaises(InvalidOperation, y.logical_invert, context=None)
2219 self.assertTrue(c.flags[InvalidOperation])
2220
2221 c.clear_flags()
2222 self.assertEqual(str(y.next_minus(context=None)), '9.999999E+999')
2223 self.assertRaises(InvalidOperation, Decimal('sNaN').next_minus, context=None)
2224 self.assertTrue(c.flags[InvalidOperation])
2225
2226 c.clear_flags()
2227 self.assertEqual(str(y.next_plus(context=None)), 'Infinity')
2228 self.assertRaises(InvalidOperation, Decimal('sNaN').next_plus, context=None)
2229 self.assertTrue(c.flags[InvalidOperation])
2230
2231 c.clear_flags()
2232 self.assertEqual(str(z.normalize(context=None)), '0')
2233 self.assertRaises(Overflow, y.normalize, context=None)
2234 self.assertTrue(c.flags[Overflow])
2235
2236 self.assertEqual(str(z.number_class(context=None)), '+Subnormal')
2237
2238 c.clear_flags()
2239 self.assertEqual(str(z.sqrt(context=None)), '0E-1005')
2240 self.assertTrue(c.flags[Clamped])
2241 self.assertTrue(c.flags[Inexact])
2242 self.assertTrue(c.flags[Rounded])
2243 self.assertTrue(c.flags[Subnormal])
2244 self.assertTrue(c.flags[Underflow])
2245 c.clear_flags()
2246 self.assertRaises(Overflow, y.sqrt, context=None)
2247 self.assertTrue(c.flags[Overflow])
2248
2249 c.capitals = 0
2250 self.assertEqual(str(z.to_eng_string(context=None)), '1e-9999')
2251 c.capitals = 1
2252
2253
2254 ##### Binary functions
2255 c.clear_flags()
2256 ans = str(x.compare(Decimal('Nan891287828'), context=None))
2257 self.assertEqual(ans, 'NaN1287828')
2258 self.assertRaises(InvalidOperation, x.compare, Decimal('sNaN'), context=None)
2259 self.assertTrue(c.flags[InvalidOperation])
2260
2261 c.clear_flags()
2262 ans = str(x.compare_signal(8224, context=None))
2263 self.assertEqual(ans, '-1')
2264 self.assertRaises(InvalidOperation, x.compare_signal, Decimal('NaN'), context=None)
2265 self.assertTrue(c.flags[InvalidOperation])
2266
2267 c.clear_flags()
2268 ans = str(x.logical_and(101, context=None))
2269 self.assertEqual(ans, '101')
2270 self.assertRaises(InvalidOperation, x.logical_and, 123, context=None)
2271 self.assertTrue(c.flags[InvalidOperation])
2272
2273 c.clear_flags()
2274 ans = str(x.logical_or(101, context=None))
2275 self.assertEqual(ans, '111')
2276 self.assertRaises(InvalidOperation, x.logical_or, 123, context=None)
2277 self.assertTrue(c.flags[InvalidOperation])
2278
2279 c.clear_flags()
2280 ans = str(x.logical_xor(101, context=None))
2281 self.assertEqual(ans, '10')
2282 self.assertRaises(InvalidOperation, x.logical_xor, 123, context=None)
2283 self.assertTrue(c.flags[InvalidOperation])
2284
2285 c.clear_flags()
2286 ans = str(x.max(101, context=None))
2287 self.assertEqual(ans, '111')
2288 self.assertRaises(InvalidOperation, x.max, Decimal('sNaN'), context=None)
2289 self.assertTrue(c.flags[InvalidOperation])
2290
2291 c.clear_flags()
2292 ans = str(x.max_mag(101, context=None))
2293 self.assertEqual(ans, '111')
2294 self.assertRaises(InvalidOperation, x.max_mag, Decimal('sNaN'), context=None)
2295 self.assertTrue(c.flags[InvalidOperation])
2296
2297 c.clear_flags()
2298 ans = str(x.min(101, context=None))
2299 self.assertEqual(ans, '101')
2300 self.assertRaises(InvalidOperation, x.min, Decimal('sNaN'), context=None)
2301 self.assertTrue(c.flags[InvalidOperation])
2302
2303 c.clear_flags()
2304 ans = str(x.min_mag(101, context=None))
2305 self.assertEqual(ans, '101')
2306 self.assertRaises(InvalidOperation, x.min_mag, Decimal('sNaN'), context=None)
2307 self.assertTrue(c.flags[InvalidOperation])
2308
2309 c.clear_flags()
2310 ans = str(x.remainder_near(101, context=None))
2311 self.assertEqual(ans, '10')
2312 self.assertRaises(InvalidOperation, y.remainder_near, 101, context=None)
2313 self.assertTrue(c.flags[InvalidOperation])
2314
2315 c.clear_flags()
2316 ans = str(x.rotate(2, context=None))
2317 self.assertEqual(ans, '11100')
2318 self.assertRaises(InvalidOperation, x.rotate, 101, context=None)
2319 self.assertTrue(c.flags[InvalidOperation])
2320
2321 c.clear_flags()
2322 ans = str(x.scaleb(7, context=None))
2323 self.assertEqual(ans, '1.11E+9')
2324 self.assertRaises(InvalidOperation, x.scaleb, 10000, context=None)
2325 self.assertTrue(c.flags[InvalidOperation])
2326
2327 c.clear_flags()
2328 ans = str(x.shift(2, context=None))
2329 self.assertEqual(ans, '11100')
2330 self.assertRaises(InvalidOperation, x.shift, 10000, context=None)
2331 self.assertTrue(c.flags[InvalidOperation])
2332
2333
2334 ##### Ternary functions
2335 c.clear_flags()
2336 ans = str(x.fma(2, 3, context=None))
2337 self.assertEqual(ans, '225')
2338 self.assertRaises(Overflow, x.fma, Decimal('1e9999'), 3, context=None)
2339 self.assertTrue(c.flags[Overflow])
2340
2341
2342 ##### Special cases
2343 c.rounding = ROUND_HALF_EVEN
2344 ans = str(Decimal('1.5').to_integral(rounding=None, context=None))
2345 self.assertEqual(ans, '2')
2346 c.rounding = ROUND_DOWN
2347 ans = str(Decimal('1.5').to_integral(rounding=None, context=None))
2348 self.assertEqual(ans, '1')
2349 ans = str(Decimal('1.5').to_integral(rounding=ROUND_UP, context=None))
2350 self.assertEqual(ans, '2')
2351 c.clear_flags()
2352 self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral, context=None)
2353 self.assertTrue(c.flags[InvalidOperation])
2354
2355 c.rounding = ROUND_HALF_EVEN
2356 ans = str(Decimal('1.5').to_integral_value(rounding=None, context=None))
2357 self.assertEqual(ans, '2')
2358 c.rounding = ROUND_DOWN
2359 ans = str(Decimal('1.5').to_integral_value(rounding=None, context=None))
2360 self.assertEqual(ans, '1')
2361 ans = str(Decimal('1.5').to_integral_value(rounding=ROUND_UP, context=None))
2362 self.assertEqual(ans, '2')
2363 c.clear_flags()
2364 self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral_value, context=None)
2365 self.assertTrue(c.flags[InvalidOperation])
2366
2367 c.rounding = ROUND_HALF_EVEN
2368 ans = str(Decimal('1.5').to_integral_exact(rounding=None, context=None))
2369 self.assertEqual(ans, '2')
2370 c.rounding = ROUND_DOWN
2371 ans = str(Decimal('1.5').to_integral_exact(rounding=None, context=None))
2372 self.assertEqual(ans, '1')
2373 ans = str(Decimal('1.5').to_integral_exact(rounding=ROUND_UP, context=None))
2374 self.assertEqual(ans, '2')
2375 c.clear_flags()
2376 self.assertRaises(InvalidOperation, Decimal('sNaN').to_integral_exact, context=None)
2377 self.assertTrue(c.flags[InvalidOperation])
2378
2379 c.rounding = ROUND_UP
2380 ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=None, context=None))
2381 self.assertEqual(ans, '1.501')
2382 c.rounding = ROUND_DOWN
2383 ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=None, context=None))
2384 self.assertEqual(ans, '1.500')
2385 ans = str(Decimal('1.50001').quantize(exp=Decimal('1e-3'), rounding=ROUND_UP, context=None))
2386 self.assertEqual(ans, '1.501')
2387 c.clear_flags()
2388 self.assertRaises(InvalidOperation, y.quantize, Decimal('1e-10'), rounding=ROUND_UP, context=None)
2389 self.assertTrue(c.flags[InvalidOperation])
2390
2391 with localcontext(Context()) as context:
2392 context.prec = 7
2393 context.Emax = 999
2394 context.Emin = -999
2395 with localcontext(ctx=None) as c:
2396 self.assertEqual(c.prec, 7)
2397 self.assertEqual(c.Emax, 999)
2398 self.assertEqual(c.Emin, -999)
2399
Stefan Krah1919b7e2012-03-21 18:25:23 +01002400 def test_conversions_from_int(self):
2401 # Check that methods taking a second Decimal argument will
2402 # always accept an integer in place of a Decimal.
2403 Decimal = self.decimal.Decimal
2404
2405 self.assertEqual(Decimal(4).compare(3),
2406 Decimal(4).compare(Decimal(3)))
2407 self.assertEqual(Decimal(4).compare_signal(3),
2408 Decimal(4).compare_signal(Decimal(3)))
2409 self.assertEqual(Decimal(4).compare_total(3),
2410 Decimal(4).compare_total(Decimal(3)))
2411 self.assertEqual(Decimal(4).compare_total_mag(3),
2412 Decimal(4).compare_total_mag(Decimal(3)))
2413 self.assertEqual(Decimal(10101).logical_and(1001),
2414 Decimal(10101).logical_and(Decimal(1001)))
2415 self.assertEqual(Decimal(10101).logical_or(1001),
2416 Decimal(10101).logical_or(Decimal(1001)))
2417 self.assertEqual(Decimal(10101).logical_xor(1001),
2418 Decimal(10101).logical_xor(Decimal(1001)))
2419 self.assertEqual(Decimal(567).max(123),
2420 Decimal(567).max(Decimal(123)))
2421 self.assertEqual(Decimal(567).max_mag(123),
2422 Decimal(567).max_mag(Decimal(123)))
2423 self.assertEqual(Decimal(567).min(123),
2424 Decimal(567).min(Decimal(123)))
2425 self.assertEqual(Decimal(567).min_mag(123),
2426 Decimal(567).min_mag(Decimal(123)))
2427 self.assertEqual(Decimal(567).next_toward(123),
2428 Decimal(567).next_toward(Decimal(123)))
2429 self.assertEqual(Decimal(1234).quantize(100),
2430 Decimal(1234).quantize(Decimal(100)))
2431 self.assertEqual(Decimal(768).remainder_near(1234),
2432 Decimal(768).remainder_near(Decimal(1234)))
2433 self.assertEqual(Decimal(123).rotate(1),
2434 Decimal(123).rotate(Decimal(1)))
2435 self.assertEqual(Decimal(1234).same_quantum(1000),
2436 Decimal(1234).same_quantum(Decimal(1000)))
2437 self.assertEqual(Decimal('9.123').scaleb(-100),
2438 Decimal('9.123').scaleb(Decimal(-100)))
2439 self.assertEqual(Decimal(456).shift(-1),
2440 Decimal(456).shift(Decimal(-1)))
2441
2442 self.assertEqual(Decimal(-12).fma(Decimal(45), 67),
2443 Decimal(-12).fma(Decimal(45), Decimal(67)))
2444 self.assertEqual(Decimal(-12).fma(45, 67),
2445 Decimal(-12).fma(Decimal(45), Decimal(67)))
2446 self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
2447 Decimal(-12).fma(Decimal(45), Decimal(67)))
2448
2449class CUsabilityTest(UsabilityTest):
2450 decimal = C
2451class PyUsabilityTest(UsabilityTest):
2452 decimal = P
2453
2454class PythonAPItests(unittest.TestCase):
2455
2456 def test_abc(self):
2457 Decimal = self.decimal.Decimal
2458
2459 self.assertTrue(issubclass(Decimal, numbers.Number))
2460 self.assertFalse(issubclass(Decimal, numbers.Real))
2461 self.assertIsInstance(Decimal(0), numbers.Number)
2462 self.assertNotIsInstance(Decimal(0), numbers.Real)
2463
2464 def test_pickle(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02002465 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
2466 Decimal = self.decimal.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002467
Serhiy Storchakabad12572014-12-15 14:03:42 +02002468 savedecimal = sys.modules['decimal']
Stefan Krah1919b7e2012-03-21 18:25:23 +01002469
Serhiy Storchakabad12572014-12-15 14:03:42 +02002470 # Round trip
2471 sys.modules['decimal'] = self.decimal
2472 d = Decimal('-3.141590000')
2473 p = pickle.dumps(d, proto)
2474 e = pickle.loads(p)
2475 self.assertEqual(d, e)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002476
Serhiy Storchakabad12572014-12-15 14:03:42 +02002477 if C:
2478 # Test interchangeability
2479 x = C.Decimal('-3.123e81723')
2480 y = P.Decimal('-3.123e81723')
Stefan Krah1919b7e2012-03-21 18:25:23 +01002481
Serhiy Storchakabad12572014-12-15 14:03:42 +02002482 sys.modules['decimal'] = C
2483 sx = pickle.dumps(x, proto)
2484 sys.modules['decimal'] = P
2485 r = pickle.loads(sx)
2486 self.assertIsInstance(r, P.Decimal)
2487 self.assertEqual(r, y)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002488
Serhiy Storchakabad12572014-12-15 14:03:42 +02002489 sys.modules['decimal'] = P
2490 sy = pickle.dumps(y, proto)
2491 sys.modules['decimal'] = C
2492 r = pickle.loads(sy)
2493 self.assertIsInstance(r, C.Decimal)
2494 self.assertEqual(r, x)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002495
Serhiy Storchakabad12572014-12-15 14:03:42 +02002496 x = C.Decimal('-3.123e81723').as_tuple()
2497 y = P.Decimal('-3.123e81723').as_tuple()
Stefan Krahf1d4e422014-04-29 18:23:35 +02002498
Serhiy Storchakabad12572014-12-15 14:03:42 +02002499 sys.modules['decimal'] = C
2500 sx = pickle.dumps(x, proto)
2501 sys.modules['decimal'] = P
2502 r = pickle.loads(sx)
2503 self.assertIsInstance(r, P.DecimalTuple)
2504 self.assertEqual(r, y)
Stefan Krahf1d4e422014-04-29 18:23:35 +02002505
Serhiy Storchakabad12572014-12-15 14:03:42 +02002506 sys.modules['decimal'] = P
2507 sy = pickle.dumps(y, proto)
2508 sys.modules['decimal'] = C
2509 r = pickle.loads(sy)
2510 self.assertIsInstance(r, C.DecimalTuple)
2511 self.assertEqual(r, x)
Stefan Krahf1d4e422014-04-29 18:23:35 +02002512
Serhiy Storchakabad12572014-12-15 14:03:42 +02002513 sys.modules['decimal'] = savedecimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002514
2515 def test_int(self):
2516 Decimal = self.decimal.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002517
2518 for x in range(-250, 250):
2519 s = '%0.2f' % (x / 100.0)
2520 # should work the same as for floats
2521 self.assertEqual(int(Decimal(s)), int(float(s)))
2522 # should work the same as to_integral in the ROUND_DOWN mode
2523 d = Decimal(s)
2524 r = d.to_integral(ROUND_DOWN)
2525 self.assertEqual(Decimal(int(d)), r)
2526
2527 self.assertRaises(ValueError, int, Decimal('-nan'))
2528 self.assertRaises(ValueError, int, Decimal('snan'))
2529 self.assertRaises(OverflowError, int, Decimal('inf'))
2530 self.assertRaises(OverflowError, int, Decimal('-inf'))
2531
2532 def test_trunc(self):
2533 Decimal = self.decimal.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002534
2535 for x in range(-250, 250):
2536 s = '%0.2f' % (x / 100.0)
2537 # should work the same as for floats
2538 self.assertEqual(int(Decimal(s)), int(float(s)))
2539 # should work the same as to_integral in the ROUND_DOWN mode
2540 d = Decimal(s)
2541 r = d.to_integral(ROUND_DOWN)
2542 self.assertEqual(Decimal(math.trunc(d)), r)
2543
2544 def test_from_float(self):
2545
2546 Decimal = self.decimal.Decimal
2547
2548 class MyDecimal(Decimal):
Stefan Krah6817c592016-06-20 12:10:13 +02002549 def __init__(self, _):
2550 self.x = 'y'
Stefan Krah1919b7e2012-03-21 18:25:23 +01002551
2552 self.assertTrue(issubclass(MyDecimal, Decimal))
2553
2554 r = MyDecimal.from_float(0.1)
2555 self.assertEqual(type(r), MyDecimal)
2556 self.assertEqual(str(r),
2557 '0.1000000000000000055511151231257827021181583404541015625')
Stefan Krah6817c592016-06-20 12:10:13 +02002558 self.assertEqual(r.x, 'y')
2559
Stefan Krah1919b7e2012-03-21 18:25:23 +01002560 bigint = 12345678901234567890123456789
2561 self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
2562 self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan())
2563 self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite())
2564 self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite())
2565 self.assertEqual(str(MyDecimal.from_float(float('nan'))),
2566 str(Decimal('NaN')))
2567 self.assertEqual(str(MyDecimal.from_float(float('inf'))),
2568 str(Decimal('Infinity')))
2569 self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
2570 str(Decimal('-Infinity')))
2571 self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
2572 for i in range(200):
2573 x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
2574 self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
2575
2576 def test_create_decimal_from_float(self):
2577 Decimal = self.decimal.Decimal
2578 Context = self.decimal.Context
Stefan Krah1919b7e2012-03-21 18:25:23 +01002579 Inexact = self.decimal.Inexact
2580
2581 context = Context(prec=5, rounding=ROUND_DOWN)
2582 self.assertEqual(
2583 context.create_decimal_from_float(math.pi),
2584 Decimal('3.1415')
2585 )
2586 context = Context(prec=5, rounding=ROUND_UP)
2587 self.assertEqual(
2588 context.create_decimal_from_float(math.pi),
2589 Decimal('3.1416')
2590 )
2591 context = Context(prec=5, traps=[Inexact])
2592 self.assertRaises(
2593 Inexact,
2594 context.create_decimal_from_float,
2595 math.pi
2596 )
2597 self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
2598 "Decimal('-0')")
2599 self.assertEqual(repr(context.create_decimal_from_float(1.0)),
2600 "Decimal('1')")
2601 self.assertEqual(repr(context.create_decimal_from_float(10)),
2602 "Decimal('10')")
2603
2604 def test_quantize(self):
2605 Decimal = self.decimal.Decimal
2606 Context = self.decimal.Context
2607 InvalidOperation = self.decimal.InvalidOperation
Stefan Krah1919b7e2012-03-21 18:25:23 +01002608
2609 c = Context(Emax=99999, Emin=-99999)
2610 self.assertEqual(
2611 Decimal('7.335').quantize(Decimal('.01')),
2612 Decimal('7.34')
2613 )
2614 self.assertEqual(
2615 Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN),
2616 Decimal('7.33')
2617 )
2618 self.assertRaises(
2619 InvalidOperation,
2620 Decimal("10e99999").quantize, Decimal('1e100000'), context=c
2621 )
2622
2623 c = Context()
2624 d = Decimal("0.871831e800")
2625 x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN)
2626 self.assertEqual(x, Decimal('8.71E+799'))
2627
2628 def test_complex(self):
2629 Decimal = self.decimal.Decimal
2630
2631 x = Decimal("9.8182731e181273")
2632 self.assertEqual(x.real, x)
2633 self.assertEqual(x.imag, 0)
2634 self.assertEqual(x.conjugate(), x)
2635
2636 x = Decimal("1")
2637 self.assertEqual(complex(x), complex(float(1)))
2638
2639 self.assertRaises(AttributeError, setattr, x, 'real', 100)
2640 self.assertRaises(AttributeError, setattr, x, 'imag', 100)
2641 self.assertRaises(AttributeError, setattr, x, 'conjugate', 100)
2642 self.assertRaises(AttributeError, setattr, x, '__complex__', 100)
2643
2644 def test_named_parameters(self):
2645 D = self.decimal.Decimal
2646 Context = self.decimal.Context
2647 localcontext = self.decimal.localcontext
2648 InvalidOperation = self.decimal.InvalidOperation
2649 Overflow = self.decimal.Overflow
2650
2651 xc = Context()
2652 xc.prec = 1
2653 xc.Emax = 1
2654 xc.Emin = -1
2655
2656 with localcontext() as c:
2657 c.clear_flags()
2658
2659 self.assertEqual(D(9, xc), 9)
2660 self.assertEqual(D(9, context=xc), 9)
2661 self.assertEqual(D(context=xc, value=9), 9)
2662 self.assertEqual(D(context=xc), 0)
2663 xc.clear_flags()
2664 self.assertRaises(InvalidOperation, D, "xyz", context=xc)
2665 self.assertTrue(xc.flags[InvalidOperation])
2666 self.assertFalse(c.flags[InvalidOperation])
2667
2668 xc.clear_flags()
2669 self.assertEqual(D(2).exp(context=xc), 7)
2670 self.assertRaises(Overflow, D(8).exp, context=xc)
2671 self.assertTrue(xc.flags[Overflow])
2672 self.assertFalse(c.flags[Overflow])
2673
2674 xc.clear_flags()
2675 self.assertEqual(D(2).ln(context=xc), D('0.7'))
2676 self.assertRaises(InvalidOperation, D(-1).ln, context=xc)
2677 self.assertTrue(xc.flags[InvalidOperation])
2678 self.assertFalse(c.flags[InvalidOperation])
2679
2680 self.assertEqual(D(0).log10(context=xc), D('-inf'))
2681 self.assertEqual(D(-1).next_minus(context=xc), -2)
2682 self.assertEqual(D(-1).next_plus(context=xc), D('-0.9'))
2683 self.assertEqual(D("9.73").normalize(context=xc), D('1E+1'))
2684 self.assertEqual(D("9999").to_integral(context=xc), 9999)
2685 self.assertEqual(D("-2000").to_integral_exact(context=xc), -2000)
2686 self.assertEqual(D("123").to_integral_value(context=xc), 123)
2687 self.assertEqual(D("0.0625").sqrt(context=xc), D('0.2'))
2688
2689 self.assertEqual(D("0.0625").compare(context=xc, other=3), -1)
2690 xc.clear_flags()
2691 self.assertRaises(InvalidOperation,
2692 D("0").compare_signal, D('nan'), context=xc)
2693 self.assertTrue(xc.flags[InvalidOperation])
2694 self.assertFalse(c.flags[InvalidOperation])
2695 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2696 self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
2697 self.assertEqual(D("0.2").max_mag(D('-0.3'), context=xc),
2698 D('-0.3'))
2699 self.assertEqual(D("0.02").min(D('-0.03'), context=xc), D('-0.0'))
2700 self.assertEqual(D("0.02").min_mag(D('-0.03'), context=xc),
2701 D('0.0'))
2702 self.assertEqual(D("0.2").next_toward(D('-1'), context=xc), D('0.1'))
2703 xc.clear_flags()
2704 self.assertRaises(InvalidOperation,
2705 D("0.2").quantize, D('1e10'), context=xc)
2706 self.assertTrue(xc.flags[InvalidOperation])
2707 self.assertFalse(c.flags[InvalidOperation])
2708 self.assertEqual(D("9.99").remainder_near(D('1.5'), context=xc),
2709 D('-0.5'))
2710
2711 self.assertEqual(D("9.9").fma(third=D('0.9'), context=xc, other=7),
2712 D('7E+1'))
2713
2714 self.assertRaises(TypeError, D(1).is_canonical, context=xc)
2715 self.assertRaises(TypeError, D(1).is_finite, context=xc)
2716 self.assertRaises(TypeError, D(1).is_infinite, context=xc)
2717 self.assertRaises(TypeError, D(1).is_nan, context=xc)
2718 self.assertRaises(TypeError, D(1).is_qnan, context=xc)
2719 self.assertRaises(TypeError, D(1).is_snan, context=xc)
2720 self.assertRaises(TypeError, D(1).is_signed, context=xc)
2721 self.assertRaises(TypeError, D(1).is_zero, context=xc)
2722
2723 self.assertFalse(D("0.01").is_normal(context=xc))
2724 self.assertTrue(D("0.01").is_subnormal(context=xc))
2725
2726 self.assertRaises(TypeError, D(1).adjusted, context=xc)
2727 self.assertRaises(TypeError, D(1).conjugate, context=xc)
2728 self.assertRaises(TypeError, D(1).radix, context=xc)
2729
2730 self.assertEqual(D(-111).logb(context=xc), 2)
2731 self.assertEqual(D(0).logical_invert(context=xc), 1)
2732 self.assertEqual(D('0.01').number_class(context=xc), '+Subnormal')
2733 self.assertEqual(D('0.21').to_eng_string(context=xc), '0.21')
2734
2735 self.assertEqual(D('11').logical_and(D('10'), context=xc), 0)
2736 self.assertEqual(D('11').logical_or(D('10'), context=xc), 1)
2737 self.assertEqual(D('01').logical_xor(D('10'), context=xc), 1)
2738 self.assertEqual(D('23').rotate(1, context=xc), 3)
2739 self.assertEqual(D('23').rotate(1, context=xc), 3)
2740 xc.clear_flags()
2741 self.assertRaises(Overflow,
2742 D('23').scaleb, 1, context=xc)
2743 self.assertTrue(xc.flags[Overflow])
2744 self.assertFalse(c.flags[Overflow])
2745 self.assertEqual(D('23').shift(-1, context=xc), 0)
2746
2747 self.assertRaises(TypeError, D.from_float, 1.1, context=xc)
2748 self.assertRaises(TypeError, D(0).as_tuple, context=xc)
2749
Stefan Krah040e3112012-12-15 22:33:33 +01002750 self.assertEqual(D(1).canonical(), 1)
2751 self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
2752 self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
2753 self.assertRaises(TypeError, D(1).canonical, context="x")
2754 self.assertRaises(TypeError, D(1).canonical, xyz="x")
Stefan Krah1919b7e2012-03-21 18:25:23 +01002755
Stefan Krahb6405ef2012-03-23 14:46:48 +01002756 def test_exception_hierarchy(self):
2757
2758 decimal = self.decimal
2759 DecimalException = decimal.DecimalException
2760 InvalidOperation = decimal.InvalidOperation
2761 FloatOperation = decimal.FloatOperation
2762 DivisionByZero = decimal.DivisionByZero
2763 Overflow = decimal.Overflow
2764 Underflow = decimal.Underflow
2765 Subnormal = decimal.Subnormal
2766 Inexact = decimal.Inexact
2767 Rounded = decimal.Rounded
2768 Clamped = decimal.Clamped
2769
2770 self.assertTrue(issubclass(DecimalException, ArithmeticError))
2771
2772 self.assertTrue(issubclass(InvalidOperation, DecimalException))
2773 self.assertTrue(issubclass(FloatOperation, DecimalException))
2774 self.assertTrue(issubclass(FloatOperation, TypeError))
2775 self.assertTrue(issubclass(DivisionByZero, DecimalException))
2776 self.assertTrue(issubclass(DivisionByZero, ZeroDivisionError))
2777 self.assertTrue(issubclass(Overflow, Rounded))
2778 self.assertTrue(issubclass(Overflow, Inexact))
2779 self.assertTrue(issubclass(Overflow, DecimalException))
2780 self.assertTrue(issubclass(Underflow, Inexact))
2781 self.assertTrue(issubclass(Underflow, Rounded))
2782 self.assertTrue(issubclass(Underflow, Subnormal))
2783 self.assertTrue(issubclass(Underflow, DecimalException))
2784
2785 self.assertTrue(issubclass(Subnormal, DecimalException))
2786 self.assertTrue(issubclass(Inexact, DecimalException))
2787 self.assertTrue(issubclass(Rounded, DecimalException))
2788 self.assertTrue(issubclass(Clamped, DecimalException))
2789
2790 self.assertTrue(issubclass(decimal.ConversionSyntax, InvalidOperation))
2791 self.assertTrue(issubclass(decimal.DivisionImpossible, InvalidOperation))
2792 self.assertTrue(issubclass(decimal.DivisionUndefined, InvalidOperation))
2793 self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError))
2794 self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation))
2795
Stefan Krah1919b7e2012-03-21 18:25:23 +01002796class CPythonAPItests(PythonAPItests):
2797 decimal = C
2798class PyPythonAPItests(PythonAPItests):
2799 decimal = P
2800
2801class ContextAPItests(unittest.TestCase):
2802
Stefan Krah9a4ff432012-12-16 21:10:35 +01002803 def test_none_args(self):
2804 Context = self.decimal.Context
2805 InvalidOperation = self.decimal.InvalidOperation
2806 DivisionByZero = self.decimal.DivisionByZero
2807 Overflow = self.decimal.Overflow
Stefan Krah9a4ff432012-12-16 21:10:35 +01002808
2809 c1 = Context()
2810 c2 = Context(prec=None, rounding=None, Emax=None, Emin=None,
2811 capitals=None, clamp=None, flags=None, traps=None)
2812 for c in [c1, c2]:
2813 self.assertEqual(c.prec, 28)
2814 self.assertEqual(c.rounding, ROUND_HALF_EVEN)
2815 self.assertEqual(c.Emax, 999999)
2816 self.assertEqual(c.Emin, -999999)
2817 self.assertEqual(c.capitals, 1)
2818 self.assertEqual(c.clamp, 0)
2819 assert_signals(self, c, 'flags', [])
2820 assert_signals(self, c, 'traps', [InvalidOperation, DivisionByZero,
2821 Overflow])
2822
Stefan Krah59a4a932013-01-16 12:58:59 +01002823 @cpython_only
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03002824 @requires_legacy_unicode_capi
Inada Naoki902356a2020-07-20 12:02:50 +09002825 @warnings_helper.ignore_warnings(category=DeprecationWarning)
Stefan Krah59a4a932013-01-16 12:58:59 +01002826 def test_from_legacy_strings(self):
2827 import _testcapi
2828 c = self.decimal.Context()
2829
2830 for rnd in RoundingModes:
2831 c.rounding = _testcapi.unicode_legacy_string(rnd)
2832 self.assertEqual(c.rounding, rnd)
2833
2834 s = _testcapi.unicode_legacy_string('')
2835 self.assertRaises(TypeError, setattr, c, 'rounding', s)
2836
2837 s = _testcapi.unicode_legacy_string('ROUND_\x00UP')
2838 self.assertRaises(TypeError, setattr, c, 'rounding', s)
2839
Stefan Krah1919b7e2012-03-21 18:25:23 +01002840 def test_pickle(self):
2841
Serhiy Storchakabad12572014-12-15 14:03:42 +02002842 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
2843 Context = self.decimal.Context
Stefan Krah1919b7e2012-03-21 18:25:23 +01002844
Serhiy Storchakabad12572014-12-15 14:03:42 +02002845 savedecimal = sys.modules['decimal']
Stefan Krah1919b7e2012-03-21 18:25:23 +01002846
Serhiy Storchakabad12572014-12-15 14:03:42 +02002847 # Round trip
2848 sys.modules['decimal'] = self.decimal
2849 c = Context()
2850 e = pickle.loads(pickle.dumps(c, proto))
Stefan Krah1919b7e2012-03-21 18:25:23 +01002851
Serhiy Storchakabad12572014-12-15 14:03:42 +02002852 self.assertEqual(c.prec, e.prec)
2853 self.assertEqual(c.Emin, e.Emin)
2854 self.assertEqual(c.Emax, e.Emax)
2855 self.assertEqual(c.rounding, e.rounding)
2856 self.assertEqual(c.capitals, e.capitals)
2857 self.assertEqual(c.clamp, e.clamp)
2858 self.assertEqual(c.flags, e.flags)
2859 self.assertEqual(c.traps, e.traps)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002860
Serhiy Storchakabad12572014-12-15 14:03:42 +02002861 # Test interchangeability
2862 combinations = [(C, P), (P, C)] if C else [(P, P)]
2863 for dumper, loader in combinations:
2864 for ri, _ in enumerate(RoundingModes):
2865 for fi, _ in enumerate(OrderedSignals[dumper]):
2866 for ti, _ in enumerate(OrderedSignals[dumper]):
Stefan Krah1919b7e2012-03-21 18:25:23 +01002867
Serhiy Storchakabad12572014-12-15 14:03:42 +02002868 prec = random.randrange(1, 100)
2869 emin = random.randrange(-100, 0)
2870 emax = random.randrange(1, 100)
2871 caps = random.randrange(2)
2872 clamp = random.randrange(2)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002873
Serhiy Storchakabad12572014-12-15 14:03:42 +02002874 # One module dumps
2875 sys.modules['decimal'] = dumper
2876 c = dumper.Context(
2877 prec=prec, Emin=emin, Emax=emax,
2878 rounding=RoundingModes[ri],
2879 capitals=caps, clamp=clamp,
2880 flags=OrderedSignals[dumper][:fi],
2881 traps=OrderedSignals[dumper][:ti]
2882 )
2883 s = pickle.dumps(c, proto)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002884
Serhiy Storchakabad12572014-12-15 14:03:42 +02002885 # The other module loads
2886 sys.modules['decimal'] = loader
2887 d = pickle.loads(s)
2888 self.assertIsInstance(d, loader.Context)
Stefan Krah1919b7e2012-03-21 18:25:23 +01002889
Serhiy Storchakabad12572014-12-15 14:03:42 +02002890 self.assertEqual(d.prec, prec)
2891 self.assertEqual(d.Emin, emin)
2892 self.assertEqual(d.Emax, emax)
2893 self.assertEqual(d.rounding, RoundingModes[ri])
2894 self.assertEqual(d.capitals, caps)
2895 self.assertEqual(d.clamp, clamp)
2896 assert_signals(self, d, 'flags', OrderedSignals[loader][:fi])
2897 assert_signals(self, d, 'traps', OrderedSignals[loader][:ti])
Stefan Krah1919b7e2012-03-21 18:25:23 +01002898
Serhiy Storchakabad12572014-12-15 14:03:42 +02002899 sys.modules['decimal'] = savedecimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01002900
2901 def test_equality_with_other_types(self):
2902 Decimal = self.decimal.Decimal
2903
2904 self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}])
2905 self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}])
2906
2907 def test_copy(self):
2908 # All copies should be deep
2909 Decimal = self.decimal.Decimal
2910 Context = self.decimal.Context
2911
2912 c = Context()
2913 d = c.copy()
2914 self.assertNotEqual(id(c), id(d))
2915 self.assertNotEqual(id(c.flags), id(d.flags))
2916 self.assertNotEqual(id(c.traps), id(d.traps))
2917 k1 = set(c.flags.keys())
2918 k2 = set(d.flags.keys())
2919 self.assertEqual(k1, k2)
2920 self.assertEqual(c.flags, d.flags)
2921
2922 def test__clamp(self):
2923 # In Python 3.2, the private attribute `_clamp` was made
2924 # public (issue 8540), with the old `_clamp` becoming a
2925 # property wrapping `clamp`. For the duration of Python 3.2
2926 # only, the attribute should be gettable/settable via both
2927 # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be
2928 # removed.
2929 Context = self.decimal.Context
2930 c = Context()
2931 self.assertRaises(AttributeError, getattr, c, '_clamp')
2932
2933 def test_abs(self):
2934 Decimal = self.decimal.Decimal
2935 Context = self.decimal.Context
2936
2937 c = Context()
2938 d = c.abs(Decimal(-1))
2939 self.assertEqual(c.abs(-1), d)
2940 self.assertRaises(TypeError, c.abs, '-1')
2941
2942 def test_add(self):
2943 Decimal = self.decimal.Decimal
2944 Context = self.decimal.Context
2945
2946 c = Context()
2947 d = c.add(Decimal(1), Decimal(1))
2948 self.assertEqual(c.add(1, 1), d)
2949 self.assertEqual(c.add(Decimal(1), 1), d)
2950 self.assertEqual(c.add(1, Decimal(1)), d)
2951 self.assertRaises(TypeError, c.add, '1', 1)
2952 self.assertRaises(TypeError, c.add, 1, '1')
2953
2954 def test_compare(self):
2955 Decimal = self.decimal.Decimal
2956 Context = self.decimal.Context
2957
2958 c = Context()
2959 d = c.compare(Decimal(1), Decimal(1))
2960 self.assertEqual(c.compare(1, 1), d)
2961 self.assertEqual(c.compare(Decimal(1), 1), d)
2962 self.assertEqual(c.compare(1, Decimal(1)), d)
2963 self.assertRaises(TypeError, c.compare, '1', 1)
2964 self.assertRaises(TypeError, c.compare, 1, '1')
2965
2966 def test_compare_signal(self):
2967 Decimal = self.decimal.Decimal
2968 Context = self.decimal.Context
2969
2970 c = Context()
2971 d = c.compare_signal(Decimal(1), Decimal(1))
2972 self.assertEqual(c.compare_signal(1, 1), d)
2973 self.assertEqual(c.compare_signal(Decimal(1), 1), d)
2974 self.assertEqual(c.compare_signal(1, Decimal(1)), d)
2975 self.assertRaises(TypeError, c.compare_signal, '1', 1)
2976 self.assertRaises(TypeError, c.compare_signal, 1, '1')
2977
2978 def test_compare_total(self):
2979 Decimal = self.decimal.Decimal
2980 Context = self.decimal.Context
2981
2982 c = Context()
2983 d = c.compare_total(Decimal(1), Decimal(1))
2984 self.assertEqual(c.compare_total(1, 1), d)
2985 self.assertEqual(c.compare_total(Decimal(1), 1), d)
2986 self.assertEqual(c.compare_total(1, Decimal(1)), d)
2987 self.assertRaises(TypeError, c.compare_total, '1', 1)
2988 self.assertRaises(TypeError, c.compare_total, 1, '1')
2989
2990 def test_compare_total_mag(self):
2991 Decimal = self.decimal.Decimal
2992 Context = self.decimal.Context
2993
2994 c = Context()
2995 d = c.compare_total_mag(Decimal(1), Decimal(1))
2996 self.assertEqual(c.compare_total_mag(1, 1), d)
2997 self.assertEqual(c.compare_total_mag(Decimal(1), 1), d)
2998 self.assertEqual(c.compare_total_mag(1, Decimal(1)), d)
2999 self.assertRaises(TypeError, c.compare_total_mag, '1', 1)
3000 self.assertRaises(TypeError, c.compare_total_mag, 1, '1')
3001
3002 def test_copy_abs(self):
3003 Decimal = self.decimal.Decimal
3004 Context = self.decimal.Context
3005
3006 c = Context()
3007 d = c.copy_abs(Decimal(-1))
3008 self.assertEqual(c.copy_abs(-1), d)
3009 self.assertRaises(TypeError, c.copy_abs, '-1')
3010
3011 def test_copy_decimal(self):
3012 Decimal = self.decimal.Decimal
3013 Context = self.decimal.Context
3014
3015 c = Context()
3016 d = c.copy_decimal(Decimal(-1))
3017 self.assertEqual(c.copy_decimal(-1), d)
3018 self.assertRaises(TypeError, c.copy_decimal, '-1')
3019
3020 def test_copy_negate(self):
3021 Decimal = self.decimal.Decimal
3022 Context = self.decimal.Context
3023
3024 c = Context()
3025 d = c.copy_negate(Decimal(-1))
3026 self.assertEqual(c.copy_negate(-1), d)
3027 self.assertRaises(TypeError, c.copy_negate, '-1')
3028
3029 def test_copy_sign(self):
3030 Decimal = self.decimal.Decimal
3031 Context = self.decimal.Context
3032
3033 c = Context()
3034 d = c.copy_sign(Decimal(1), Decimal(-2))
3035 self.assertEqual(c.copy_sign(1, -2), d)
3036 self.assertEqual(c.copy_sign(Decimal(1), -2), d)
3037 self.assertEqual(c.copy_sign(1, Decimal(-2)), d)
3038 self.assertRaises(TypeError, c.copy_sign, '1', -2)
3039 self.assertRaises(TypeError, c.copy_sign, 1, '-2')
3040
3041 def test_divide(self):
3042 Decimal = self.decimal.Decimal
3043 Context = self.decimal.Context
3044
3045 c = Context()
3046 d = c.divide(Decimal(1), Decimal(2))
3047 self.assertEqual(c.divide(1, 2), d)
3048 self.assertEqual(c.divide(Decimal(1), 2), d)
3049 self.assertEqual(c.divide(1, Decimal(2)), d)
3050 self.assertRaises(TypeError, c.divide, '1', 2)
3051 self.assertRaises(TypeError, c.divide, 1, '2')
3052
3053 def test_divide_int(self):
3054 Decimal = self.decimal.Decimal
3055 Context = self.decimal.Context
3056
3057 c = Context()
3058 d = c.divide_int(Decimal(1), Decimal(2))
3059 self.assertEqual(c.divide_int(1, 2), d)
3060 self.assertEqual(c.divide_int(Decimal(1), 2), d)
3061 self.assertEqual(c.divide_int(1, Decimal(2)), d)
3062 self.assertRaises(TypeError, c.divide_int, '1', 2)
3063 self.assertRaises(TypeError, c.divide_int, 1, '2')
3064
3065 def test_divmod(self):
3066 Decimal = self.decimal.Decimal
3067 Context = self.decimal.Context
3068
3069 c = Context()
3070 d = c.divmod(Decimal(1), Decimal(2))
3071 self.assertEqual(c.divmod(1, 2), d)
3072 self.assertEqual(c.divmod(Decimal(1), 2), d)
3073 self.assertEqual(c.divmod(1, Decimal(2)), d)
3074 self.assertRaises(TypeError, c.divmod, '1', 2)
3075 self.assertRaises(TypeError, c.divmod, 1, '2')
3076
3077 def test_exp(self):
3078 Decimal = self.decimal.Decimal
3079 Context = self.decimal.Context
3080
3081 c = Context()
3082 d = c.exp(Decimal(10))
3083 self.assertEqual(c.exp(10), d)
3084 self.assertRaises(TypeError, c.exp, '10')
3085
3086 def test_fma(self):
3087 Decimal = self.decimal.Decimal
3088 Context = self.decimal.Context
3089
3090 c = Context()
3091 d = c.fma(Decimal(2), Decimal(3), Decimal(4))
3092 self.assertEqual(c.fma(2, 3, 4), d)
3093 self.assertEqual(c.fma(Decimal(2), 3, 4), d)
3094 self.assertEqual(c.fma(2, Decimal(3), 4), d)
3095 self.assertEqual(c.fma(2, 3, Decimal(4)), d)
3096 self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d)
3097 self.assertRaises(TypeError, c.fma, '2', 3, 4)
3098 self.assertRaises(TypeError, c.fma, 2, '3', 4)
3099 self.assertRaises(TypeError, c.fma, 2, 3, '4')
3100
3101 # Issue 12079 for Context.fma ...
3102 self.assertRaises(TypeError, c.fma,
3103 Decimal('Infinity'), Decimal(0), "not a decimal")
3104 self.assertRaises(TypeError, c.fma,
3105 Decimal(1), Decimal('snan'), 1.222)
3106 # ... and for Decimal.fma.
3107 self.assertRaises(TypeError, Decimal('Infinity').fma,
3108 Decimal(0), "not a decimal")
3109 self.assertRaises(TypeError, Decimal(1).fma,
3110 Decimal('snan'), 1.222)
3111
3112 def test_is_finite(self):
3113 Decimal = self.decimal.Decimal
3114 Context = self.decimal.Context
3115
3116 c = Context()
3117 d = c.is_finite(Decimal(10))
3118 self.assertEqual(c.is_finite(10), d)
3119 self.assertRaises(TypeError, c.is_finite, '10')
3120
3121 def test_is_infinite(self):
3122 Decimal = self.decimal.Decimal
3123 Context = self.decimal.Context
3124
3125 c = Context()
3126 d = c.is_infinite(Decimal(10))
3127 self.assertEqual(c.is_infinite(10), d)
3128 self.assertRaises(TypeError, c.is_infinite, '10')
3129
3130 def test_is_nan(self):
3131 Decimal = self.decimal.Decimal
3132 Context = self.decimal.Context
3133
3134 c = Context()
3135 d = c.is_nan(Decimal(10))
3136 self.assertEqual(c.is_nan(10), d)
3137 self.assertRaises(TypeError, c.is_nan, '10')
3138
3139 def test_is_normal(self):
3140 Decimal = self.decimal.Decimal
3141 Context = self.decimal.Context
3142
3143 c = Context()
3144 d = c.is_normal(Decimal(10))
3145 self.assertEqual(c.is_normal(10), d)
3146 self.assertRaises(TypeError, c.is_normal, '10')
3147
3148 def test_is_qnan(self):
3149 Decimal = self.decimal.Decimal
3150 Context = self.decimal.Context
3151
3152 c = Context()
3153 d = c.is_qnan(Decimal(10))
3154 self.assertEqual(c.is_qnan(10), d)
3155 self.assertRaises(TypeError, c.is_qnan, '10')
3156
3157 def test_is_signed(self):
3158 Decimal = self.decimal.Decimal
3159 Context = self.decimal.Context
3160
3161 c = Context()
3162 d = c.is_signed(Decimal(10))
3163 self.assertEqual(c.is_signed(10), d)
3164 self.assertRaises(TypeError, c.is_signed, '10')
3165
3166 def test_is_snan(self):
3167 Decimal = self.decimal.Decimal
3168 Context = self.decimal.Context
3169
3170 c = Context()
3171 d = c.is_snan(Decimal(10))
3172 self.assertEqual(c.is_snan(10), d)
3173 self.assertRaises(TypeError, c.is_snan, '10')
3174
3175 def test_is_subnormal(self):
3176 Decimal = self.decimal.Decimal
3177 Context = self.decimal.Context
3178
3179 c = Context()
3180 d = c.is_subnormal(Decimal(10))
3181 self.assertEqual(c.is_subnormal(10), d)
3182 self.assertRaises(TypeError, c.is_subnormal, '10')
3183
3184 def test_is_zero(self):
3185 Decimal = self.decimal.Decimal
3186 Context = self.decimal.Context
3187
3188 c = Context()
3189 d = c.is_zero(Decimal(10))
3190 self.assertEqual(c.is_zero(10), d)
3191 self.assertRaises(TypeError, c.is_zero, '10')
3192
3193 def test_ln(self):
3194 Decimal = self.decimal.Decimal
3195 Context = self.decimal.Context
3196
3197 c = Context()
3198 d = c.ln(Decimal(10))
3199 self.assertEqual(c.ln(10), d)
3200 self.assertRaises(TypeError, c.ln, '10')
3201
3202 def test_log10(self):
3203 Decimal = self.decimal.Decimal
3204 Context = self.decimal.Context
3205
3206 c = Context()
3207 d = c.log10(Decimal(10))
3208 self.assertEqual(c.log10(10), d)
3209 self.assertRaises(TypeError, c.log10, '10')
3210
3211 def test_logb(self):
3212 Decimal = self.decimal.Decimal
3213 Context = self.decimal.Context
3214
3215 c = Context()
3216 d = c.logb(Decimal(10))
3217 self.assertEqual(c.logb(10), d)
3218 self.assertRaises(TypeError, c.logb, '10')
3219
3220 def test_logical_and(self):
3221 Decimal = self.decimal.Decimal
3222 Context = self.decimal.Context
3223
3224 c = Context()
3225 d = c.logical_and(Decimal(1), Decimal(1))
3226 self.assertEqual(c.logical_and(1, 1), d)
3227 self.assertEqual(c.logical_and(Decimal(1), 1), d)
3228 self.assertEqual(c.logical_and(1, Decimal(1)), d)
3229 self.assertRaises(TypeError, c.logical_and, '1', 1)
3230 self.assertRaises(TypeError, c.logical_and, 1, '1')
3231
3232 def test_logical_invert(self):
3233 Decimal = self.decimal.Decimal
3234 Context = self.decimal.Context
3235
3236 c = Context()
3237 d = c.logical_invert(Decimal(1000))
3238 self.assertEqual(c.logical_invert(1000), d)
3239 self.assertRaises(TypeError, c.logical_invert, '1000')
3240
3241 def test_logical_or(self):
3242 Decimal = self.decimal.Decimal
3243 Context = self.decimal.Context
3244
3245 c = Context()
3246 d = c.logical_or(Decimal(1), Decimal(1))
3247 self.assertEqual(c.logical_or(1, 1), d)
3248 self.assertEqual(c.logical_or(Decimal(1), 1), d)
3249 self.assertEqual(c.logical_or(1, Decimal(1)), d)
3250 self.assertRaises(TypeError, c.logical_or, '1', 1)
3251 self.assertRaises(TypeError, c.logical_or, 1, '1')
3252
3253 def test_logical_xor(self):
3254 Decimal = self.decimal.Decimal
3255 Context = self.decimal.Context
3256
3257 c = Context()
3258 d = c.logical_xor(Decimal(1), Decimal(1))
3259 self.assertEqual(c.logical_xor(1, 1), d)
3260 self.assertEqual(c.logical_xor(Decimal(1), 1), d)
3261 self.assertEqual(c.logical_xor(1, Decimal(1)), d)
3262 self.assertRaises(TypeError, c.logical_xor, '1', 1)
3263 self.assertRaises(TypeError, c.logical_xor, 1, '1')
3264
3265 def test_max(self):
3266 Decimal = self.decimal.Decimal
3267 Context = self.decimal.Context
3268
3269 c = Context()
3270 d = c.max(Decimal(1), Decimal(2))
3271 self.assertEqual(c.max(1, 2), d)
3272 self.assertEqual(c.max(Decimal(1), 2), d)
3273 self.assertEqual(c.max(1, Decimal(2)), d)
3274 self.assertRaises(TypeError, c.max, '1', 2)
3275 self.assertRaises(TypeError, c.max, 1, '2')
3276
3277 def test_max_mag(self):
3278 Decimal = self.decimal.Decimal
3279 Context = self.decimal.Context
3280
3281 c = Context()
3282 d = c.max_mag(Decimal(1), Decimal(2))
3283 self.assertEqual(c.max_mag(1, 2), d)
3284 self.assertEqual(c.max_mag(Decimal(1), 2), d)
3285 self.assertEqual(c.max_mag(1, Decimal(2)), d)
3286 self.assertRaises(TypeError, c.max_mag, '1', 2)
3287 self.assertRaises(TypeError, c.max_mag, 1, '2')
3288
3289 def test_min(self):
3290 Decimal = self.decimal.Decimal
3291 Context = self.decimal.Context
3292
3293 c = Context()
3294 d = c.min(Decimal(1), Decimal(2))
3295 self.assertEqual(c.min(1, 2), d)
3296 self.assertEqual(c.min(Decimal(1), 2), d)
3297 self.assertEqual(c.min(1, Decimal(2)), d)
3298 self.assertRaises(TypeError, c.min, '1', 2)
3299 self.assertRaises(TypeError, c.min, 1, '2')
3300
3301 def test_min_mag(self):
3302 Decimal = self.decimal.Decimal
3303 Context = self.decimal.Context
3304
3305 c = Context()
3306 d = c.min_mag(Decimal(1), Decimal(2))
3307 self.assertEqual(c.min_mag(1, 2), d)
3308 self.assertEqual(c.min_mag(Decimal(1), 2), d)
3309 self.assertEqual(c.min_mag(1, Decimal(2)), d)
3310 self.assertRaises(TypeError, c.min_mag, '1', 2)
3311 self.assertRaises(TypeError, c.min_mag, 1, '2')
3312
3313 def test_minus(self):
3314 Decimal = self.decimal.Decimal
3315 Context = self.decimal.Context
3316
3317 c = Context()
3318 d = c.minus(Decimal(10))
3319 self.assertEqual(c.minus(10), d)
3320 self.assertRaises(TypeError, c.minus, '10')
3321
3322 def test_multiply(self):
3323 Decimal = self.decimal.Decimal
3324 Context = self.decimal.Context
3325
3326 c = Context()
3327 d = c.multiply(Decimal(1), Decimal(2))
3328 self.assertEqual(c.multiply(1, 2), d)
3329 self.assertEqual(c.multiply(Decimal(1), 2), d)
3330 self.assertEqual(c.multiply(1, Decimal(2)), d)
3331 self.assertRaises(TypeError, c.multiply, '1', 2)
3332 self.assertRaises(TypeError, c.multiply, 1, '2')
3333
3334 def test_next_minus(self):
3335 Decimal = self.decimal.Decimal
3336 Context = self.decimal.Context
3337
3338 c = Context()
3339 d = c.next_minus(Decimal(10))
3340 self.assertEqual(c.next_minus(10), d)
3341 self.assertRaises(TypeError, c.next_minus, '10')
3342
3343 def test_next_plus(self):
3344 Decimal = self.decimal.Decimal
3345 Context = self.decimal.Context
3346
3347 c = Context()
3348 d = c.next_plus(Decimal(10))
3349 self.assertEqual(c.next_plus(10), d)
3350 self.assertRaises(TypeError, c.next_plus, '10')
3351
3352 def test_next_toward(self):
3353 Decimal = self.decimal.Decimal
3354 Context = self.decimal.Context
3355
3356 c = Context()
3357 d = c.next_toward(Decimal(1), Decimal(2))
3358 self.assertEqual(c.next_toward(1, 2), d)
3359 self.assertEqual(c.next_toward(Decimal(1), 2), d)
3360 self.assertEqual(c.next_toward(1, Decimal(2)), d)
3361 self.assertRaises(TypeError, c.next_toward, '1', 2)
3362 self.assertRaises(TypeError, c.next_toward, 1, '2')
3363
3364 def test_normalize(self):
3365 Decimal = self.decimal.Decimal
3366 Context = self.decimal.Context
3367
3368 c = Context()
3369 d = c.normalize(Decimal(10))
3370 self.assertEqual(c.normalize(10), d)
3371 self.assertRaises(TypeError, c.normalize, '10')
3372
3373 def test_number_class(self):
3374 Decimal = self.decimal.Decimal
3375 Context = self.decimal.Context
3376
3377 c = Context()
3378 self.assertEqual(c.number_class(123), c.number_class(Decimal(123)))
3379 self.assertEqual(c.number_class(0), c.number_class(Decimal(0)))
3380 self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45)))
3381
3382 def test_plus(self):
3383 Decimal = self.decimal.Decimal
3384 Context = self.decimal.Context
3385
3386 c = Context()
3387 d = c.plus(Decimal(10))
3388 self.assertEqual(c.plus(10), d)
3389 self.assertRaises(TypeError, c.plus, '10')
3390
3391 def test_power(self):
3392 Decimal = self.decimal.Decimal
3393 Context = self.decimal.Context
3394
3395 c = Context()
3396 d = c.power(Decimal(1), Decimal(4))
3397 self.assertEqual(c.power(1, 4), d)
3398 self.assertEqual(c.power(Decimal(1), 4), d)
3399 self.assertEqual(c.power(1, Decimal(4)), d)
3400 self.assertEqual(c.power(Decimal(1), Decimal(4)), d)
3401 self.assertRaises(TypeError, c.power, '1', 4)
3402 self.assertRaises(TypeError, c.power, 1, '4')
3403 self.assertEqual(c.power(modulo=5, b=8, a=2), 1)
3404
3405 def test_quantize(self):
3406 Decimal = self.decimal.Decimal
3407 Context = self.decimal.Context
3408
3409 c = Context()
3410 d = c.quantize(Decimal(1), Decimal(2))
3411 self.assertEqual(c.quantize(1, 2), d)
3412 self.assertEqual(c.quantize(Decimal(1), 2), d)
3413 self.assertEqual(c.quantize(1, Decimal(2)), d)
3414 self.assertRaises(TypeError, c.quantize, '1', 2)
3415 self.assertRaises(TypeError, c.quantize, 1, '2')
3416
3417 def test_remainder(self):
3418 Decimal = self.decimal.Decimal
3419 Context = self.decimal.Context
3420
3421 c = Context()
3422 d = c.remainder(Decimal(1), Decimal(2))
3423 self.assertEqual(c.remainder(1, 2), d)
3424 self.assertEqual(c.remainder(Decimal(1), 2), d)
3425 self.assertEqual(c.remainder(1, Decimal(2)), d)
3426 self.assertRaises(TypeError, c.remainder, '1', 2)
3427 self.assertRaises(TypeError, c.remainder, 1, '2')
3428
3429 def test_remainder_near(self):
3430 Decimal = self.decimal.Decimal
3431 Context = self.decimal.Context
3432
3433 c = Context()
3434 d = c.remainder_near(Decimal(1), Decimal(2))
3435 self.assertEqual(c.remainder_near(1, 2), d)
3436 self.assertEqual(c.remainder_near(Decimal(1), 2), d)
3437 self.assertEqual(c.remainder_near(1, Decimal(2)), d)
3438 self.assertRaises(TypeError, c.remainder_near, '1', 2)
3439 self.assertRaises(TypeError, c.remainder_near, 1, '2')
3440
3441 def test_rotate(self):
3442 Decimal = self.decimal.Decimal
3443 Context = self.decimal.Context
3444
3445 c = Context()
3446 d = c.rotate(Decimal(1), Decimal(2))
3447 self.assertEqual(c.rotate(1, 2), d)
3448 self.assertEqual(c.rotate(Decimal(1), 2), d)
3449 self.assertEqual(c.rotate(1, Decimal(2)), d)
3450 self.assertRaises(TypeError, c.rotate, '1', 2)
3451 self.assertRaises(TypeError, c.rotate, 1, '2')
3452
3453 def test_sqrt(self):
3454 Decimal = self.decimal.Decimal
3455 Context = self.decimal.Context
3456
3457 c = Context()
3458 d = c.sqrt(Decimal(10))
3459 self.assertEqual(c.sqrt(10), d)
3460 self.assertRaises(TypeError, c.sqrt, '10')
3461
3462 def test_same_quantum(self):
3463 Decimal = self.decimal.Decimal
3464 Context = self.decimal.Context
3465
3466 c = Context()
3467 d = c.same_quantum(Decimal(1), Decimal(2))
3468 self.assertEqual(c.same_quantum(1, 2), d)
3469 self.assertEqual(c.same_quantum(Decimal(1), 2), d)
3470 self.assertEqual(c.same_quantum(1, Decimal(2)), d)
3471 self.assertRaises(TypeError, c.same_quantum, '1', 2)
3472 self.assertRaises(TypeError, c.same_quantum, 1, '2')
3473
3474 def test_scaleb(self):
3475 Decimal = self.decimal.Decimal
3476 Context = self.decimal.Context
3477
3478 c = Context()
3479 d = c.scaleb(Decimal(1), Decimal(2))
3480 self.assertEqual(c.scaleb(1, 2), d)
3481 self.assertEqual(c.scaleb(Decimal(1), 2), d)
3482 self.assertEqual(c.scaleb(1, Decimal(2)), d)
3483 self.assertRaises(TypeError, c.scaleb, '1', 2)
3484 self.assertRaises(TypeError, c.scaleb, 1, '2')
3485
3486 def test_shift(self):
3487 Decimal = self.decimal.Decimal
3488 Context = self.decimal.Context
3489
3490 c = Context()
3491 d = c.shift(Decimal(1), Decimal(2))
3492 self.assertEqual(c.shift(1, 2), d)
3493 self.assertEqual(c.shift(Decimal(1), 2), d)
3494 self.assertEqual(c.shift(1, Decimal(2)), d)
3495 self.assertRaises(TypeError, c.shift, '1', 2)
3496 self.assertRaises(TypeError, c.shift, 1, '2')
3497
3498 def test_subtract(self):
3499 Decimal = self.decimal.Decimal
3500 Context = self.decimal.Context
3501
3502 c = Context()
3503 d = c.subtract(Decimal(1), Decimal(2))
3504 self.assertEqual(c.subtract(1, 2), d)
3505 self.assertEqual(c.subtract(Decimal(1), 2), d)
3506 self.assertEqual(c.subtract(1, Decimal(2)), d)
3507 self.assertRaises(TypeError, c.subtract, '1', 2)
3508 self.assertRaises(TypeError, c.subtract, 1, '2')
3509
3510 def test_to_eng_string(self):
3511 Decimal = self.decimal.Decimal
3512 Context = self.decimal.Context
3513
3514 c = Context()
3515 d = c.to_eng_string(Decimal(10))
3516 self.assertEqual(c.to_eng_string(10), d)
3517 self.assertRaises(TypeError, c.to_eng_string, '10')
3518
3519 def test_to_sci_string(self):
3520 Decimal = self.decimal.Decimal
3521 Context = self.decimal.Context
3522
3523 c = Context()
3524 d = c.to_sci_string(Decimal(10))
3525 self.assertEqual(c.to_sci_string(10), d)
3526 self.assertRaises(TypeError, c.to_sci_string, '10')
3527
3528 def test_to_integral_exact(self):
3529 Decimal = self.decimal.Decimal
3530 Context = self.decimal.Context
3531
3532 c = Context()
3533 d = c.to_integral_exact(Decimal(10))
3534 self.assertEqual(c.to_integral_exact(10), d)
3535 self.assertRaises(TypeError, c.to_integral_exact, '10')
3536
3537 def test_to_integral_value(self):
3538 Decimal = self.decimal.Decimal
3539 Context = self.decimal.Context
3540
3541 c = Context()
3542 d = c.to_integral_value(Decimal(10))
3543 self.assertEqual(c.to_integral_value(10), d)
3544 self.assertRaises(TypeError, c.to_integral_value, '10')
3545 self.assertRaises(TypeError, c.to_integral_value, 10, 'x')
3546
3547class CContextAPItests(ContextAPItests):
3548 decimal = C
3549class PyContextAPItests(ContextAPItests):
3550 decimal = P
3551
3552class ContextWithStatement(unittest.TestCase):
3553 # Can't do these as docstrings until Python 2.6
3554 # as doctest can't handle __future__ statements
3555
3556 def test_localcontext(self):
3557 # Use a copy of the current context in the block
3558 getcontext = self.decimal.getcontext
3559 localcontext = self.decimal.localcontext
3560
3561 orig_ctx = getcontext()
3562 with localcontext() as enter_ctx:
3563 set_ctx = getcontext()
3564 final_ctx = getcontext()
3565 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3566 self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context')
3567 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3568
3569 def test_localcontextarg(self):
3570 # Use a copy of the supplied context in the block
3571 Context = self.decimal.Context
3572 getcontext = self.decimal.getcontext
3573 localcontext = self.decimal.localcontext
3574
3575 localcontext = self.decimal.localcontext
3576 orig_ctx = getcontext()
3577 new_ctx = Context(prec=42)
3578 with localcontext(new_ctx) as enter_ctx:
3579 set_ctx = getcontext()
3580 final_ctx = getcontext()
3581 self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly')
3582 self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context')
3583 self.assertIsNot(new_ctx, set_ctx, 'did not copy the context')
3584 self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
3585
3586 def test_nested_with_statements(self):
3587 # Use a copy of the supplied context in the block
3588 Decimal = self.decimal.Decimal
3589 Context = self.decimal.Context
3590 getcontext = self.decimal.getcontext
3591 localcontext = self.decimal.localcontext
3592 Clamped = self.decimal.Clamped
3593 Overflow = self.decimal.Overflow
3594
3595 orig_ctx = getcontext()
3596 orig_ctx.clear_flags()
3597 new_ctx = Context(Emax=384)
3598 with localcontext() as c1:
3599 self.assertEqual(c1.flags, orig_ctx.flags)
3600 self.assertEqual(c1.traps, orig_ctx.traps)
3601 c1.traps[Clamped] = True
3602 c1.Emin = -383
3603 self.assertNotEqual(orig_ctx.Emin, -383)
3604 self.assertRaises(Clamped, c1.create_decimal, '0e-999')
3605 self.assertTrue(c1.flags[Clamped])
3606 with localcontext(new_ctx) as c2:
3607 self.assertEqual(c2.flags, new_ctx.flags)
3608 self.assertEqual(c2.traps, new_ctx.traps)
3609 self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2)
3610 self.assertFalse(c2.flags[Clamped])
3611 self.assertTrue(c2.flags[Overflow])
3612 del c2
3613 self.assertFalse(c1.flags[Overflow])
3614 del c1
3615 self.assertNotEqual(orig_ctx.Emin, -383)
3616 self.assertFalse(orig_ctx.flags[Clamped])
3617 self.assertFalse(orig_ctx.flags[Overflow])
3618 self.assertFalse(new_ctx.flags[Clamped])
3619 self.assertFalse(new_ctx.flags[Overflow])
3620
3621 def test_with_statements_gc1(self):
3622 localcontext = self.decimal.localcontext
3623
3624 with localcontext() as c1:
3625 del c1
3626 with localcontext() as c2:
3627 del c2
3628 with localcontext() as c3:
3629 del c3
3630 with localcontext() as c4:
3631 del c4
3632
3633 def test_with_statements_gc2(self):
3634 localcontext = self.decimal.localcontext
3635
3636 with localcontext() as c1:
3637 with localcontext(c1) as c2:
3638 del c1
3639 with localcontext(c2) as c3:
3640 del c2
3641 with localcontext(c3) as c4:
3642 del c3
3643 del c4
3644
3645 def test_with_statements_gc3(self):
3646 Context = self.decimal.Context
3647 localcontext = self.decimal.localcontext
3648 getcontext = self.decimal.getcontext
3649 setcontext = self.decimal.setcontext
3650
3651 with localcontext() as c1:
3652 del c1
3653 n1 = Context(prec=1)
3654 setcontext(n1)
3655 with localcontext(n1) as c2:
3656 del n1
3657 self.assertEqual(c2.prec, 1)
3658 del c2
3659 n2 = Context(prec=2)
3660 setcontext(n2)
3661 del n2
3662 self.assertEqual(getcontext().prec, 2)
3663 n3 = Context(prec=3)
3664 setcontext(n3)
3665 self.assertEqual(getcontext().prec, 3)
3666 with localcontext(n3) as c3:
3667 del n3
3668 self.assertEqual(c3.prec, 3)
3669 del c3
3670 n4 = Context(prec=4)
3671 setcontext(n4)
3672 del n4
3673 self.assertEqual(getcontext().prec, 4)
3674 with localcontext() as c4:
3675 self.assertEqual(c4.prec, 4)
3676 del c4
3677
3678class CContextWithStatement(ContextWithStatement):
3679 decimal = C
3680class PyContextWithStatement(ContextWithStatement):
3681 decimal = P
3682
3683class ContextFlags(unittest.TestCase):
3684
3685 def test_flags_irrelevant(self):
3686 # check that the result (numeric result + flags raised) of an
3687 # arithmetic operation doesn't depend on the current flags
3688 Decimal = self.decimal.Decimal
3689 Context = self.decimal.Context
3690 Inexact = self.decimal.Inexact
3691 Rounded = self.decimal.Rounded
3692 Underflow = self.decimal.Underflow
3693 Clamped = self.decimal.Clamped
3694 Subnormal = self.decimal.Subnormal
Stefan Krah1919b7e2012-03-21 18:25:23 +01003695
3696 def raise_error(context, flag):
3697 if self.decimal == C:
3698 context.flags[flag] = True
3699 if context.traps[flag]:
3700 raise flag
3701 else:
3702 context._raise_error(flag)
3703
3704 context = Context(prec=9, Emin = -425000000, Emax = 425000000,
3705 rounding=ROUND_HALF_EVEN, traps=[], flags=[])
3706
3707 # operations that raise various flags, in the form (function, arglist)
3708 operations = [
3709 (context._apply, [Decimal("100E-425000010")]),
3710 (context.sqrt, [Decimal(2)]),
3711 (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
3712 (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
3713 (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]),
3714 ]
3715
3716 # try various flags individually, then a whole lot at once
3717 flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal],
3718 [Inexact, Rounded, Underflow, Clamped, Subnormal]]
3719
3720 for fn, args in operations:
3721 # find answer and flags raised using a clean context
3722 context.clear_flags()
3723 ans = fn(*args)
3724 flags = [k for k, v in context.flags.items() if v]
3725
3726 for extra_flags in flagsets:
3727 # set flags, before calling operation
3728 context.clear_flags()
3729 for flag in extra_flags:
3730 raise_error(context, flag)
3731 new_ans = fn(*args)
3732
3733 # flags that we expect to be set after the operation
3734 expected_flags = list(flags)
3735 for flag in extra_flags:
3736 if flag not in expected_flags:
3737 expected_flags.append(flag)
3738 expected_flags.sort(key=id)
3739
3740 # flags we actually got
3741 new_flags = [k for k,v in context.flags.items() if v]
3742 new_flags.sort(key=id)
3743
3744 self.assertEqual(ans, new_ans,
3745 "operation produces different answers depending on flags set: " +
3746 "expected %s, got %s." % (ans, new_ans))
3747 self.assertEqual(new_flags, expected_flags,
3748 "operation raises different flags depending on flags set: " +
3749 "expected %s, got %s" % (expected_flags, new_flags))
3750
3751 def test_flag_comparisons(self):
3752 Context = self.decimal.Context
3753 Inexact = self.decimal.Inexact
3754 Rounded = self.decimal.Rounded
3755
3756 c = Context()
3757
3758 # Valid SignalDict
3759 self.assertNotEqual(c.flags, c.traps)
3760 self.assertNotEqual(c.traps, c.flags)
3761
3762 c.flags = c.traps
3763 self.assertEqual(c.flags, c.traps)
3764 self.assertEqual(c.traps, c.flags)
3765
3766 c.flags[Rounded] = True
3767 c.traps = c.flags
3768 self.assertEqual(c.flags, c.traps)
3769 self.assertEqual(c.traps, c.flags)
3770
3771 d = {}
3772 d.update(c.flags)
3773 self.assertEqual(d, c.flags)
3774 self.assertEqual(c.flags, d)
3775
3776 d[Inexact] = True
3777 self.assertNotEqual(d, c.flags)
3778 self.assertNotEqual(c.flags, d)
3779
3780 # Invalid SignalDict
3781 d = {Inexact:False}
3782 self.assertNotEqual(d, c.flags)
3783 self.assertNotEqual(c.flags, d)
3784
3785 d = ["xyz"]
3786 self.assertNotEqual(d, c.flags)
3787 self.assertNotEqual(c.flags, d)
3788
3789 @requires_IEEE_754
3790 def test_float_operation(self):
3791 Decimal = self.decimal.Decimal
3792 FloatOperation = self.decimal.FloatOperation
3793 localcontext = self.decimal.localcontext
3794
3795 with localcontext() as c:
3796 ##### trap is off by default
3797 self.assertFalse(c.traps[FloatOperation])
3798
3799 # implicit conversion sets the flag
3800 c.clear_flags()
3801 self.assertEqual(Decimal(7.5), 7.5)
3802 self.assertTrue(c.flags[FloatOperation])
3803
3804 c.clear_flags()
3805 self.assertEqual(c.create_decimal(7.5), 7.5)
3806 self.assertTrue(c.flags[FloatOperation])
3807
3808 # explicit conversion does not set the flag
3809 c.clear_flags()
3810 x = Decimal.from_float(7.5)
3811 self.assertFalse(c.flags[FloatOperation])
3812 # comparison sets the flag
3813 self.assertEqual(x, 7.5)
3814 self.assertTrue(c.flags[FloatOperation])
3815
3816 c.clear_flags()
3817 x = c.create_decimal_from_float(7.5)
3818 self.assertFalse(c.flags[FloatOperation])
3819 self.assertEqual(x, 7.5)
3820 self.assertTrue(c.flags[FloatOperation])
3821
3822 ##### set the trap
3823 c.traps[FloatOperation] = True
3824
3825 # implicit conversion raises
3826 c.clear_flags()
3827 self.assertRaises(FloatOperation, Decimal, 7.5)
3828 self.assertTrue(c.flags[FloatOperation])
3829
3830 c.clear_flags()
3831 self.assertRaises(FloatOperation, c.create_decimal, 7.5)
3832 self.assertTrue(c.flags[FloatOperation])
3833
3834 # explicit conversion is silent
3835 c.clear_flags()
3836 x = Decimal.from_float(7.5)
3837 self.assertFalse(c.flags[FloatOperation])
3838
3839 c.clear_flags()
3840 x = c.create_decimal_from_float(7.5)
3841 self.assertFalse(c.flags[FloatOperation])
3842
3843 def test_float_comparison(self):
3844 Decimal = self.decimal.Decimal
3845 Context = self.decimal.Context
3846 FloatOperation = self.decimal.FloatOperation
3847 localcontext = self.decimal.localcontext
3848
3849 def assert_attr(a, b, attr, context, signal=None):
3850 context.clear_flags()
3851 f = getattr(a, attr)
3852 if signal == FloatOperation:
3853 self.assertRaises(signal, f, b)
3854 else:
3855 self.assertIs(f(b), True)
3856 self.assertTrue(context.flags[FloatOperation])
3857
3858 small_d = Decimal('0.25')
3859 big_d = Decimal('3.0')
3860 small_f = 0.25
3861 big_f = 3.0
3862
3863 zero_d = Decimal('0.0')
3864 neg_zero_d = Decimal('-0.0')
3865 zero_f = 0.0
3866 neg_zero_f = -0.0
3867
3868 inf_d = Decimal('Infinity')
3869 neg_inf_d = Decimal('-Infinity')
3870 inf_f = float('inf')
3871 neg_inf_f = float('-inf')
3872
3873 def doit(c, signal=None):
3874 # Order
3875 for attr in '__lt__', '__le__':
3876 assert_attr(small_d, big_f, attr, c, signal)
3877
3878 for attr in '__gt__', '__ge__':
3879 assert_attr(big_d, small_f, attr, c, signal)
3880
3881 # Equality
3882 assert_attr(small_d, small_f, '__eq__', c, None)
3883
3884 assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None)
3885 assert_attr(neg_zero_d, zero_f, '__eq__', c, None)
3886
3887 assert_attr(zero_d, neg_zero_f, '__eq__', c, None)
3888 assert_attr(zero_d, zero_f, '__eq__', c, None)
3889
3890 assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None)
3891 assert_attr(inf_d, inf_f, '__eq__', c, None)
3892
3893 # Inequality
3894 assert_attr(small_d, big_f, '__ne__', c, None)
3895
3896 assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None)
3897
3898 assert_attr(neg_inf_d, inf_f, '__ne__', c, None)
3899 assert_attr(inf_d, neg_inf_f, '__ne__', c, None)
3900
3901 assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None)
3902
3903 def test_containers(c, signal=None):
3904 c.clear_flags()
3905 s = set([100.0, Decimal('100.0')])
3906 self.assertEqual(len(s), 1)
3907 self.assertTrue(c.flags[FloatOperation])
3908
3909 c.clear_flags()
3910 if signal:
3911 self.assertRaises(signal, sorted, [1.0, Decimal('10.0')])
3912 else:
3913 s = sorted([10.0, Decimal('10.0')])
3914 self.assertTrue(c.flags[FloatOperation])
3915
3916 c.clear_flags()
3917 b = 10.0 in [Decimal('10.0'), 1.0]
3918 self.assertTrue(c.flags[FloatOperation])
3919
3920 c.clear_flags()
3921 b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'}
3922 self.assertTrue(c.flags[FloatOperation])
3923
3924 nc = Context()
3925 with localcontext(nc) as c:
3926 self.assertFalse(c.traps[FloatOperation])
3927 doit(c, signal=None)
3928 test_containers(c, signal=None)
3929
3930 c.traps[FloatOperation] = True
3931 doit(c, signal=FloatOperation)
3932 test_containers(c, signal=FloatOperation)
3933
3934 def test_float_operation_default(self):
3935 Decimal = self.decimal.Decimal
3936 Context = self.decimal.Context
3937 Inexact = self.decimal.Inexact
3938 FloatOperation= self.decimal.FloatOperation
3939
3940 context = Context()
3941 self.assertFalse(context.flags[FloatOperation])
3942 self.assertFalse(context.traps[FloatOperation])
3943
3944 context.clear_traps()
3945 context.traps[Inexact] = True
3946 context.traps[FloatOperation] = True
3947 self.assertTrue(context.traps[FloatOperation])
3948 self.assertTrue(context.traps[Inexact])
3949
3950class CContextFlags(ContextFlags):
3951 decimal = C
3952class PyContextFlags(ContextFlags):
3953 decimal = P
3954
3955class SpecialContexts(unittest.TestCase):
3956 """Test the context templates."""
3957
3958 def test_context_templates(self):
3959 BasicContext = self.decimal.BasicContext
3960 ExtendedContext = self.decimal.ExtendedContext
3961 getcontext = self.decimal.getcontext
3962 setcontext = self.decimal.setcontext
3963 InvalidOperation = self.decimal.InvalidOperation
3964 DivisionByZero = self.decimal.DivisionByZero
3965 Overflow = self.decimal.Overflow
3966 Underflow = self.decimal.Underflow
3967 Clamped = self.decimal.Clamped
3968
3969 assert_signals(self, BasicContext, 'traps',
3970 [InvalidOperation, DivisionByZero, Overflow, Underflow, Clamped]
3971 )
3972
3973 savecontext = getcontext().copy()
3974 basic_context_prec = BasicContext.prec
3975 extended_context_prec = ExtendedContext.prec
3976
3977 ex = None
3978 try:
3979 BasicContext.prec = ExtendedContext.prec = 441
3980 for template in BasicContext, ExtendedContext:
3981 setcontext(template)
3982 c = getcontext()
3983 self.assertIsNot(c, template)
3984 self.assertEqual(c.prec, 441)
3985 except Exception as e:
3986 ex = e.__class__
3987 finally:
3988 BasicContext.prec = basic_context_prec
3989 ExtendedContext.prec = extended_context_prec
3990 setcontext(savecontext)
3991 if ex:
3992 raise ex
3993
3994 def test_default_context(self):
3995 DefaultContext = self.decimal.DefaultContext
3996 BasicContext = self.decimal.BasicContext
3997 ExtendedContext = self.decimal.ExtendedContext
3998 getcontext = self.decimal.getcontext
3999 setcontext = self.decimal.setcontext
4000 InvalidOperation = self.decimal.InvalidOperation
4001 DivisionByZero = self.decimal.DivisionByZero
4002 Overflow = self.decimal.Overflow
4003
4004 self.assertEqual(BasicContext.prec, 9)
4005 self.assertEqual(ExtendedContext.prec, 9)
4006
4007 assert_signals(self, DefaultContext, 'traps',
4008 [InvalidOperation, DivisionByZero, Overflow]
4009 )
4010
4011 savecontext = getcontext().copy()
4012 default_context_prec = DefaultContext.prec
4013
4014 ex = None
4015 try:
4016 c = getcontext()
4017 saveprec = c.prec
4018
4019 DefaultContext.prec = 961
4020 c = getcontext()
4021 self.assertEqual(c.prec, saveprec)
4022
4023 setcontext(DefaultContext)
4024 c = getcontext()
4025 self.assertIsNot(c, DefaultContext)
4026 self.assertEqual(c.prec, 961)
4027 except Exception as e:
4028 ex = e.__class__
4029 finally:
4030 DefaultContext.prec = default_context_prec
4031 setcontext(savecontext)
4032 if ex:
4033 raise ex
4034
4035class CSpecialContexts(SpecialContexts):
4036 decimal = C
4037class PySpecialContexts(SpecialContexts):
4038 decimal = P
4039
4040class ContextInputValidation(unittest.TestCase):
4041
4042 def test_invalid_context(self):
4043 Context = self.decimal.Context
4044 DefaultContext = self.decimal.DefaultContext
4045
4046 c = DefaultContext.copy()
4047
4048 # prec, Emax
4049 for attr in ['prec', 'Emax']:
4050 setattr(c, attr, 999999)
4051 self.assertEqual(getattr(c, attr), 999999)
4052 self.assertRaises(ValueError, setattr, c, attr, -1)
4053 self.assertRaises(TypeError, setattr, c, attr, 'xyz')
4054
4055 # Emin
4056 setattr(c, 'Emin', -999999)
4057 self.assertEqual(getattr(c, 'Emin'), -999999)
4058 self.assertRaises(ValueError, setattr, c, 'Emin', 1)
4059 self.assertRaises(TypeError, setattr, c, 'Emin', (1,2,3))
4060
Stefan Krah1919b7e2012-03-21 18:25:23 +01004061 self.assertRaises(TypeError, setattr, c, 'rounding', -1)
4062 self.assertRaises(TypeError, setattr, c, 'rounding', 9)
4063 self.assertRaises(TypeError, setattr, c, 'rounding', 1.0)
4064 self.assertRaises(TypeError, setattr, c, 'rounding', 'xyz')
4065
4066 # capitals, clamp
4067 for attr in ['capitals', 'clamp']:
4068 self.assertRaises(ValueError, setattr, c, attr, -1)
4069 self.assertRaises(ValueError, setattr, c, attr, 2)
4070 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
4071
4072 # Invalid attribute
4073 self.assertRaises(AttributeError, setattr, c, 'emax', 100)
4074
4075 # Invalid signal dict
4076 self.assertRaises(TypeError, setattr, c, 'flags', [])
4077 self.assertRaises(KeyError, setattr, c, 'flags', {})
4078 self.assertRaises(KeyError, setattr, c, 'traps',
4079 {'InvalidOperation':0})
4080
4081 # Attributes cannot be deleted
4082 for attr in ['prec', 'Emax', 'Emin', 'rounding', 'capitals', 'clamp',
4083 'flags', 'traps']:
4084 self.assertRaises(AttributeError, c.__delattr__, attr)
4085
4086 # Invalid attributes
4087 self.assertRaises(TypeError, getattr, c, 9)
4088 self.assertRaises(TypeError, setattr, c, 9)
4089
4090 # Invalid values in constructor
4091 self.assertRaises(TypeError, Context, rounding=999999)
4092 self.assertRaises(TypeError, Context, rounding='xyz')
4093 self.assertRaises(ValueError, Context, clamp=2)
4094 self.assertRaises(ValueError, Context, capitals=-1)
4095 self.assertRaises(KeyError, Context, flags=["P"])
4096 self.assertRaises(KeyError, Context, traps=["Q"])
4097
4098 # Type error in conversion
4099 self.assertRaises(TypeError, Context, flags=(0,1))
4100 self.assertRaises(TypeError, Context, traps=(1,0))
4101
4102class CContextInputValidation(ContextInputValidation):
4103 decimal = C
4104class PyContextInputValidation(ContextInputValidation):
4105 decimal = P
4106
4107class ContextSubclassing(unittest.TestCase):
4108
4109 def test_context_subclassing(self):
4110 decimal = self.decimal
4111 Decimal = decimal.Decimal
4112 Context = decimal.Context
Stefan Krah1919b7e2012-03-21 18:25:23 +01004113 Clamped = decimal.Clamped
4114 DivisionByZero = decimal.DivisionByZero
4115 Inexact = decimal.Inexact
4116 Overflow = decimal.Overflow
4117 Rounded = decimal.Rounded
4118 Subnormal = decimal.Subnormal
4119 Underflow = decimal.Underflow
4120 InvalidOperation = decimal.InvalidOperation
4121
4122 class MyContext(Context):
4123 def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
4124 capitals=None, clamp=None, flags=None,
4125 traps=None):
4126 Context.__init__(self)
4127 if prec is not None:
4128 self.prec = prec
4129 if rounding is not None:
4130 self.rounding = rounding
4131 if Emin is not None:
4132 self.Emin = Emin
4133 if Emax is not None:
4134 self.Emax = Emax
4135 if capitals is not None:
4136 self.capitals = capitals
4137 if clamp is not None:
4138 self.clamp = clamp
4139 if flags is not None:
4140 if isinstance(flags, list):
4141 flags = {v:(v in flags) for v in OrderedSignals[decimal] + flags}
4142 self.flags = flags
4143 if traps is not None:
4144 if isinstance(traps, list):
4145 traps = {v:(v in traps) for v in OrderedSignals[decimal] + traps}
4146 self.traps = traps
4147
4148 c = Context()
4149 d = MyContext()
4150 for attr in ('prec', 'rounding', 'Emin', 'Emax', 'capitals', 'clamp',
4151 'flags', 'traps'):
4152 self.assertEqual(getattr(c, attr), getattr(d, attr))
4153
4154 # prec
4155 self.assertRaises(ValueError, MyContext, **{'prec':-1})
4156 c = MyContext(prec=1)
4157 self.assertEqual(c.prec, 1)
4158 self.assertRaises(InvalidOperation, c.quantize, Decimal('9e2'), 0)
4159
4160 # rounding
4161 self.assertRaises(TypeError, MyContext, **{'rounding':'XYZ'})
4162 c = MyContext(rounding=ROUND_DOWN, prec=1)
4163 self.assertEqual(c.rounding, ROUND_DOWN)
4164 self.assertEqual(c.plus(Decimal('9.9')), 9)
4165
4166 # Emin
4167 self.assertRaises(ValueError, MyContext, **{'Emin':5})
4168 c = MyContext(Emin=-1, prec=1)
4169 self.assertEqual(c.Emin, -1)
4170 x = c.add(Decimal('1e-99'), Decimal('2.234e-2000'))
4171 self.assertEqual(x, Decimal('0.0'))
4172 for signal in (Inexact, Underflow, Subnormal, Rounded, Clamped):
4173 self.assertTrue(c.flags[signal])
4174
4175 # Emax
4176 self.assertRaises(ValueError, MyContext, **{'Emax':-1})
4177 c = MyContext(Emax=1, prec=1)
4178 self.assertEqual(c.Emax, 1)
4179 self.assertRaises(Overflow, c.add, Decimal('1e99'), Decimal('2.234e2000'))
4180 if self.decimal == C:
4181 for signal in (Inexact, Overflow, Rounded):
4182 self.assertTrue(c.flags[signal])
4183
4184 # capitals
4185 self.assertRaises(ValueError, MyContext, **{'capitals':-1})
4186 c = MyContext(capitals=0)
4187 self.assertEqual(c.capitals, 0)
4188 x = c.create_decimal('1E222')
4189 self.assertEqual(c.to_sci_string(x), '1e+222')
4190
4191 # clamp
4192 self.assertRaises(ValueError, MyContext, **{'clamp':2})
4193 c = MyContext(clamp=1, Emax=99)
4194 self.assertEqual(c.clamp, 1)
4195 x = c.plus(Decimal('1e99'))
4196 self.assertEqual(str(x), '1.000000000000000000000000000E+99')
4197
4198 # flags
4199 self.assertRaises(TypeError, MyContext, **{'flags':'XYZ'})
4200 c = MyContext(flags=[Rounded, DivisionByZero])
4201 for signal in (Rounded, DivisionByZero):
4202 self.assertTrue(c.flags[signal])
4203 c.clear_flags()
4204 for signal in OrderedSignals[decimal]:
4205 self.assertFalse(c.flags[signal])
4206
4207 # traps
4208 self.assertRaises(TypeError, MyContext, **{'traps':'XYZ'})
4209 c = MyContext(traps=[Rounded, DivisionByZero])
4210 for signal in (Rounded, DivisionByZero):
4211 self.assertTrue(c.traps[signal])
4212 c.clear_traps()
4213 for signal in OrderedSignals[decimal]:
4214 self.assertFalse(c.traps[signal])
4215
4216class CContextSubclassing(ContextSubclassing):
4217 decimal = C
4218class PyContextSubclassing(ContextSubclassing):
4219 decimal = P
4220
4221@skip_if_extra_functionality
4222class CheckAttributes(unittest.TestCase):
4223
4224 def test_module_attributes(self):
4225
4226 # Architecture dependent context limits
4227 self.assertEqual(C.MAX_PREC, P.MAX_PREC)
4228 self.assertEqual(C.MAX_EMAX, P.MAX_EMAX)
4229 self.assertEqual(C.MIN_EMIN, P.MIN_EMIN)
4230 self.assertEqual(C.MIN_ETINY, P.MIN_ETINY)
4231
4232 self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False)
4233 self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False)
4234
4235 self.assertEqual(C.__version__, P.__version__)
4236
Stefan Krahb578f8a2014-09-10 17:58:15 +02004237 self.assertEqual(dir(C), dir(P))
Stefan Krah1919b7e2012-03-21 18:25:23 +01004238
4239 def test_context_attributes(self):
4240
4241 x = [s for s in dir(C.Context()) if '__' in s or not s.startswith('_')]
4242 y = [s for s in dir(P.Context()) if '__' in s or not s.startswith('_')]
4243 self.assertEqual(set(x) - set(y), set())
4244
4245 def test_decimal_attributes(self):
4246
4247 x = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
4248 y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
4249 self.assertEqual(set(x) - set(y), set())
4250
4251class Coverage(unittest.TestCase):
4252
4253 def test_adjusted(self):
4254 Decimal = self.decimal.Decimal
4255
4256 self.assertEqual(Decimal('1234e9999').adjusted(), 10002)
4257 # XXX raise?
4258 self.assertEqual(Decimal('nan').adjusted(), 0)
4259 self.assertEqual(Decimal('inf').adjusted(), 0)
4260
4261 def test_canonical(self):
4262 Decimal = self.decimal.Decimal
4263 getcontext = self.decimal.getcontext
4264
4265 x = Decimal(9).canonical()
4266 self.assertEqual(x, 9)
4267
4268 c = getcontext()
4269 x = c.canonical(Decimal(9))
4270 self.assertEqual(x, 9)
4271
4272 def test_context_repr(self):
4273 c = self.decimal.DefaultContext.copy()
4274
4275 c.prec = 425000000
4276 c.Emax = 425000000
4277 c.Emin = -425000000
Stefan Krah59a4a932013-01-16 12:58:59 +01004278 c.rounding = ROUND_HALF_DOWN
Stefan Krah1919b7e2012-03-21 18:25:23 +01004279 c.capitals = 0
4280 c.clamp = 1
4281 for sig in OrderedSignals[self.decimal]:
4282 c.flags[sig] = False
4283 c.traps[sig] = False
4284
4285 s = c.__repr__()
4286 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
4287 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
4288 "flags=[], traps=[])"
4289 self.assertEqual(s, t)
4290
4291 def test_implicit_context(self):
4292 Decimal = self.decimal.Decimal
4293 localcontext = self.decimal.localcontext
4294
4295 with localcontext() as c:
4296 c.prec = 1
4297 c.Emax = 1
4298 c.Emin = -1
4299
4300 # abs
4301 self.assertEqual(abs(Decimal("-10")), 10)
4302 # add
4303 self.assertEqual(Decimal("7") + 1, 8)
4304 # divide
4305 self.assertEqual(Decimal("10") / 5, 2)
4306 # divide_int
4307 self.assertEqual(Decimal("10") // 7, 1)
4308 # fma
4309 self.assertEqual(Decimal("1.2").fma(Decimal("0.01"), 1), 1)
4310 self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True)
4311 # three arg power
4312 self.assertEqual(pow(Decimal(10), 2, 7), 2)
4313 # exp
4314 self.assertEqual(Decimal("1.01").exp(), 3)
4315 # is_normal
4316 self.assertIs(Decimal("0.01").is_normal(), False)
4317 # is_subnormal
4318 self.assertIs(Decimal("0.01").is_subnormal(), True)
4319 # ln
4320 self.assertEqual(Decimal("20").ln(), 3)
4321 # log10
4322 self.assertEqual(Decimal("20").log10(), 1)
4323 # logb
4324 self.assertEqual(Decimal("580").logb(), 2)
4325 # logical_invert
4326 self.assertEqual(Decimal("10").logical_invert(), 1)
4327 # minus
4328 self.assertEqual(-Decimal("-10"), 10)
4329 # multiply
4330 self.assertEqual(Decimal("2") * 4, 8)
4331 # next_minus
4332 self.assertEqual(Decimal("10").next_minus(), 9)
4333 # next_plus
4334 self.assertEqual(Decimal("10").next_plus(), Decimal('2E+1'))
4335 # normalize
4336 self.assertEqual(Decimal("-10").normalize(), Decimal('-1E+1'))
4337 # number_class
4338 self.assertEqual(Decimal("10").number_class(), '+Normal')
4339 # plus
4340 self.assertEqual(+Decimal("-1"), -1)
4341 # remainder
4342 self.assertEqual(Decimal("10") % 7, 3)
4343 # subtract
4344 self.assertEqual(Decimal("10") - 7, 3)
4345 # to_integral_exact
4346 self.assertEqual(Decimal("1.12345").to_integral_exact(), 1)
4347
4348 # Boolean functions
4349 self.assertTrue(Decimal("1").is_canonical())
4350 self.assertTrue(Decimal("1").is_finite())
4351 self.assertTrue(Decimal("1").is_finite())
4352 self.assertTrue(Decimal("snan").is_snan())
4353 self.assertTrue(Decimal("-1").is_signed())
4354 self.assertTrue(Decimal("0").is_zero())
4355 self.assertTrue(Decimal("0").is_zero())
4356
4357 # Copy
4358 with localcontext() as c:
4359 c.prec = 10000
4360 x = 1228 ** 1523
4361 y = -Decimal(x)
4362
4363 z = y.copy_abs()
4364 self.assertEqual(z, x)
4365
4366 z = y.copy_negate()
4367 self.assertEqual(z, x)
4368
4369 z = y.copy_sign(Decimal(1))
4370 self.assertEqual(z, x)
4371
4372 def test_divmod(self):
4373 Decimal = self.decimal.Decimal
4374 localcontext = self.decimal.localcontext
4375 InvalidOperation = self.decimal.InvalidOperation
4376 DivisionByZero = self.decimal.DivisionByZero
4377
4378 with localcontext() as c:
4379 q, r = divmod(Decimal("10912837129"), 1001)
4380 self.assertEqual(q, Decimal('10901935'))
4381 self.assertEqual(r, Decimal('194'))
4382
4383 q, r = divmod(Decimal("NaN"), 7)
4384 self.assertTrue(q.is_nan() and r.is_nan())
4385
4386 c.traps[InvalidOperation] = False
4387 q, r = divmod(Decimal("NaN"), 7)
4388 self.assertTrue(q.is_nan() and r.is_nan())
4389
4390 c.traps[InvalidOperation] = False
4391 c.clear_flags()
4392 q, r = divmod(Decimal("inf"), Decimal("inf"))
4393 self.assertTrue(q.is_nan() and r.is_nan())
4394 self.assertTrue(c.flags[InvalidOperation])
4395
4396 c.clear_flags()
4397 q, r = divmod(Decimal("inf"), 101)
4398 self.assertTrue(q.is_infinite() and r.is_nan())
4399 self.assertTrue(c.flags[InvalidOperation])
4400
4401 c.clear_flags()
4402 q, r = divmod(Decimal(0), 0)
4403 self.assertTrue(q.is_nan() and r.is_nan())
4404 self.assertTrue(c.flags[InvalidOperation])
4405
4406 c.traps[DivisionByZero] = False
4407 c.clear_flags()
4408 q, r = divmod(Decimal(11), 0)
4409 self.assertTrue(q.is_infinite() and r.is_nan())
4410 self.assertTrue(c.flags[InvalidOperation] and
4411 c.flags[DivisionByZero])
4412
4413 def test_power(self):
4414 Decimal = self.decimal.Decimal
4415 localcontext = self.decimal.localcontext
4416 Overflow = self.decimal.Overflow
4417 Rounded = self.decimal.Rounded
4418
4419 with localcontext() as c:
4420 c.prec = 3
4421 c.clear_flags()
4422 self.assertEqual(Decimal("1.0") ** 100, Decimal('1.00'))
4423 self.assertTrue(c.flags[Rounded])
4424
4425 c.prec = 1
4426 c.Emax = 1
4427 c.Emin = -1
4428 c.clear_flags()
4429 c.traps[Overflow] = False
4430 self.assertEqual(Decimal(10000) ** Decimal("0.5"), Decimal('inf'))
4431 self.assertTrue(c.flags[Overflow])
4432
4433 def test_quantize(self):
4434 Decimal = self.decimal.Decimal
4435 localcontext = self.decimal.localcontext
4436 InvalidOperation = self.decimal.InvalidOperation
4437
4438 with localcontext() as c:
4439 c.prec = 1
4440 c.Emax = 1
4441 c.Emin = -1
4442 c.traps[InvalidOperation] = False
4443 x = Decimal(99).quantize(Decimal("1e1"))
4444 self.assertTrue(x.is_nan())
4445
4446 def test_radix(self):
4447 Decimal = self.decimal.Decimal
4448 getcontext = self.decimal.getcontext
4449
4450 c = getcontext()
4451 self.assertEqual(Decimal("1").radix(), 10)
4452 self.assertEqual(c.radix(), 10)
4453
4454 def test_rop(self):
4455 Decimal = self.decimal.Decimal
4456
4457 for attr in ('__radd__', '__rsub__', '__rmul__', '__rtruediv__',
4458 '__rdivmod__', '__rmod__', '__rfloordiv__', '__rpow__'):
4459 self.assertIs(getattr(Decimal("1"), attr)("xyz"), NotImplemented)
4460
4461 def test_round(self):
4462 # Python3 behavior: round() returns Decimal
4463 Decimal = self.decimal.Decimal
Stefan Krahe95dfc52018-06-03 18:40:00 +02004464 localcontext = self.decimal.localcontext
Stefan Krah1919b7e2012-03-21 18:25:23 +01004465
Stefan Krahe95dfc52018-06-03 18:40:00 +02004466 with localcontext() as c:
4467 c.prec = 28
Stefan Krah1919b7e2012-03-21 18:25:23 +01004468
Stefan Krahe95dfc52018-06-03 18:40:00 +02004469 self.assertEqual(str(Decimal("9.99").__round__()), "10")
4470 self.assertEqual(str(Decimal("9.99e-5").__round__()), "0")
4471 self.assertEqual(str(Decimal("1.23456789").__round__(5)), "1.23457")
4472 self.assertEqual(str(Decimal("1.2345").__round__(10)), "1.2345000000")
4473 self.assertEqual(str(Decimal("1.2345").__round__(-10)), "0E+10")
Stefan Krah1919b7e2012-03-21 18:25:23 +01004474
Stefan Krahe95dfc52018-06-03 18:40:00 +02004475 self.assertRaises(TypeError, Decimal("1.23").__round__, "5")
4476 self.assertRaises(TypeError, Decimal("1.23").__round__, 5, 8)
Stefan Krah1919b7e2012-03-21 18:25:23 +01004477
4478 def test_create_decimal(self):
4479 c = self.decimal.Context()
4480 self.assertRaises(ValueError, c.create_decimal, ["%"])
4481
4482 def test_int(self):
4483 Decimal = self.decimal.Decimal
4484 localcontext = self.decimal.localcontext
4485
4486 with localcontext() as c:
4487 c.prec = 9999
4488 x = Decimal(1221**1271) / 10**3923
4489 self.assertEqual(int(x), 1)
4490 self.assertEqual(x.to_integral(), 2)
4491
4492 def test_copy(self):
4493 Context = self.decimal.Context
4494
4495 c = Context()
4496 c.prec = 10000
4497 x = -(1172 ** 1712)
4498
4499 y = c.copy_abs(x)
4500 self.assertEqual(y, -x)
4501
4502 y = c.copy_negate(x)
4503 self.assertEqual(y, -x)
4504
4505 y = c.copy_sign(x, 1)
4506 self.assertEqual(y, -x)
4507
4508class CCoverage(Coverage):
4509 decimal = C
4510class PyCoverage(Coverage):
4511 decimal = P
4512
4513class PyFunctionality(unittest.TestCase):
4514 """Extra functionality in decimal.py"""
4515
Stefan Krah1919b7e2012-03-21 18:25:23 +01004516 def test_py_alternate_formatting(self):
4517 # triples giving a format, a Decimal, and the expected result
4518 Decimal = P.Decimal
4519 localcontext = P.localcontext
4520
4521 test_values = [
4522 # Issue 7094: Alternate formatting (specified by #)
4523 ('.0e', '1.0', '1e+0'),
4524 ('#.0e', '1.0', '1.e+0'),
4525 ('.0f', '1.0', '1'),
4526 ('#.0f', '1.0', '1.'),
4527 ('g', '1.1', '1.1'),
4528 ('#g', '1.1', '1.1'),
4529 ('.0g', '1', '1'),
4530 ('#.0g', '1', '1.'),
4531 ('.0%', '1.0', '100%'),
4532 ('#.0%', '1.0', '100.%'),
4533 ]
4534 for fmt, d, result in test_values:
4535 self.assertEqual(format(Decimal(d), fmt), result)
4536
4537class PyWhitebox(unittest.TestCase):
4538 """White box testing for decimal.py"""
4539
4540 def test_py_exact_power(self):
4541 # Rarely exercised lines in _power_exact.
4542 Decimal = P.Decimal
4543 localcontext = P.localcontext
4544
4545 with localcontext() as c:
4546 c.prec = 8
4547 x = Decimal(2**16) ** Decimal("-0.5")
4548 self.assertEqual(x, Decimal('0.00390625'))
4549
4550 x = Decimal(2**16) ** Decimal("-0.6")
4551 self.assertEqual(x, Decimal('0.0012885819'))
4552
4553 x = Decimal("256e7") ** Decimal("-0.5")
4554
4555 x = Decimal(152587890625) ** Decimal('-0.0625')
4556 self.assertEqual(x, Decimal("0.2"))
4557
4558 x = Decimal("152587890625e7") ** Decimal('-0.0625')
4559
4560 x = Decimal(5**2659) ** Decimal('-0.0625')
4561
4562 c.prec = 1
4563 x = Decimal("152587890625") ** Decimal('-0.5')
4564 c.prec = 201
4565 x = Decimal(2**578) ** Decimal("-0.5")
4566
4567 def test_py_immutability_operations(self):
Terry Jan Reedy0f847642013-03-11 18:34:00 -04004568 # Do operations and check that it didn't change internal objects.
Stefan Krah1919b7e2012-03-21 18:25:23 +01004569 Decimal = P.Decimal
4570 DefaultContext = P.DefaultContext
4571 setcontext = P.setcontext
4572
4573 c = DefaultContext.copy()
4574 c.traps = dict((s, 0) for s in OrderedSignals[P])
4575 setcontext(c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004576
4577 d1 = Decimal('-25e55')
4578 b1 = Decimal('-25e55')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004579 d2 = Decimal('33e+33')
4580 b2 = Decimal('33e+33')
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004581
4582 def checkSameDec(operation, useOther=False):
4583 if useOther:
4584 eval("d1." + operation + "(d2)")
4585 self.assertEqual(d1._sign, b1._sign)
4586 self.assertEqual(d1._int, b1._int)
4587 self.assertEqual(d1._exp, b1._exp)
4588 self.assertEqual(d2._sign, b2._sign)
4589 self.assertEqual(d2._int, b2._int)
4590 self.assertEqual(d2._exp, b2._exp)
4591 else:
4592 eval("d1." + operation + "()")
4593 self.assertEqual(d1._sign, b1._sign)
4594 self.assertEqual(d1._int, b1._int)
4595 self.assertEqual(d1._exp, b1._exp)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004596
4597 Decimal(d1)
4598 self.assertEqual(d1._sign, b1._sign)
4599 self.assertEqual(d1._int, b1._int)
4600 self.assertEqual(d1._exp, b1._exp)
4601
4602 checkSameDec("__abs__")
4603 checkSameDec("__add__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004604 checkSameDec("__divmod__", True)
Christian Heimes77c02eb2008-02-09 02:18:51 +00004605 checkSameDec("__eq__", True)
4606 checkSameDec("__ne__", True)
4607 checkSameDec("__le__", True)
4608 checkSameDec("__lt__", True)
4609 checkSameDec("__ge__", True)
4610 checkSameDec("__gt__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004611 checkSameDec("__float__")
4612 checkSameDec("__floordiv__", True)
4613 checkSameDec("__hash__")
4614 checkSameDec("__int__")
Christian Heimes969fe572008-01-25 11:23:10 +00004615 checkSameDec("__trunc__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004616 checkSameDec("__mod__", True)
4617 checkSameDec("__mul__", True)
4618 checkSameDec("__neg__")
Jack Diederich4dafcc42006-11-28 19:15:13 +00004619 checkSameDec("__bool__")
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004620 checkSameDec("__pos__")
4621 checkSameDec("__pow__", True)
4622 checkSameDec("__radd__", True)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004623 checkSameDec("__rdivmod__", True)
4624 checkSameDec("__repr__")
4625 checkSameDec("__rfloordiv__", True)
4626 checkSameDec("__rmod__", True)
4627 checkSameDec("__rmul__", True)
4628 checkSameDec("__rpow__", True)
4629 checkSameDec("__rsub__", True)
4630 checkSameDec("__str__")
4631 checkSameDec("__sub__", True)
4632 checkSameDec("__truediv__", True)
4633 checkSameDec("adjusted")
4634 checkSameDec("as_tuple")
4635 checkSameDec("compare", True)
4636 checkSameDec("max", True)
4637 checkSameDec("min", True)
4638 checkSameDec("normalize")
4639 checkSameDec("quantize", True)
4640 checkSameDec("remainder_near", True)
4641 checkSameDec("same_quantum", True)
4642 checkSameDec("sqrt")
4643 checkSameDec("to_eng_string")
4644 checkSameDec("to_integral")
4645
Stefan Krah1919b7e2012-03-21 18:25:23 +01004646 def test_py_decimal_id(self):
4647 Decimal = P.Decimal
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004648
Stefan Krah1919b7e2012-03-21 18:25:23 +01004649 d = Decimal(45)
4650 e = Decimal(d)
4651 self.assertEqual(str(e), '45')
4652 self.assertNotEqual(id(d), id(e))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004653
Stefan Krah1919b7e2012-03-21 18:25:23 +01004654 def test_py_rescale(self):
4655 # Coverage
4656 Decimal = P.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01004657 localcontext = P.localcontext
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004658
Stefan Krah1919b7e2012-03-21 18:25:23 +01004659 with localcontext() as c:
4660 x = Decimal("NaN")._rescale(3, ROUND_UP)
4661 self.assertTrue(x.is_nan())
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004662
Stefan Krah1919b7e2012-03-21 18:25:23 +01004663 def test_py__round(self):
4664 # Coverage
4665 Decimal = P.Decimal
Christian Heimes0348fb62008-03-26 12:55:56 +00004666
Stefan Krah1919b7e2012-03-21 18:25:23 +01004667 self.assertRaises(ValueError, Decimal("3.1234")._round, 0, ROUND_UP)
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004668
Stefan Krah1919b7e2012-03-21 18:25:23 +01004669class CFunctionality(unittest.TestCase):
4670 """Extra functionality in _decimal"""
Mark Dickinsona2d1fe02009-10-29 12:23:02 +00004671
Stefan Krah1919b7e2012-03-21 18:25:23 +01004672 @requires_extra_functionality
4673 def test_c_ieee_context(self):
4674 # issue 8786: Add support for IEEE 754 contexts to decimal module.
4675 IEEEContext = C.IEEEContext
4676 DECIMAL32 = C.DECIMAL32
4677 DECIMAL64 = C.DECIMAL64
4678 DECIMAL128 = C.DECIMAL128
Thomas Wouters1b7f8912007-09-19 03:06:30 +00004679
Stefan Krah1919b7e2012-03-21 18:25:23 +01004680 def assert_rest(self, context):
4681 self.assertEqual(context.clamp, 1)
4682 assert_signals(self, context, 'traps', [])
4683 assert_signals(self, context, 'flags', [])
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004684
Stefan Krah1919b7e2012-03-21 18:25:23 +01004685 c = IEEEContext(DECIMAL32)
4686 self.assertEqual(c.prec, 7)
4687 self.assertEqual(c.Emax, 96)
4688 self.assertEqual(c.Emin, -95)
4689 assert_rest(self, c)
Raymond Hettinger82417ca2009-02-03 03:54:28 +00004690
Stefan Krah1919b7e2012-03-21 18:25:23 +01004691 c = IEEEContext(DECIMAL64)
4692 self.assertEqual(c.prec, 16)
4693 self.assertEqual(c.Emax, 384)
4694 self.assertEqual(c.Emin, -383)
4695 assert_rest(self, c)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00004696
Stefan Krah1919b7e2012-03-21 18:25:23 +01004697 c = IEEEContext(DECIMAL128)
4698 self.assertEqual(c.prec, 34)
4699 self.assertEqual(c.Emax, 6144)
4700 self.assertEqual(c.Emin, -6143)
4701 assert_rest(self, c)
Raymond Hettinger5548be22004-07-05 18:49:38 +00004702
Stefan Krah1919b7e2012-03-21 18:25:23 +01004703 # Invalid values
4704 self.assertRaises(OverflowError, IEEEContext, 2**63)
4705 self.assertRaises(ValueError, IEEEContext, -1)
4706 self.assertRaises(ValueError, IEEEContext, 1024)
Mark Dickinson825fce32009-09-07 18:08:12 +00004707
Stefan Krah1919b7e2012-03-21 18:25:23 +01004708 @requires_extra_functionality
4709 def test_c_context(self):
4710 Context = C.Context
Christian Heimes969fe572008-01-25 11:23:10 +00004711
Stefan Krah1919b7e2012-03-21 18:25:23 +01004712 c = Context(flags=C.DecClamped, traps=C.DecRounded)
4713 self.assertEqual(c._flags, C.DecClamped)
4714 self.assertEqual(c._traps, C.DecRounded)
Raymond Hettinger771ed762009-01-03 19:20:32 +00004715
Stefan Krah1919b7e2012-03-21 18:25:23 +01004716 @requires_extra_functionality
4717 def test_constants(self):
4718 # Condition flags
4719 cond = (
4720 C.DecClamped, C.DecConversionSyntax, C.DecDivisionByZero,
4721 C.DecDivisionImpossible, C.DecDivisionUndefined,
4722 C.DecFpuError, C.DecInexact, C.DecInvalidContext,
4723 C.DecInvalidOperation, C.DecMallocError,
4724 C.DecFloatOperation, C.DecOverflow, C.DecRounded,
4725 C.DecSubnormal, C.DecUnderflow
Raymond Hettinger771ed762009-01-03 19:20:32 +00004726 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01004727
4728 # IEEEContext
4729 self.assertEqual(C.DECIMAL32, 32)
4730 self.assertEqual(C.DECIMAL64, 64)
4731 self.assertEqual(C.DECIMAL128, 128)
4732 self.assertEqual(C.IEEE_CONTEXT_MAX_BITS, 512)
4733
Stefan Krah1919b7e2012-03-21 18:25:23 +01004734 # Conditions
4735 for i, v in enumerate(cond):
4736 self.assertEqual(v, 1<<i)
4737
4738 self.assertEqual(C.DecIEEEInvalidOperation,
4739 C.DecConversionSyntax|
4740 C.DecDivisionImpossible|
4741 C.DecDivisionUndefined|
4742 C.DecFpuError|
4743 C.DecInvalidContext|
4744 C.DecInvalidOperation|
4745 C.DecMallocError)
4746
4747 self.assertEqual(C.DecErrors,
4748 C.DecIEEEInvalidOperation|
4749 C.DecDivisionByZero)
4750
4751 self.assertEqual(C.DecTraps,
4752 C.DecErrors|C.DecOverflow|C.DecUnderflow)
4753
4754class CWhitebox(unittest.TestCase):
4755 """Whitebox testing for _decimal"""
4756
4757 def test_bignum(self):
4758 # Not exactly whitebox, but too slow with pydecimal.
4759
4760 Decimal = C.Decimal
4761 localcontext = C.localcontext
4762
4763 b1 = 10**35
4764 b2 = 10**36
4765 with localcontext() as c:
4766 c.prec = 1000000
4767 for i in range(5):
4768 a = random.randrange(b1, b2)
4769 b = random.randrange(1000, 1200)
4770 x = a ** b
4771 y = Decimal(a) ** Decimal(b)
4772 self.assertEqual(x, y)
4773
4774 def test_invalid_construction(self):
4775 self.assertRaises(TypeError, C.Decimal, 9, "xyz")
4776
4777 def test_c_input_restriction(self):
4778 # Too large for _decimal to be converted exactly
4779 Decimal = C.Decimal
4780 InvalidOperation = C.InvalidOperation
4781 Context = C.Context
4782 localcontext = C.localcontext
4783
4784 with localcontext(Context()):
4785 self.assertRaises(InvalidOperation, Decimal,
4786 "1e9999999999999999999")
4787
4788 def test_c_context_repr(self):
4789 # This test is _decimal-only because flags are not printed
4790 # in the same order.
4791 DefaultContext = C.DefaultContext
4792 FloatOperation = C.FloatOperation
Stefan Krah1919b7e2012-03-21 18:25:23 +01004793
4794 c = DefaultContext.copy()
4795
4796 c.prec = 425000000
4797 c.Emax = 425000000
4798 c.Emin = -425000000
4799 c.rounding = ROUND_HALF_DOWN
4800 c.capitals = 0
4801 c.clamp = 1
4802 for sig in OrderedSignals[C]:
4803 c.flags[sig] = True
4804 c.traps[sig] = True
4805 c.flags[FloatOperation] = True
4806 c.traps[FloatOperation] = True
4807
4808 s = c.__repr__()
4809 t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
4810 "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
4811 "flags=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4812 "FloatOperation, Overflow, Rounded, Subnormal, Underflow], " \
4813 "traps=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
4814 "FloatOperation, Overflow, Rounded, Subnormal, Underflow])"
4815 self.assertEqual(s, t)
4816
4817 def test_c_context_errors(self):
4818 Context = C.Context
4819 InvalidOperation = C.InvalidOperation
4820 Overflow = C.Overflow
4821 FloatOperation = C.FloatOperation
4822 localcontext = C.localcontext
4823 getcontext = C.getcontext
4824 setcontext = C.setcontext
4825 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4826
4827 c = Context()
4828
4829 # SignalDict: input validation
4830 self.assertRaises(KeyError, c.flags.__setitem__, 801, 0)
4831 self.assertRaises(KeyError, c.traps.__setitem__, 801, 0)
4832 self.assertRaises(ValueError, c.flags.__delitem__, Overflow)
4833 self.assertRaises(ValueError, c.traps.__delitem__, InvalidOperation)
4834 self.assertRaises(TypeError, setattr, c, 'flags', ['x'])
4835 self.assertRaises(TypeError, setattr, c,'traps', ['y'])
4836 self.assertRaises(KeyError, setattr, c, 'flags', {0:1})
4837 self.assertRaises(KeyError, setattr, c, 'traps', {0:1})
4838
4839 # Test assignment from a signal dict with the correct length but
4840 # one invalid key.
4841 d = c.flags.copy()
4842 del d[FloatOperation]
4843 d["XYZ"] = 91283719
4844 self.assertRaises(KeyError, setattr, c, 'flags', d)
4845 self.assertRaises(KeyError, setattr, c, 'traps', d)
4846
4847 # Input corner cases
4848 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4849 gt_max_emax = 10**18 if HAVE_CONFIG_64 else 10**9
4850
4851 # prec, Emax, Emin
4852 for attr in ['prec', 'Emax']:
4853 self.assertRaises(ValueError, setattr, c, attr, gt_max_emax)
4854 self.assertRaises(ValueError, setattr, c, 'Emin', -gt_max_emax)
4855
4856 # prec, Emax, Emin in context constructor
4857 self.assertRaises(ValueError, Context, prec=gt_max_emax)
4858 self.assertRaises(ValueError, Context, Emax=gt_max_emax)
4859 self.assertRaises(ValueError, Context, Emin=-gt_max_emax)
4860
4861 # Overflow in conversion
4862 self.assertRaises(OverflowError, Context, prec=int_max+1)
4863 self.assertRaises(OverflowError, Context, Emax=int_max+1)
4864 self.assertRaises(OverflowError, Context, Emin=-int_max-2)
Stefan Krah1919b7e2012-03-21 18:25:23 +01004865 self.assertRaises(OverflowError, Context, clamp=int_max+1)
4866 self.assertRaises(OverflowError, Context, capitals=int_max+1)
4867
4868 # OverflowError, general ValueError
4869 for attr in ('prec', 'Emin', 'Emax', 'capitals', 'clamp'):
4870 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4871 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4872 if sys.platform != 'win32':
4873 self.assertRaises(ValueError, setattr, c, attr, int_max)
4874 self.assertRaises(ValueError, setattr, c, attr, -int_max-1)
4875
Stefan Krah1919b7e2012-03-21 18:25:23 +01004876 # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
4877 if C.MAX_PREC == 425000000:
4878 self.assertRaises(OverflowError, getattr(c, '_unsafe_setprec'),
4879 int_max+1)
4880 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemax'),
4881 int_max+1)
4882 self.assertRaises(OverflowError, getattr(c, '_unsafe_setemin'),
4883 -int_max-2)
4884
4885 # ValueError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
4886 if C.MAX_PREC == 425000000:
4887 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), 0)
4888 self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'),
4889 1070000001)
4890 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), -1)
4891 self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'),
4892 1070000001)
4893 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'),
4894 -1070000001)
4895 self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), 1)
4896
4897 # capitals, clamp
4898 for attr in ['capitals', 'clamp']:
4899 self.assertRaises(ValueError, setattr, c, attr, -1)
4900 self.assertRaises(ValueError, setattr, c, attr, 2)
4901 self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
4902 if HAVE_CONFIG_64:
4903 self.assertRaises(ValueError, setattr, c, attr, 2**32)
4904 self.assertRaises(ValueError, setattr, c, attr, 2**32+1)
4905
4906 # Invalid local context
4907 self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass',
4908 locals())
Stefan Krah040e3112012-12-15 22:33:33 +01004909 self.assertRaises(TypeError, exec,
4910 'with localcontext(context=getcontext()): pass',
4911 locals())
Stefan Krah1919b7e2012-03-21 18:25:23 +01004912
4913 # setcontext
4914 saved_context = getcontext()
4915 self.assertRaises(TypeError, setcontext, "xyz")
4916 setcontext(saved_context)
4917
Stefan Krah59a4a932013-01-16 12:58:59 +01004918 def test_rounding_strings_interned(self):
4919
4920 self.assertIs(C.ROUND_UP, P.ROUND_UP)
4921 self.assertIs(C.ROUND_DOWN, P.ROUND_DOWN)
4922 self.assertIs(C.ROUND_CEILING, P.ROUND_CEILING)
4923 self.assertIs(C.ROUND_FLOOR, P.ROUND_FLOOR)
4924 self.assertIs(C.ROUND_HALF_UP, P.ROUND_HALF_UP)
4925 self.assertIs(C.ROUND_HALF_DOWN, P.ROUND_HALF_DOWN)
4926 self.assertIs(C.ROUND_HALF_EVEN, P.ROUND_HALF_EVEN)
4927 self.assertIs(C.ROUND_05UP, P.ROUND_05UP)
4928
Stefan Krah1919b7e2012-03-21 18:25:23 +01004929 @requires_extra_functionality
4930 def test_c_context_errors_extra(self):
4931 Context = C.Context
4932 InvalidOperation = C.InvalidOperation
4933 Overflow = C.Overflow
4934 localcontext = C.localcontext
4935 getcontext = C.getcontext
4936 setcontext = C.setcontext
4937 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
4938
4939 c = Context()
4940
4941 # Input corner cases
4942 int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
4943
4944 # OverflowError, general ValueError
4945 self.assertRaises(OverflowError, setattr, c, '_allcr', int_max+1)
4946 self.assertRaises(OverflowError, setattr, c, '_allcr', -int_max-2)
4947 if sys.platform != 'win32':
4948 self.assertRaises(ValueError, setattr, c, '_allcr', int_max)
4949 self.assertRaises(ValueError, setattr, c, '_allcr', -int_max-1)
4950
4951 # OverflowError, general TypeError
4952 for attr in ('_flags', '_traps'):
4953 self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
4954 self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
4955 if sys.platform != 'win32':
4956 self.assertRaises(TypeError, setattr, c, attr, int_max)
4957 self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
4958
4959 # _allcr
4960 self.assertRaises(ValueError, setattr, c, '_allcr', -1)
4961 self.assertRaises(ValueError, setattr, c, '_allcr', 2)
4962 self.assertRaises(TypeError, setattr, c, '_allcr', [1,2,3])
4963 if HAVE_CONFIG_64:
4964 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32)
4965 self.assertRaises(ValueError, setattr, c, '_allcr', 2**32+1)
4966
4967 # _flags, _traps
4968 for attr in ['_flags', '_traps']:
4969 self.assertRaises(TypeError, setattr, c, attr, 999999)
4970 self.assertRaises(TypeError, setattr, c, attr, 'x')
4971
4972 def test_c_valid_context(self):
4973 # These tests are for code coverage in _decimal.
4974 DefaultContext = C.DefaultContext
Stefan Krah1919b7e2012-03-21 18:25:23 +01004975 Clamped = C.Clamped
4976 Underflow = C.Underflow
4977 Inexact = C.Inexact
4978 Rounded = C.Rounded
4979 Subnormal = C.Subnormal
4980
4981 c = DefaultContext.copy()
4982
4983 # Exercise all getters and setters
4984 c.prec = 34
4985 c.rounding = ROUND_HALF_UP
4986 c.Emax = 3000
4987 c.Emin = -3000
4988 c.capitals = 1
4989 c.clamp = 0
4990
4991 self.assertEqual(c.prec, 34)
4992 self.assertEqual(c.rounding, ROUND_HALF_UP)
4993 self.assertEqual(c.Emin, -3000)
4994 self.assertEqual(c.Emax, 3000)
4995 self.assertEqual(c.capitals, 1)
4996 self.assertEqual(c.clamp, 0)
4997
4998 self.assertEqual(c.Etiny(), -3033)
4999 self.assertEqual(c.Etop(), 2967)
5000
5001 # Exercise all unsafe setters
5002 if C.MAX_PREC == 425000000:
5003 c._unsafe_setprec(999999999)
5004 c._unsafe_setemax(999999999)
5005 c._unsafe_setemin(-999999999)
5006 self.assertEqual(c.prec, 999999999)
5007 self.assertEqual(c.Emax, 999999999)
5008 self.assertEqual(c.Emin, -999999999)
5009
5010 @requires_extra_functionality
5011 def test_c_valid_context_extra(self):
5012 DefaultContext = C.DefaultContext
5013
5014 c = DefaultContext.copy()
5015 self.assertEqual(c._allcr, 1)
5016 c._allcr = 0
5017 self.assertEqual(c._allcr, 0)
5018
5019 def test_c_round(self):
5020 # Restricted input.
5021 Decimal = C.Decimal
5022 InvalidOperation = C.InvalidOperation
5023 localcontext = C.localcontext
5024 MAX_EMAX = C.MAX_EMAX
5025 MIN_ETINY = C.MIN_ETINY
5026 int_max = 2**63-1 if C.MAX_PREC > 425000000 else 2**31-1
5027
5028 with localcontext() as c:
5029 c.traps[InvalidOperation] = True
5030 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
5031 -int_max-1)
5032 self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
5033 int_max)
5034 self.assertRaises(InvalidOperation, Decimal("1").__round__,
5035 int(MAX_EMAX+1))
5036 self.assertRaises(C.InvalidOperation, Decimal("1").__round__,
5037 -int(MIN_ETINY-1))
5038 self.assertRaises(OverflowError, Decimal("1.23").__round__,
5039 -int_max-2)
5040 self.assertRaises(OverflowError, Decimal("1.23").__round__,
5041 int_max+1)
5042
5043 def test_c_format(self):
5044 # Restricted input
5045 Decimal = C.Decimal
Stefan Krah1919b7e2012-03-21 18:25:23 +01005046 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
5047
5048 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", [], 9)
5049 self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", 9)
5050 self.assertRaises(TypeError, Decimal(1).__format__, [])
5051
Stefan Kraheb8c4512013-01-24 15:22:33 +01005052 self.assertRaises(ValueError, Decimal(1).__format__, "<>=10.10")
5053 maxsize = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
5054 self.assertRaises(ValueError, Decimal("1.23456789").__format__,
5055 "=%d.1" % maxsize)
Stefan Krah1919b7e2012-03-21 18:25:23 +01005056
5057 def test_c_integral(self):
5058 Decimal = C.Decimal
5059 Inexact = C.Inexact
Stefan Krah1919b7e2012-03-21 18:25:23 +01005060 localcontext = C.localcontext
5061
5062 x = Decimal(10)
5063 self.assertEqual(x.to_integral(), 10)
5064 self.assertRaises(TypeError, x.to_integral, '10')
5065 self.assertRaises(TypeError, x.to_integral, 10, 'x')
5066 self.assertRaises(TypeError, x.to_integral, 10)
5067
5068 self.assertEqual(x.to_integral_value(), 10)
5069 self.assertRaises(TypeError, x.to_integral_value, '10')
5070 self.assertRaises(TypeError, x.to_integral_value, 10, 'x')
5071 self.assertRaises(TypeError, x.to_integral_value, 10)
5072
5073 self.assertEqual(x.to_integral_exact(), 10)
5074 self.assertRaises(TypeError, x.to_integral_exact, '10')
5075 self.assertRaises(TypeError, x.to_integral_exact, 10, 'x')
5076 self.assertRaises(TypeError, x.to_integral_exact, 10)
5077
5078 with localcontext() as c:
5079 x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP)
5080 self.assertEqual(x, Decimal('100000000000000000000000000'))
5081
5082 x = Decimal("99999999999999999999999999.9").to_integral_exact(ROUND_UP)
5083 self.assertEqual(x, Decimal('100000000000000000000000000'))
5084
5085 c.traps[Inexact] = True
5086 self.assertRaises(Inexact, Decimal("999.9").to_integral_exact, ROUND_UP)
5087
5088 def test_c_funcs(self):
5089 # Invalid arguments
5090 Decimal = C.Decimal
5091 InvalidOperation = C.InvalidOperation
5092 DivisionByZero = C.DivisionByZero
Stefan Krah1919b7e2012-03-21 18:25:23 +01005093 getcontext = C.getcontext
5094 localcontext = C.localcontext
5095
5096 self.assertEqual(Decimal('9.99e10').to_eng_string(), '99.9E+9')
5097
5098 self.assertRaises(TypeError, pow, Decimal(1), 2, "3")
5099 self.assertRaises(TypeError, Decimal(9).number_class, "x", "y")
5100 self.assertRaises(TypeError, Decimal(9).same_quantum, 3, "x", "y")
5101
Raymond Hettinger771ed762009-01-03 19:20:32 +00005102 self.assertRaises(
Stefan Krah1919b7e2012-03-21 18:25:23 +01005103 TypeError,
5104 Decimal("1.23456789").quantize, Decimal('1e-100000'), []
Raymond Hettinger771ed762009-01-03 19:20:32 +00005105 )
Stefan Krah1919b7e2012-03-21 18:25:23 +01005106 self.assertRaises(
5107 TypeError,
5108 Decimal("1.23456789").quantize, Decimal('1e-100000'), getcontext()
5109 )
5110 self.assertRaises(
5111 TypeError,
5112 Decimal("1.23456789").quantize, Decimal('1e-100000'), 10
5113 )
5114 self.assertRaises(
5115 TypeError,
5116 Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000
5117 )
Raymond Hettinger771ed762009-01-03 19:20:32 +00005118
Stefan Krah1919b7e2012-03-21 18:25:23 +01005119 with localcontext() as c:
5120 c.clear_traps()
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00005121
Stefan Krah1919b7e2012-03-21 18:25:23 +01005122 # Invalid arguments
5123 self.assertRaises(TypeError, c.copy_sign, Decimal(1), "x", "y")
5124 self.assertRaises(TypeError, c.canonical, 200)
5125 self.assertRaises(TypeError, c.is_canonical, 200)
5126 self.assertRaises(TypeError, c.divmod, 9, 8, "x", "y")
5127 self.assertRaises(TypeError, c.same_quantum, 9, 3, "x", "y")
Raymond Hettingerd9c0a7a2004-07-03 10:02:28 +00005128
Stefan Krah1919b7e2012-03-21 18:25:23 +01005129 self.assertEqual(str(c.canonical(Decimal(200))), '200')
5130 self.assertEqual(c.radix(), 10)
Raymond Hettinger0aeac102004-07-05 22:53:03 +00005131
Stefan Krah1919b7e2012-03-21 18:25:23 +01005132 c.traps[DivisionByZero] = True
5133 self.assertRaises(DivisionByZero, Decimal(9).__divmod__, 0)
5134 self.assertRaises(DivisionByZero, c.divmod, 9, 0)
5135 self.assertTrue(c.flags[InvalidOperation])
Raymond Hettinger955d2b22004-08-08 20:17:45 +00005136
Stefan Krah1919b7e2012-03-21 18:25:23 +01005137 c.clear_flags()
5138 c.traps[InvalidOperation] = True
5139 self.assertRaises(InvalidOperation, Decimal(9).__divmod__, 0)
5140 self.assertRaises(InvalidOperation, c.divmod, 9, 0)
5141 self.assertTrue(c.flags[DivisionByZero])
Mark Dickinsonb1d8e322010-05-22 18:35:36 +00005142
Stefan Krah1919b7e2012-03-21 18:25:23 +01005143 c.traps[InvalidOperation] = True
5144 c.prec = 2
5145 self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501)
Mark Dickinson84230a12010-02-18 14:49:50 +00005146
Stefan Krah040e3112012-12-15 22:33:33 +01005147 def test_va_args_exceptions(self):
5148 Decimal = C.Decimal
5149 Context = C.Context
5150
5151 x = Decimal("10001111111")
5152
5153 for attr in ['exp', 'is_normal', 'is_subnormal', 'ln', 'log10',
5154 'logb', 'logical_invert', 'next_minus', 'next_plus',
5155 'normalize', 'number_class', 'sqrt', 'to_eng_string']:
5156 func = getattr(x, attr)
5157 self.assertRaises(TypeError, func, context="x")
5158 self.assertRaises(TypeError, func, "x", context=None)
5159
5160 for attr in ['compare', 'compare_signal', 'logical_and',
5161 'logical_or', 'max', 'max_mag', 'min', 'min_mag',
5162 'remainder_near', 'rotate', 'scaleb', 'shift']:
5163 func = getattr(x, attr)
5164 self.assertRaises(TypeError, func, context="x")
5165 self.assertRaises(TypeError, func, "x", context=None)
5166
5167 self.assertRaises(TypeError, x.to_integral, rounding=None, context=[])
5168 self.assertRaises(TypeError, x.to_integral, rounding={}, context=[])
5169 self.assertRaises(TypeError, x.to_integral, [], [])
5170
5171 self.assertRaises(TypeError, x.to_integral_value, rounding=None, context=[])
5172 self.assertRaises(TypeError, x.to_integral_value, rounding={}, context=[])
5173 self.assertRaises(TypeError, x.to_integral_value, [], [])
5174
5175 self.assertRaises(TypeError, x.to_integral_exact, rounding=None, context=[])
5176 self.assertRaises(TypeError, x.to_integral_exact, rounding={}, context=[])
5177 self.assertRaises(TypeError, x.to_integral_exact, [], [])
5178
5179 self.assertRaises(TypeError, x.fma, 1, 2, context="x")
5180 self.assertRaises(TypeError, x.fma, 1, 2, "x", context=None)
5181
5182 self.assertRaises(TypeError, x.quantize, 1, [], context=None)
5183 self.assertRaises(TypeError, x.quantize, 1, [], rounding=None)
5184 self.assertRaises(TypeError, x.quantize, 1, [], [])
5185
5186 c = Context()
5187 self.assertRaises(TypeError, c.power, 1, 2, mod="x")
5188 self.assertRaises(TypeError, c.power, 1, "x", mod=None)
5189 self.assertRaises(TypeError, c.power, "x", 2, mod=None)
5190
Stefan Krah1919b7e2012-03-21 18:25:23 +01005191 @requires_extra_functionality
5192 def test_c_context_templates(self):
5193 self.assertEqual(
5194 C.BasicContext._traps,
5195 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow|
5196 C.DecUnderflow|C.DecClamped
5197 )
5198 self.assertEqual(
5199 C.DefaultContext._traps,
5200 C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow
5201 )
Mark Dickinson84230a12010-02-18 14:49:50 +00005202
Stefan Krah1919b7e2012-03-21 18:25:23 +01005203 @requires_extra_functionality
5204 def test_c_signal_dict(self):
Mark Dickinson84230a12010-02-18 14:49:50 +00005205
Stefan Krah1919b7e2012-03-21 18:25:23 +01005206 # SignalDict coverage
5207 Context = C.Context
5208 DefaultContext = C.DefaultContext
Mark Dickinson84230a12010-02-18 14:49:50 +00005209
Stefan Krah1919b7e2012-03-21 18:25:23 +01005210 InvalidOperation = C.InvalidOperation
Stefan Krah5fe1df12020-06-05 22:01:18 +02005211 FloatOperation = C.FloatOperation
Stefan Krah1919b7e2012-03-21 18:25:23 +01005212 DivisionByZero = C.DivisionByZero
5213 Overflow = C.Overflow
5214 Subnormal = C.Subnormal
5215 Underflow = C.Underflow
5216 Rounded = C.Rounded
5217 Inexact = C.Inexact
5218 Clamped = C.Clamped
Mark Dickinson84230a12010-02-18 14:49:50 +00005219
Stefan Krah1919b7e2012-03-21 18:25:23 +01005220 DecClamped = C.DecClamped
5221 DecInvalidOperation = C.DecInvalidOperation
5222 DecIEEEInvalidOperation = C.DecIEEEInvalidOperation
Mark Dickinson84230a12010-02-18 14:49:50 +00005223
Stefan Krah1919b7e2012-03-21 18:25:23 +01005224 def assertIsExclusivelySet(signal, signal_dict):
5225 for sig in signal_dict:
5226 if sig == signal:
5227 self.assertTrue(signal_dict[sig])
5228 else:
5229 self.assertFalse(signal_dict[sig])
Mark Dickinson84230a12010-02-18 14:49:50 +00005230
Stefan Krah1919b7e2012-03-21 18:25:23 +01005231 c = DefaultContext.copy()
Mark Dickinson84230a12010-02-18 14:49:50 +00005232
Stefan Krah1919b7e2012-03-21 18:25:23 +01005233 # Signal dict methods
5234 self.assertTrue(Overflow in c.traps)
5235 c.clear_traps()
5236 for k in c.traps.keys():
5237 c.traps[k] = True
5238 for v in c.traps.values():
5239 self.assertTrue(v)
5240 c.clear_traps()
5241 for k, v in c.traps.items():
5242 self.assertFalse(v)
Mark Dickinson84230a12010-02-18 14:49:50 +00005243
Stefan Krah1919b7e2012-03-21 18:25:23 +01005244 self.assertFalse(c.flags.get(Overflow))
5245 self.assertIs(c.flags.get("x"), None)
5246 self.assertEqual(c.flags.get("x", "y"), "y")
5247 self.assertRaises(TypeError, c.flags.get, "x", "y", "z")
Mark Dickinson84230a12010-02-18 14:49:50 +00005248
Stefan Krah1919b7e2012-03-21 18:25:23 +01005249 self.assertEqual(len(c.flags), len(c.traps))
5250 s = sys.getsizeof(c.flags)
5251 s = sys.getsizeof(c.traps)
5252 s = c.flags.__repr__()
Mark Dickinson84230a12010-02-18 14:49:50 +00005253
Stefan Krah1919b7e2012-03-21 18:25:23 +01005254 # Set flags/traps.
5255 c.clear_flags()
5256 c._flags = DecClamped
5257 self.assertTrue(c.flags[Clamped])
Mark Dickinson84230a12010-02-18 14:49:50 +00005258
Stefan Krah1919b7e2012-03-21 18:25:23 +01005259 c.clear_traps()
5260 c._traps = DecInvalidOperation
5261 self.assertTrue(c.traps[InvalidOperation])
Mark Dickinson84230a12010-02-18 14:49:50 +00005262
Stefan Krah1919b7e2012-03-21 18:25:23 +01005263 # Set flags/traps from dictionary.
5264 c.clear_flags()
5265 d = c.flags.copy()
5266 d[DivisionByZero] = True
5267 c.flags = d
5268 assertIsExclusivelySet(DivisionByZero, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00005269
Stefan Krah1919b7e2012-03-21 18:25:23 +01005270 c.clear_traps()
5271 d = c.traps.copy()
5272 d[Underflow] = True
5273 c.traps = d
5274 assertIsExclusivelySet(Underflow, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00005275
Stefan Krah1919b7e2012-03-21 18:25:23 +01005276 # Random constructors
5277 IntSignals = {
5278 Clamped: C.DecClamped,
5279 Rounded: C.DecRounded,
5280 Inexact: C.DecInexact,
5281 Subnormal: C.DecSubnormal,
5282 Underflow: C.DecUnderflow,
5283 Overflow: C.DecOverflow,
5284 DivisionByZero: C.DecDivisionByZero,
Stefan Krah5fe1df12020-06-05 22:01:18 +02005285 FloatOperation: C.DecFloatOperation,
Stefan Krah1919b7e2012-03-21 18:25:23 +01005286 InvalidOperation: C.DecIEEEInvalidOperation
5287 }
5288 IntCond = [
5289 C.DecDivisionImpossible, C.DecDivisionUndefined, C.DecFpuError,
5290 C.DecInvalidContext, C.DecInvalidOperation, C.DecMallocError,
5291 C.DecConversionSyntax,
5292 ]
Mark Dickinsonb455e582011-05-22 12:53:18 +01005293
Stefan Krah1919b7e2012-03-21 18:25:23 +01005294 lim = len(OrderedSignals[C])
5295 for r in range(lim):
5296 for t in range(lim):
Stefan Krah59a4a932013-01-16 12:58:59 +01005297 for round in RoundingModes:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005298 flags = random.sample(OrderedSignals[C], r)
5299 traps = random.sample(OrderedSignals[C], t)
5300 prec = random.randrange(1, 10000)
5301 emin = random.randrange(-10000, 0)
5302 emax = random.randrange(0, 10000)
5303 clamp = random.randrange(0, 2)
5304 caps = random.randrange(0, 2)
5305 cr = random.randrange(0, 2)
5306 c = Context(prec=prec, rounding=round, Emin=emin, Emax=emax,
5307 capitals=caps, clamp=clamp, flags=list(flags),
5308 traps=list(traps))
Mark Dickinson84230a12010-02-18 14:49:50 +00005309
Stefan Krah1919b7e2012-03-21 18:25:23 +01005310 self.assertEqual(c.prec, prec)
5311 self.assertEqual(c.rounding, round)
5312 self.assertEqual(c.Emin, emin)
5313 self.assertEqual(c.Emax, emax)
5314 self.assertEqual(c.capitals, caps)
5315 self.assertEqual(c.clamp, clamp)
Mark Dickinson84230a12010-02-18 14:49:50 +00005316
Stefan Krah1919b7e2012-03-21 18:25:23 +01005317 f = 0
5318 for x in flags:
5319 f |= IntSignals[x]
5320 self.assertEqual(c._flags, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00005321
Stefan Krah1919b7e2012-03-21 18:25:23 +01005322 f = 0
5323 for x in traps:
5324 f |= IntSignals[x]
5325 self.assertEqual(c._traps, f)
Mark Dickinson84230a12010-02-18 14:49:50 +00005326
Stefan Krah1919b7e2012-03-21 18:25:23 +01005327 for cond in IntCond:
5328 c._flags = cond
5329 self.assertTrue(c._flags&DecIEEEInvalidOperation)
5330 assertIsExclusivelySet(InvalidOperation, c.flags)
Mark Dickinson84230a12010-02-18 14:49:50 +00005331
Stefan Krah1919b7e2012-03-21 18:25:23 +01005332 for cond in IntCond:
5333 c._traps = cond
5334 self.assertTrue(c._traps&DecIEEEInvalidOperation)
5335 assertIsExclusivelySet(InvalidOperation, c.traps)
Mark Dickinson84230a12010-02-18 14:49:50 +00005336
Stefan Krah1919b7e2012-03-21 18:25:23 +01005337 def test_invalid_override(self):
5338 Decimal = C.Decimal
Mark Dickinson84230a12010-02-18 14:49:50 +00005339
Stefan Krah1919b7e2012-03-21 18:25:23 +01005340 try:
5341 from locale import CHAR_MAX
5342 except ImportError:
Zachary Ware9fe6d862013-12-08 00:20:35 -06005343 self.skipTest('locale.CHAR_MAX not available')
Mark Dickinson84230a12010-02-18 14:49:50 +00005344
Stefan Krah1919b7e2012-03-21 18:25:23 +01005345 def make_grouping(lst):
5346 return ''.join([chr(x) for x in lst])
Mark Dickinson84230a12010-02-18 14:49:50 +00005347
Stefan Krah1919b7e2012-03-21 18:25:23 +01005348 def get_fmt(x, override=None, fmt='n'):
5349 return Decimal(x).__format__(fmt, override)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005350
Stefan Krah1919b7e2012-03-21 18:25:23 +01005351 invalid_grouping = {
5352 'decimal_point' : ',',
5353 'grouping' : make_grouping([255, 255, 0]),
5354 'thousands_sep' : ','
5355 }
5356 invalid_dot = {
5357 'decimal_point' : 'xxxxx',
5358 'grouping' : make_grouping([3, 3, 0]),
5359 'thousands_sep' : ','
5360 }
5361 invalid_sep = {
5362 'decimal_point' : '.',
5363 'grouping' : make_grouping([3, 3, 0]),
5364 'thousands_sep' : 'yyyyy'
5365 }
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005366
Stefan Krah1919b7e2012-03-21 18:25:23 +01005367 if CHAR_MAX == 127: # negative grouping in override
5368 self.assertRaises(ValueError, get_fmt, 12345,
5369 invalid_grouping, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005370
Stefan Krah1919b7e2012-03-21 18:25:23 +01005371 self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g')
5372 self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005373
Stefan Krah0774e9b2012-04-05 15:21:58 +02005374 def test_exact_conversion(self):
5375 Decimal = C.Decimal
5376 localcontext = C.localcontext
5377 InvalidOperation = C.InvalidOperation
5378
5379 with localcontext() as c:
5380
5381 c.traps[InvalidOperation] = True
5382
5383 # Clamped
5384 x = "0e%d" % sys.maxsize
5385 self.assertRaises(InvalidOperation, Decimal, x)
5386
5387 x = "0e%d" % (-sys.maxsize-1)
5388 self.assertRaises(InvalidOperation, Decimal, x)
5389
5390 # Overflow
5391 x = "1e%d" % sys.maxsize
5392 self.assertRaises(InvalidOperation, Decimal, x)
5393
5394 # Underflow
5395 x = "1e%d" % (-sys.maxsize-1)
5396 self.assertRaises(InvalidOperation, Decimal, x)
5397
Stefan Krahff3eca02012-04-05 15:46:19 +02005398 def test_from_tuple(self):
5399 Decimal = C.Decimal
5400 localcontext = C.localcontext
5401 InvalidOperation = C.InvalidOperation
5402 Overflow = C.Overflow
5403 Underflow = C.Underflow
5404
5405 with localcontext() as c:
5406
5407 c.traps[InvalidOperation] = True
5408 c.traps[Overflow] = True
5409 c.traps[Underflow] = True
5410
5411 # SSIZE_MAX
5412 x = (1, (), sys.maxsize)
5413 self.assertEqual(str(c.create_decimal(x)), '-0E+999999')
5414 self.assertRaises(InvalidOperation, Decimal, x)
5415
5416 x = (1, (0, 1, 2), sys.maxsize)
5417 self.assertRaises(Overflow, c.create_decimal, x)
5418 self.assertRaises(InvalidOperation, Decimal, x)
5419
5420 # SSIZE_MIN
5421 x = (1, (), -sys.maxsize-1)
Stefan Krahe95dfc52018-06-03 18:40:00 +02005422 self.assertEqual(str(c.create_decimal(x)), '-0E-1000007')
Stefan Krahff3eca02012-04-05 15:46:19 +02005423 self.assertRaises(InvalidOperation, Decimal, x)
5424
5425 x = (1, (0, 1, 2), -sys.maxsize-1)
5426 self.assertRaises(Underflow, c.create_decimal, x)
5427 self.assertRaises(InvalidOperation, Decimal, x)
5428
5429 # OverflowError
5430 x = (1, (), sys.maxsize+1)
5431 self.assertRaises(OverflowError, c.create_decimal, x)
5432 self.assertRaises(OverflowError, Decimal, x)
5433
5434 x = (1, (), -sys.maxsize-2)
5435 self.assertRaises(OverflowError, c.create_decimal, x)
5436 self.assertRaises(OverflowError, Decimal, x)
5437
5438 # Specials
5439 x = (1, (), "N")
5440 self.assertEqual(str(Decimal(x)), '-sNaN')
5441 x = (1, (0,), "N")
5442 self.assertEqual(str(Decimal(x)), '-sNaN')
5443 x = (1, (0, 1), "N")
5444 self.assertEqual(str(Decimal(x)), '-sNaN1')
5445
Stefan Krah891ca9e2013-05-29 19:14:17 +02005446 def test_sizeof(self):
5447 Decimal = C.Decimal
5448 HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
5449
5450 self.assertGreater(Decimal(0).__sizeof__(), 0)
5451 if HAVE_CONFIG_64:
5452 x = Decimal(10**(19*24)).__sizeof__()
5453 y = Decimal(10**(19*25)).__sizeof__()
5454 self.assertEqual(y, x+8)
5455 else:
5456 x = Decimal(10**(9*24)).__sizeof__()
5457 y = Decimal(10**(9*25)).__sizeof__()
5458 self.assertEqual(y, x+4)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005459
Stefan Krah8c126f12016-07-17 14:01:42 +02005460 def test_internal_use_of_overridden_methods(self):
5461 Decimal = C.Decimal
5462
5463 # Unsound subtyping
5464 class X(float):
5465 def as_integer_ratio(self):
5466 return 1
5467 def __abs__(self):
5468 return self
5469
5470 class Y(float):
5471 def __abs__(self):
5472 return [1]*200
5473
5474 class I(int):
5475 def bit_length(self):
5476 return [1]*200
5477
5478 class Z(float):
5479 def as_integer_ratio(self):
5480 return (I(1), I(1))
5481 def __abs__(self):
5482 return self
5483
5484 for cls in X, Y, Z:
5485 self.assertEqual(Decimal.from_float(cls(101.1)),
5486 Decimal.from_float(101.1))
5487
Stefan Krah39dab242020-08-15 20:19:07 +02005488 # Issue 41540:
5489 @unittest.skipIf(sys.platform.startswith("aix"),
5490 "AIX: default ulimit: test is flaky because of extreme over-allocation")
Stefan Krah90930e62020-02-21 01:52:47 +01005491 def test_maxcontext_exact_arith(self):
5492
5493 # Make sure that exact operations do not raise MemoryError due
5494 # to huge intermediate values when the context precision is very
5495 # large.
5496
5497 # The following functions fill the available precision and are
5498 # therefore not suitable for large precisions (by design of the
5499 # specification).
5500 MaxContextSkip = ['logical_invert', 'next_minus', 'next_plus',
5501 'logical_and', 'logical_or', 'logical_xor',
5502 'next_toward', 'rotate', 'shift']
5503
5504 Decimal = C.Decimal
5505 Context = C.Context
5506 localcontext = C.localcontext
5507
5508 # Here only some functions that are likely candidates for triggering a
5509 # MemoryError are tested. deccheck.py has an exhaustive test.
5510 maxcontext = Context(prec=C.MAX_PREC, Emin=C.MIN_EMIN, Emax=C.MAX_EMAX)
5511 with localcontext(maxcontext):
5512 self.assertEqual(Decimal(0).exp(), 1)
5513 self.assertEqual(Decimal(1).ln(), 0)
5514 self.assertEqual(Decimal(1).log10(), 0)
5515 self.assertEqual(Decimal(10**2).log10(), 2)
5516 self.assertEqual(Decimal(10**223).log10(), 223)
5517 self.assertEqual(Decimal(10**19).logb(), 19)
5518 self.assertEqual(Decimal(4).sqrt(), 2)
5519 self.assertEqual(Decimal("40E9").sqrt(), Decimal('2.0E+5'))
5520 self.assertEqual(divmod(Decimal(10), 3), (3, 1))
5521 self.assertEqual(Decimal(10) // 3, 3)
5522 self.assertEqual(Decimal(4) / 2, 2)
5523 self.assertEqual(Decimal(400) ** -1, Decimal('0.0025'))
5524
5525
Stefan Krah6b794b82014-05-01 17:42:33 +02005526@requires_docstrings
5527@unittest.skipUnless(C, "test requires C version")
Stefan Krah5de1f822014-05-01 15:53:42 +02005528class SignatureTest(unittest.TestCase):
5529 """Function signatures"""
5530
5531 def test_inspect_module(self):
5532 for attr in dir(P):
5533 if attr.startswith('_'):
5534 continue
5535 p_func = getattr(P, attr)
5536 c_func = getattr(C, attr)
5537 if (attr == 'Decimal' or attr == 'Context' or
5538 inspect.isfunction(p_func)):
5539 p_sig = inspect.signature(p_func)
5540 c_sig = inspect.signature(c_func)
5541
5542 # parameter names:
5543 c_names = list(c_sig.parameters.keys())
5544 p_names = [x for x in p_sig.parameters.keys() if not
5545 x.startswith('_')]
5546
5547 self.assertEqual(c_names, p_names,
5548 msg="parameter name mismatch in %s" % p_func)
5549
5550 c_kind = [x.kind for x in c_sig.parameters.values()]
5551 p_kind = [x[1].kind for x in p_sig.parameters.items() if not
5552 x[0].startswith('_')]
5553
5554 # parameters:
5555 if attr != 'setcontext':
5556 self.assertEqual(c_kind, p_kind,
5557 msg="parameter kind mismatch in %s" % p_func)
5558
5559 def test_inspect_types(self):
5560
5561 POS = inspect._ParameterKind.POSITIONAL_ONLY
5562 POS_KWD = inspect._ParameterKind.POSITIONAL_OR_KEYWORD
5563
5564 # Type heuristic (type annotations would help!):
5565 pdict = {C: {'other': C.Decimal(1),
5566 'third': C.Decimal(1),
5567 'x': C.Decimal(1),
5568 'y': C.Decimal(1),
5569 'z': C.Decimal(1),
5570 'a': C.Decimal(1),
5571 'b': C.Decimal(1),
5572 'c': C.Decimal(1),
5573 'exp': C.Decimal(1),
5574 'modulo': C.Decimal(1),
5575 'num': "1",
5576 'f': 1.0,
5577 'rounding': C.ROUND_HALF_UP,
5578 'context': C.getcontext()},
5579 P: {'other': P.Decimal(1),
5580 'third': P.Decimal(1),
5581 'a': P.Decimal(1),
5582 'b': P.Decimal(1),
5583 'c': P.Decimal(1),
5584 'exp': P.Decimal(1),
5585 'modulo': P.Decimal(1),
5586 'num': "1",
5587 'f': 1.0,
5588 'rounding': P.ROUND_HALF_UP,
5589 'context': P.getcontext()}}
5590
5591 def mkargs(module, sig):
5592 args = []
5593 kwargs = {}
5594 for name, param in sig.parameters.items():
5595 if name == 'self': continue
5596 if param.kind == POS:
5597 args.append(pdict[module][name])
5598 elif param.kind == POS_KWD:
5599 kwargs[name] = pdict[module][name]
5600 else:
5601 raise TestFailed("unexpected parameter kind")
5602 return args, kwargs
5603
5604 def tr(s):
5605 """The C Context docstrings use 'x' in order to prevent confusion
5606 with the article 'a' in the descriptions."""
5607 if s == 'x': return 'a'
5608 if s == 'y': return 'b'
5609 if s == 'z': return 'c'
5610 return s
5611
5612 def doit(ty):
5613 p_type = getattr(P, ty)
5614 c_type = getattr(C, ty)
5615 for attr in dir(p_type):
5616 if attr.startswith('_'):
5617 continue
5618 p_func = getattr(p_type, attr)
5619 c_func = getattr(c_type, attr)
5620 if inspect.isfunction(p_func):
5621 p_sig = inspect.signature(p_func)
5622 c_sig = inspect.signature(c_func)
5623
5624 # parameter names:
5625 p_names = list(p_sig.parameters.keys())
5626 c_names = [tr(x) for x in c_sig.parameters.keys()]
5627
5628 self.assertEqual(c_names, p_names,
5629 msg="parameter name mismatch in %s" % p_func)
5630
5631 p_kind = [x.kind for x in p_sig.parameters.values()]
5632 c_kind = [x.kind for x in c_sig.parameters.values()]
5633
5634 # 'self' parameter:
5635 self.assertIs(p_kind[0], POS_KWD)
5636 self.assertIs(c_kind[0], POS)
5637
5638 # remaining parameters:
5639 if ty == 'Decimal':
5640 self.assertEqual(c_kind[1:], p_kind[1:],
5641 msg="parameter kind mismatch in %s" % p_func)
5642 else: # Context methods are positional only in the C version.
5643 self.assertEqual(len(c_kind), len(p_kind),
5644 msg="parameter kind mismatch in %s" % p_func)
5645
5646 # Run the function:
5647 args, kwds = mkargs(C, c_sig)
5648 try:
5649 getattr(c_type(9), attr)(*args, **kwds)
Pablo Galindo293dd232019-11-19 21:34:03 +00005650 except Exception:
Stefan Krah5de1f822014-05-01 15:53:42 +02005651 raise TestFailed("invalid signature for %s: %s %s" % (c_func, args, kwds))
5652
5653 args, kwds = mkargs(P, p_sig)
5654 try:
5655 getattr(p_type(9), attr)(*args, **kwds)
Pablo Galindo293dd232019-11-19 21:34:03 +00005656 except Exception:
Stefan Krah5de1f822014-05-01 15:53:42 +02005657 raise TestFailed("invalid signature for %s: %s %s" % (p_func, args, kwds))
5658
5659 doit('Decimal')
5660 doit('Context')
5661
5662
Stefan Krah1919b7e2012-03-21 18:25:23 +01005663all_tests = [
5664 CExplicitConstructionTest, PyExplicitConstructionTest,
5665 CImplicitConstructionTest, PyImplicitConstructionTest,
5666 CFormatTest, PyFormatTest,
5667 CArithmeticOperatorsTest, PyArithmeticOperatorsTest,
5668 CThreadingTest, PyThreadingTest,
5669 CUsabilityTest, PyUsabilityTest,
5670 CPythonAPItests, PyPythonAPItests,
5671 CContextAPItests, PyContextAPItests,
5672 CContextWithStatement, PyContextWithStatement,
5673 CContextFlags, PyContextFlags,
5674 CSpecialContexts, PySpecialContexts,
5675 CContextInputValidation, PyContextInputValidation,
5676 CContextSubclassing, PyContextSubclassing,
5677 CCoverage, PyCoverage,
5678 CFunctionality, PyFunctionality,
5679 CWhitebox, PyWhitebox,
5680 CIBMTestCases, PyIBMTestCases,
5681]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005682
Stefan Krah1919b7e2012-03-21 18:25:23 +01005683# Delete C tests if _decimal.so is not present.
5684if not C:
5685 all_tests = all_tests[1::2]
5686else:
5687 all_tests.insert(0, CheckAttributes)
Stefan Krah5de1f822014-05-01 15:53:42 +02005688 all_tests.insert(1, SignatureTest)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005689
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005690
Zachary Ware66f29282014-06-02 16:01:29 -05005691def test_main(arith=None, verbose=None, todo_tests=None, debug=None):
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005692 """ Execute the tests.
5693
Raymond Hettingered20ad82004-09-04 20:09:13 +00005694 Runs all arithmetic tests if arith is True or if the "decimal" resource
5695 is enabled in regrtest.py
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005696 """
Raymond Hettingered20ad82004-09-04 20:09:13 +00005697
Stefan Krah1919b7e2012-03-21 18:25:23 +01005698 init(C)
5699 init(P)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005700 global TEST_ALL, DEBUG
Zachary Ware66f29282014-06-02 16:01:29 -05005701 TEST_ALL = arith if arith is not None else is_resource_enabled('decimal')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005702 DEBUG = debug
Raymond Hettingered20ad82004-09-04 20:09:13 +00005703
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005704 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005705 test_classes = all_tests
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005706 else:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005707 test_classes = [CIBMTestCases, PyIBMTestCases]
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005708
5709 # Dynamically build custom test definition for each file in the test
5710 # directory and add the definitions to the DecimalTest class. This
5711 # procedure insures that new files do not get skipped.
5712 for filename in os.listdir(directory):
5713 if '.decTest' not in filename or filename.startswith("."):
5714 continue
5715 head, tail = filename.split('.')
5716 if todo_tests is not None and head not in todo_tests:
5717 continue
5718 tester = lambda self, f=filename: self.eval_file(directory + f)
Stefan Krah1919b7e2012-03-21 18:25:23 +01005719 setattr(CIBMTestCases, 'test_' + head, tester)
5720 setattr(PyIBMTestCases, 'test_' + head, tester)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005721 del filename, head, tail, tester
5722
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005723
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005724 try:
5725 run_unittest(*test_classes)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005726 if todo_tests is None:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005727 from doctest import IGNORE_EXCEPTION_DETAIL
5728 savedecimal = sys.modules['decimal']
5729 if C:
5730 sys.modules['decimal'] = C
5731 run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL)
5732 sys.modules['decimal'] = P
5733 run_doctest(P, verbose)
5734 sys.modules['decimal'] = savedecimal
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005735 finally:
Stefan Krah1919b7e2012-03-21 18:25:23 +01005736 if C: C.setcontext(ORIGINAL_CONTEXT[C])
5737 P.setcontext(ORIGINAL_CONTEXT[P])
5738 if not C:
5739 warnings.warn('C tests skipped: no module named _decimal.',
5740 UserWarning)
5741 if not orig_sys_decimal is sys.modules['decimal']:
5742 raise TestFailed("Internal error: unbalanced number of changes to "
5743 "sys.modules['decimal'].")
5744
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005745
5746if __name__ == '__main__':
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005747 import optparse
5748 p = optparse.OptionParser("test_decimal.py [--debug] [{--skip | test1 [test2 [...]]}]")
5749 p.add_option('--debug', '-d', action='store_true', help='shows the test number and context before each test')
5750 p.add_option('--skip', '-s', action='store_true', help='skip over 90% of the arithmetic tests')
5751 (opt, args) = p.parse_args()
5752
5753 if opt.skip:
5754 test_main(arith=False, verbose=True)
5755 elif args:
5756 test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
Raymond Hettinger7c85fa42004-07-01 11:01:35 +00005757 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00005758 test_main(arith=True, verbose=True)