[Python-checkins] [3.12] gh-89392: Make test_decimal discoverable (GH-106209) (#106230)
ambv
webhook-mailer at python.org
Wed Jul 5 06:52:20 EDT 2023
https://github.com/python/cpython/commit/334b95b2434880e6138d430054c3054266e6020f
commit: 334b95b2434880e6138d430054c3054266e6020f
branch: 3.12
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: ambv <lukasz at langa.pl>
date: 2023-07-05T12:52:16+02:00
summary:
[3.12] gh-89392: Make test_decimal discoverable (GH-106209) (#106230)
gh-89392: Make test_decimal discoverable (GH-106209)
(cherry picked from commit 0e24499129f3917b199a6d46fa33eeedd2c447fc)
Co-authored-by: Serhiy Storchaka <storchaka at gmail.com>
files:
M Lib/test/test_decimal.py
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 67ccaab40c5ed..749496e3e9455 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -20,7 +20,7 @@
This test module can be called from command line with one parameter (Arithmetic
or Behaviour) to test each part, or without parameter to test both parts. If
-you're working through IDLE, you can import this test module and call test_main()
+you're working through IDLE, you can import this test module and call test()
with the corresponding argument.
"""
@@ -32,7 +32,7 @@
import unittest
import numbers
import locale
-from test.support import (run_unittest, run_doctest, is_resource_enabled,
+from test.support import (is_resource_enabled,
requires_IEEE_754, requires_docstrings,
requires_legacy_unicode_capi, check_sanitizer)
from test.support import (TestFailed,
@@ -62,6 +62,7 @@
fractions = {C:cfractions, P:pfractions}
sys.modules['decimal'] = orig_sys_decimal
+requires_cdecimal = unittest.skipUnless(C, "test requires C version")
# Useful Test Constant
Signals = {
@@ -99,7 +100,7 @@ def assert_signals(cls, context, attr, expected):
]
# Tests are built around these assumed context defaults.
-# test_main() restores the original context.
+# test() restores the original context.
ORIGINAL_CONTEXT = {
C: C.getcontext().copy() if C else None,
P: P.getcontext().copy()
@@ -133,7 +134,7 @@ def init(m):
EXTRA_FUNCTIONALITY, "test requires regular build")
-class IBMTestCases(unittest.TestCase):
+class IBMTestCases:
"""Class which tests the Decimal class against the IBM test cases."""
def setUp(self):
@@ -488,14 +489,10 @@ def change_max_exponent(self, exp):
def change_clamp(self, clamp):
self.context.clamp = clamp
-class CIBMTestCases(IBMTestCases):
- decimal = C
-class PyIBMTestCases(IBMTestCases):
- decimal = P
# The following classes test the behaviour of Decimal according to PEP 327
-class ExplicitConstructionTest(unittest.TestCase):
+class ExplicitConstructionTest:
'''Unit tests for Explicit Construction cases of Decimal.'''
def test_explicit_empty(self):
@@ -838,12 +835,13 @@ def test_unicode_digits(self):
for input, expected in test_values.items():
self.assertEqual(str(Decimal(input)), expected)
-class CExplicitConstructionTest(ExplicitConstructionTest):
+ at requires_cdecimal
+class CExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase):
decimal = C
-class PyExplicitConstructionTest(ExplicitConstructionTest):
+class PyExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase):
decimal = P
-class ImplicitConstructionTest(unittest.TestCase):
+class ImplicitConstructionTest:
'''Unit tests for Implicit Construction cases of Decimal.'''
def test_implicit_from_None(self):
@@ -920,12 +918,13 @@ def __ne__(self, other):
self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
'10' + rop + 'str')
-class CImplicitConstructionTest(ImplicitConstructionTest):
+ at requires_cdecimal
+class CImplicitConstructionTest(ImplicitConstructionTest, unittest.TestCase):
decimal = C
-class PyImplicitConstructionTest(ImplicitConstructionTest):
+class PyImplicitConstructionTest(ImplicitConstructionTest, unittest.TestCase):
decimal = P
-class FormatTest(unittest.TestCase):
+class FormatTest:
'''Unit tests for the format function.'''
def test_formatting(self):
Decimal = self.decimal.Decimal
@@ -1262,12 +1261,13 @@ def __init__(self, a):
a = A.from_float(42)
self.assertEqual(self.decimal.Decimal, a.a_type)
-class CFormatTest(FormatTest):
+ at requires_cdecimal
+class CFormatTest(FormatTest, unittest.TestCase):
decimal = C
-class PyFormatTest(FormatTest):
+class PyFormatTest(FormatTest, unittest.TestCase):
decimal = P
-class ArithmeticOperatorsTest(unittest.TestCase):
+class ArithmeticOperatorsTest:
'''Unit tests for all arithmetic operators, binary and unary.'''
def test_addition(self):
@@ -1523,14 +1523,17 @@ def test_nan_comparisons(self):
equality_ops = operator.eq, operator.ne
# results when InvalidOperation is not trapped
- for x, y in qnan_pairs + snan_pairs:
- for op in order_ops + equality_ops:
- got = op(x, y)
- expected = True if op is operator.ne else False
- self.assertIs(expected, got,
- "expected {0!r} for operator.{1}({2!r}, {3!r}); "
- "got {4!r}".format(
- expected, op.__name__, x, y, got))
+ with localcontext() as ctx:
+ ctx.traps[InvalidOperation] = 0
+
+ for x, y in qnan_pairs + snan_pairs:
+ for op in order_ops + equality_ops:
+ got = op(x, y)
+ expected = True if op is operator.ne else False
+ self.assertIs(expected, got,
+ "expected {0!r} for operator.{1}({2!r}, {3!r}); "
+ "got {4!r}".format(
+ expected, op.__name__, x, y, got))
# repeat the above, but this time trap the InvalidOperation
with localcontext() as ctx:
@@ -1562,9 +1565,10 @@ def test_copy_sign(self):
self.assertEqual(Decimal(1).copy_sign(-2), d)
self.assertRaises(TypeError, Decimal(1).copy_sign, '-2')
-class CArithmeticOperatorsTest(ArithmeticOperatorsTest):
+ at requires_cdecimal
+class CArithmeticOperatorsTest(ArithmeticOperatorsTest, unittest.TestCase):
decimal = C
-class PyArithmeticOperatorsTest(ArithmeticOperatorsTest):
+class PyArithmeticOperatorsTest(ArithmeticOperatorsTest, unittest.TestCase):
decimal = P
# The following are two functions used to test threading in the next class
@@ -1654,7 +1658,7 @@ def thfunc2(cls):
@threading_helper.requires_working_threading()
-class ThreadingTest(unittest.TestCase):
+class ThreadingTest:
'''Unit tests for thread local contexts in Decimal.'''
# Take care executing this test from IDLE, there's an issue in threading
@@ -1699,13 +1703,14 @@ def test_threading(self):
DefaultContext.Emin = save_emin
-class CThreadingTest(ThreadingTest):
+ at requires_cdecimal
+class CThreadingTest(ThreadingTest, unittest.TestCase):
decimal = C
-class PyThreadingTest(ThreadingTest):
+class PyThreadingTest(ThreadingTest, unittest.TestCase):
decimal = P
-class UsabilityTest(unittest.TestCase):
+class UsabilityTest:
'''Unit tests for Usability cases of Decimal.'''
def test_comparison_operators(self):
@@ -2521,9 +2526,10 @@ def test_conversions_from_int(self):
self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
Decimal(-12).fma(Decimal(45), Decimal(67)))
-class CUsabilityTest(UsabilityTest):
+ at requires_cdecimal
+class CUsabilityTest(UsabilityTest, unittest.TestCase):
decimal = C
-class PyUsabilityTest(UsabilityTest):
+class PyUsabilityTest(UsabilityTest, unittest.TestCase):
decimal = P
def setUp(self):
@@ -2535,7 +2541,7 @@ def tearDown(self):
sys.set_int_max_str_digits(self._previous_int_limit)
super().tearDown()
-class PythonAPItests(unittest.TestCase):
+class PythonAPItests:
def test_abc(self):
Decimal = self.decimal.Decimal
@@ -2884,12 +2890,13 @@ def test_exception_hierarchy(self):
self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError))
self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation))
-class CPythonAPItests(PythonAPItests):
+ at requires_cdecimal
+class CPythonAPItests(PythonAPItests, unittest.TestCase):
decimal = C
-class PyPythonAPItests(PythonAPItests):
+class PyPythonAPItests(PythonAPItests, unittest.TestCase):
decimal = P
-class ContextAPItests(unittest.TestCase):
+class ContextAPItests:
def test_none_args(self):
Context = self.decimal.Context
@@ -3635,12 +3642,13 @@ def test_to_integral_value(self):
self.assertRaises(TypeError, c.to_integral_value, '10')
self.assertRaises(TypeError, c.to_integral_value, 10, 'x')
-class CContextAPItests(ContextAPItests):
+ at requires_cdecimal
+class CContextAPItests(ContextAPItests, unittest.TestCase):
decimal = C
-class PyContextAPItests(ContextAPItests):
+class PyContextAPItests(ContextAPItests, unittest.TestCase):
decimal = P
-class ContextWithStatement(unittest.TestCase):
+class ContextWithStatement:
# Can't do these as docstrings until Python 2.6
# as doctest can't handle __future__ statements
@@ -3704,9 +3712,13 @@ def test_localcontext_kwargs(self):
def test_local_context_kwargs_does_not_overwrite_existing_argument(self):
ctx = self.decimal.getcontext()
- ctx.prec = 28
+ orig_prec = ctx.prec
with self.decimal.localcontext(prec=10) as ctx2:
- self.assertEqual(ctx.prec, 28)
+ self.assertEqual(ctx2.prec, 10)
+ self.assertEqual(ctx.prec, orig_prec)
+ with self.decimal.localcontext(prec=20) as ctx2:
+ self.assertEqual(ctx2.prec, 20)
+ self.assertEqual(ctx.prec, orig_prec)
def test_nested_with_statements(self):
# Use a copy of the supplied context in the block
@@ -3800,12 +3812,13 @@ def test_with_statements_gc3(self):
self.assertEqual(c4.prec, 4)
del c4
-class CContextWithStatement(ContextWithStatement):
+ at requires_cdecimal
+class CContextWithStatement(ContextWithStatement, unittest.TestCase):
decimal = C
-class PyContextWithStatement(ContextWithStatement):
+class PyContextWithStatement(ContextWithStatement, unittest.TestCase):
decimal = P
-class ContextFlags(unittest.TestCase):
+class ContextFlags:
def test_flags_irrelevant(self):
# check that the result (numeric result + flags raised) of an
@@ -4072,12 +4085,13 @@ def test_float_operation_default(self):
self.assertTrue(context.traps[FloatOperation])
self.assertTrue(context.traps[Inexact])
-class CContextFlags(ContextFlags):
+ at requires_cdecimal
+class CContextFlags(ContextFlags, unittest.TestCase):
decimal = C
-class PyContextFlags(ContextFlags):
+class PyContextFlags(ContextFlags, unittest.TestCase):
decimal = P
-class SpecialContexts(unittest.TestCase):
+class SpecialContexts:
"""Test the context templates."""
def test_context_templates(self):
@@ -4157,12 +4171,13 @@ def test_default_context(self):
if ex:
raise ex
-class CSpecialContexts(SpecialContexts):
+ at requires_cdecimal
+class CSpecialContexts(SpecialContexts, unittest.TestCase):
decimal = C
-class PySpecialContexts(SpecialContexts):
+class PySpecialContexts(SpecialContexts, unittest.TestCase):
decimal = P
-class ContextInputValidation(unittest.TestCase):
+class ContextInputValidation:
def test_invalid_context(self):
Context = self.decimal.Context
@@ -4224,12 +4239,13 @@ def test_invalid_context(self):
self.assertRaises(TypeError, Context, flags=(0,1))
self.assertRaises(TypeError, Context, traps=(1,0))
-class CContextInputValidation(ContextInputValidation):
+ at requires_cdecimal
+class CContextInputValidation(ContextInputValidation, unittest.TestCase):
decimal = C
-class PyContextInputValidation(ContextInputValidation):
+class PyContextInputValidation(ContextInputValidation, unittest.TestCase):
decimal = P
-class ContextSubclassing(unittest.TestCase):
+class ContextSubclassing:
def test_context_subclassing(self):
decimal = self.decimal
@@ -4338,12 +4354,14 @@ def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
for signal in OrderedSignals[decimal]:
self.assertFalse(c.traps[signal])
-class CContextSubclassing(ContextSubclassing):
+ at requires_cdecimal
+class CContextSubclassing(ContextSubclassing, unittest.TestCase):
decimal = C
-class PyContextSubclassing(ContextSubclassing):
+class PyContextSubclassing(ContextSubclassing, unittest.TestCase):
decimal = P
@skip_if_extra_functionality
+ at requires_cdecimal
class CheckAttributes(unittest.TestCase):
def test_module_attributes(self):
@@ -4373,7 +4391,7 @@ def test_decimal_attributes(self):
y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
self.assertEqual(set(x) - set(y), set())
-class Coverage(unittest.TestCase):
+class Coverage:
def test_adjusted(self):
Decimal = self.decimal.Decimal
@@ -4630,9 +4648,10 @@ def test_copy(self):
y = c.copy_sign(x, 1)
self.assertEqual(y, -x)
-class CCoverage(Coverage):
+ at requires_cdecimal
+class CCoverage(Coverage, unittest.TestCase):
decimal = C
-class PyCoverage(Coverage):
+class PyCoverage(Coverage, unittest.TestCase):
decimal = P
def setUp(self):
@@ -4885,6 +4904,7 @@ def test_constants(self):
self.assertEqual(C.DecTraps,
C.DecErrors|C.DecOverflow|C.DecUnderflow)
+ at requires_cdecimal
class CWhitebox(unittest.TestCase):
"""Whitebox testing for _decimal"""
@@ -5663,7 +5683,7 @@ def test_maxcontext_exact_arith(self):
@requires_docstrings
- at unittest.skipUnless(C, "test requires C version")
+ at requires_cdecimal
class SignatureTest(unittest.TestCase):
"""Function signatures"""
@@ -5799,52 +5819,10 @@ def doit(ty):
doit('Context')
-all_tests = [
- CExplicitConstructionTest, PyExplicitConstructionTest,
- CImplicitConstructionTest, PyImplicitConstructionTest,
- CFormatTest, PyFormatTest,
- CArithmeticOperatorsTest, PyArithmeticOperatorsTest,
- CThreadingTest, PyThreadingTest,
- CUsabilityTest, PyUsabilityTest,
- CPythonAPItests, PyPythonAPItests,
- CContextAPItests, PyContextAPItests,
- CContextWithStatement, PyContextWithStatement,
- CContextFlags, PyContextFlags,
- CSpecialContexts, PySpecialContexts,
- CContextInputValidation, PyContextInputValidation,
- CContextSubclassing, PyContextSubclassing,
- CCoverage, PyCoverage,
- CFunctionality, PyFunctionality,
- CWhitebox, PyWhitebox,
- CIBMTestCases, PyIBMTestCases,
-]
-
-# Delete C tests if _decimal.so is not present.
-if not C:
- all_tests = all_tests[1::2]
-else:
- all_tests.insert(0, CheckAttributes)
- all_tests.insert(1, SignatureTest)
-
-
-def test_main(arith=None, verbose=None, todo_tests=None, debug=None):
- """ Execute the tests.
-
- Runs all arithmetic tests if arith is True or if the "decimal" resource
- is enabled in regrtest.py
- """
-
- init(C)
- init(P)
- global TEST_ALL, DEBUG
- TEST_ALL = arith if arith is not None else is_resource_enabled('decimal')
- DEBUG = debug
-
- if todo_tests is None:
- test_classes = all_tests
- else:
- test_classes = [CIBMTestCases, PyIBMTestCases]
-
+def load_tests(loader, tests, pattern):
+ if TODO_TESTS is not None:
+ # Run only Arithmetic tests
+ tests = loader.suiteClass()
# Dynamically build custom test definition for each file in the test
# directory and add the definitions to the DecimalTest class. This
# procedure insures that new files do not get skipped.
@@ -5852,34 +5830,69 @@ def test_main(arith=None, verbose=None, todo_tests=None, debug=None):
if '.decTest' not in filename or filename.startswith("."):
continue
head, tail = filename.split('.')
- if todo_tests is not None and head not in todo_tests:
+ if TODO_TESTS is not None and head not in TODO_TESTS:
continue
tester = lambda self, f=filename: self.eval_file(directory + f)
- setattr(CIBMTestCases, 'test_' + head, tester)
- setattr(PyIBMTestCases, 'test_' + head, tester)
+ setattr(IBMTestCases, 'test_' + head, tester)
del filename, head, tail, tester
+ for prefix, mod in ('C', C), ('Py', P):
+ if not mod:
+ continue
+ test_class = type(prefix + 'IBMTestCases',
+ (IBMTestCases, unittest.TestCase),
+ {'decimal': mod})
+ tests.addTest(loader.loadTestsFromTestCase(test_class))
+
+ if TODO_TESTS is None:
+ from doctest import DocTestSuite, IGNORE_EXCEPTION_DETAIL
+ for mod in C, P:
+ if not mod:
+ continue
+ def setUp(slf, mod=mod):
+ sys.modules['decimal'] = mod
+ def tearDown(slf):
+ sys.modules['decimal'] = orig_sys_decimal
+ optionflags = IGNORE_EXCEPTION_DETAIL if mod is C else 0
+ sys.modules['decimal'] = mod
+ tests.addTest(DocTestSuite(mod, setUp=setUp, tearDown=tearDown,
+ optionflags=optionflags))
+ sys.modules['decimal'] = orig_sys_decimal
+ return tests
+
+def setUpModule():
+ init(C)
+ init(P)
+ global TEST_ALL
+ TEST_ALL = ARITH if ARITH is not None else is_resource_enabled('decimal')
+
+def tearDownModule():
+ if C: C.setcontext(ORIGINAL_CONTEXT[C])
+ P.setcontext(ORIGINAL_CONTEXT[P])
+ if not C:
+ warnings.warn('C tests skipped: no module named _decimal.',
+ UserWarning)
+ if not orig_sys_decimal is sys.modules['decimal']:
+ raise TestFailed("Internal error: unbalanced number of changes to "
+ "sys.modules['decimal'].")
+
+
+ARITH = None
+TEST_ALL = True
+TODO_TESTS = None
+DEBUG = False
+
+def test(arith=None, verbose=None, todo_tests=None, debug=None):
+ """ Execute the tests.
+ Runs all arithmetic tests if arith is True or if the "decimal" resource
+ is enabled in regrtest.py
+ """
- try:
- run_unittest(*test_classes)
- if todo_tests is None:
- from doctest import IGNORE_EXCEPTION_DETAIL
- savedecimal = sys.modules['decimal']
- if C:
- sys.modules['decimal'] = C
- run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL)
- sys.modules['decimal'] = P
- run_doctest(P, verbose)
- sys.modules['decimal'] = savedecimal
- finally:
- if C: C.setcontext(ORIGINAL_CONTEXT[C])
- P.setcontext(ORIGINAL_CONTEXT[P])
- if not C:
- warnings.warn('C tests skipped: no module named _decimal.',
- UserWarning)
- if not orig_sys_decimal is sys.modules['decimal']:
- raise TestFailed("Internal error: unbalanced number of changes to "
- "sys.modules['decimal'].")
+ global ARITH, TODO_TESTS, DEBUG
+ ARITH = arith
+ TODO_TESTS = todo_tests
+ DEBUG = debug
+ unittest.main(__name__, verbosity=2 if verbose else 1, exit=False, argv=[__name__])
if __name__ == '__main__':
@@ -5890,8 +5903,8 @@ def test_main(arith=None, verbose=None, todo_tests=None, debug=None):
(opt, args) = p.parse_args()
if opt.skip:
- test_main(arith=False, verbose=True)
+ test(arith=False, verbose=True)
elif args:
- test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
+ test(arith=True, verbose=True, todo_tests=args, debug=opt.debug)
else:
- test_main(arith=True, verbose=True)
+ test(arith=True, verbose=True)
More information about the Python-checkins
mailing list