summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_decimal.py
diff options
context:
space:
mode:
authorStefan Krah <skrah@bytereef.org>2014-05-01 13:53:42 (GMT)
committerStefan Krah <skrah@bytereef.org>2014-05-01 13:53:42 (GMT)
commit5de1f824641822accc34328a4c206f785fc653bd (patch)
tree3ed2f48ae08fc9cd3aeeca5f11c261031ef50115 /Lib/test/test_decimal.py
parentb9e71d4a55f968cd713bebe417e9fa4ba1ec12eb (diff)
downloadcpython-5de1f824641822accc34328a4c206f785fc653bd.zip
cpython-5de1f824641822accc34328a4c206f785fc653bd.tar.gz
cpython-5de1f824641822accc34328a4c206f785fc653bd.tar.bz2
Issue #21407: _decimal now supports function signatures.
Diffstat (limited to 'Lib/test/test_decimal.py')
-rw-r--r--Lib/test/test_decimal.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 339fe7c..5a65bc2 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -39,6 +39,7 @@ from test.support import (check_warnings, import_fresh_module, TestFailed,
import random
import time
import warnings
+import inspect
try:
import threading
except ImportError:
@@ -5390,6 +5391,142 @@ class CWhitebox(unittest.TestCase):
y = Decimal(10**(9*25)).__sizeof__()
self.assertEqual(y, x+4)
+unittest.skipUnless(C, "test requires C version")
+class SignatureTest(unittest.TestCase):
+ """Function signatures"""
+
+ def test_inspect_module(self):
+ for attr in dir(P):
+ if attr.startswith('_'):
+ continue
+ p_func = getattr(P, attr)
+ c_func = getattr(C, attr)
+ if (attr == 'Decimal' or attr == 'Context' or
+ inspect.isfunction(p_func)):
+ p_sig = inspect.signature(p_func)
+ c_sig = inspect.signature(c_func)
+
+ # parameter names:
+ c_names = list(c_sig.parameters.keys())
+ p_names = [x for x in p_sig.parameters.keys() if not
+ x.startswith('_')]
+
+ self.assertEqual(c_names, p_names,
+ msg="parameter name mismatch in %s" % p_func)
+
+ c_kind = [x.kind for x in c_sig.parameters.values()]
+ p_kind = [x[1].kind for x in p_sig.parameters.items() if not
+ x[0].startswith('_')]
+
+ # parameters:
+ if attr != 'setcontext':
+ self.assertEqual(c_kind, p_kind,
+ msg="parameter kind mismatch in %s" % p_func)
+
+ def test_inspect_types(self):
+
+ POS = inspect._ParameterKind.POSITIONAL_ONLY
+ POS_KWD = inspect._ParameterKind.POSITIONAL_OR_KEYWORD
+
+ # Type heuristic (type annotations would help!):
+ pdict = {C: {'other': C.Decimal(1),
+ 'third': C.Decimal(1),
+ 'x': C.Decimal(1),
+ 'y': C.Decimal(1),
+ 'z': C.Decimal(1),
+ 'a': C.Decimal(1),
+ 'b': C.Decimal(1),
+ 'c': C.Decimal(1),
+ 'exp': C.Decimal(1),
+ 'modulo': C.Decimal(1),
+ 'num': "1",
+ 'f': 1.0,
+ 'rounding': C.ROUND_HALF_UP,
+ 'context': C.getcontext()},
+ P: {'other': P.Decimal(1),
+ 'third': P.Decimal(1),
+ 'a': P.Decimal(1),
+ 'b': P.Decimal(1),
+ 'c': P.Decimal(1),
+ 'exp': P.Decimal(1),
+ 'modulo': P.Decimal(1),
+ 'num': "1",
+ 'f': 1.0,
+ 'rounding': P.ROUND_HALF_UP,
+ 'context': P.getcontext()}}
+
+ def mkargs(module, sig):
+ args = []
+ kwargs = {}
+ for name, param in sig.parameters.items():
+ if name == 'self': continue
+ if param.kind == POS:
+ args.append(pdict[module][name])
+ elif param.kind == POS_KWD:
+ kwargs[name] = pdict[module][name]
+ else:
+ raise TestFailed("unexpected parameter kind")
+ return args, kwargs
+
+ def tr(s):
+ """The C Context docstrings use 'x' in order to prevent confusion
+ with the article 'a' in the descriptions."""
+ if s == 'x': return 'a'
+ if s == 'y': return 'b'
+ if s == 'z': return 'c'
+ return s
+
+ def doit(ty):
+ p_type = getattr(P, ty)
+ c_type = getattr(C, ty)
+ for attr in dir(p_type):
+ if attr.startswith('_'):
+ continue
+ p_func = getattr(p_type, attr)
+ c_func = getattr(c_type, attr)
+ if inspect.isfunction(p_func):
+ p_sig = inspect.signature(p_func)
+ c_sig = inspect.signature(c_func)
+
+ # parameter names:
+ p_names = list(p_sig.parameters.keys())
+ c_names = [tr(x) for x in c_sig.parameters.keys()]
+
+ self.assertEqual(c_names, p_names,
+ msg="parameter name mismatch in %s" % p_func)
+
+ p_kind = [x.kind for x in p_sig.parameters.values()]
+ c_kind = [x.kind for x in c_sig.parameters.values()]
+
+ # 'self' parameter:
+ self.assertIs(p_kind[0], POS_KWD)
+ self.assertIs(c_kind[0], POS)
+
+ # remaining parameters:
+ if ty == 'Decimal':
+ self.assertEqual(c_kind[1:], p_kind[1:],
+ msg="parameter kind mismatch in %s" % p_func)
+ else: # Context methods are positional only in the C version.
+ self.assertEqual(len(c_kind), len(p_kind),
+ msg="parameter kind mismatch in %s" % p_func)
+
+ # Run the function:
+ args, kwds = mkargs(C, c_sig)
+ try:
+ getattr(c_type(9), attr)(*args, **kwds)
+ except Exception as err:
+ raise TestFailed("invalid signature for %s: %s %s" % (c_func, args, kwds))
+
+ args, kwds = mkargs(P, p_sig)
+ try:
+ getattr(p_type(9), attr)(*args, **kwds)
+ except Exception as err:
+ raise TestFailed("invalid signature for %s: %s %s" % (p_func, args, kwds))
+
+ doit('Decimal')
+ doit('Context')
+
+
all_tests = [
CExplicitConstructionTest, PyExplicitConstructionTest,
CImplicitConstructionTest, PyImplicitConstructionTest,
@@ -5415,6 +5552,7 @@ if not C:
all_tests = all_tests[1::2]
else:
all_tests.insert(0, CheckAttributes)
+ all_tests.insert(1, SignatureTest)
def test_main(arith=False, verbose=None, todo_tests=None, debug=None):