1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
import time
import sys
from .ut_utils import TestCase
from forge.signature import FunctionSignature
from forge.exceptions import SignatureException, InvalidKeywordArgument, FunctionCannotBeBound
# no named tuples for python 2.5 compliance...
class ExpectedArg(object):
def __init__(self, name, has_default, default=None):
self.name = name
self.has_default = has_default
self.default = default
class SignatureTest(TestCase):
def _assert_argument_names(self, sig, names):
self.assertEqual([arg.name for arg in sig._args], names)
def _test_function_signature(self,
func,
expected_signature,
has_varargs=False,
has_varkwargs=False
):
sig = FunctionSignature(func)
self.assertEqual(len(expected_signature), len(sig._args))
self.assertEqual(len(expected_signature), sig.get_num_args())
for expected_arg, arg in zip(expected_signature, sig._args):
if isinstance(expected_arg, tuple):
expected_arg = ExpectedArg(*expected_arg)
self.assertEqual(expected_arg.name,
arg.name)
self.assertEqual(expected_arg.has_default,
arg.has_default())
if expected_arg.has_default:
self.assertEqual(expected_arg.default, arg.default)
self.assertEqual(sig.has_variable_kwargs(), has_varkwargs)
self.assertEqual(sig.has_variable_args(), has_varargs)
def test__simple_functions(self):
def f(a, b, c):
pass
self._test_function_signature(f,
[('a', False),
('b', False),
('c', False)])
def test__kwargs(self):
def f(a, b, c=2):
pass
def f_args(a, b, c=2, *args):
pass
def f_kwargs(a, b, c=2, **kwargs):
pass
def f_args_kwargs(a, b, c=2, *args, **kwargs):
pass
lambda_args_kwargs = lambda a, b, c=2, *args, **kwargs: None
sig = [('a', False),
('b', False),
('c', True, 2)]
self._test_function_signature(f, sig)
self._test_function_signature(f_args, sig, has_varargs=True)
self._test_function_signature(f_kwargs, sig, has_varkwargs=True)
self._test_function_signature(f_args_kwargs, sig, has_varargs=True, has_varkwargs=True)
self._test_function_signature(lambda_args_kwargs, sig, has_varargs=True, has_varkwargs=True)
def test__normalizing_kwargs_with_numbers(self):
# this is supported in python, but interferes with the arg-normalizing logic
sig = FunctionSignature(lambda *args, **kwargs: None)
with self.assertRaises(InvalidKeywordArgument):
sig.get_normalized_args((), {1:2})
def test__is_method_and_is_bound(self):
def f():
raise NotImplementedError()
def f_with_self_arg(self):
raise NotImplementedError()
self.assertFalse(FunctionSignature(f_with_self_arg).is_bound_method())
self.assertFalse(FunctionSignature(f).is_bound_method())
self.assertFalse(FunctionSignature(f_with_self_arg)._args[0].has_default())
class SomeClass(object):
def f_without_self():
raise NotImplementedError()
def f(self):
raise NotImplementedError()
def f_with_args(self, a, b, c):
raise NotImplementedError()
def f_with_first_argument_not_self(bla):
raise NotImplementedError()
class SomeOldStyleClass:
def f_without_self():
raise NotImplementedError()
def f(self):
raise NotImplementedError()
def f_with_args(self, a, b, c):
raise NotImplementedError()
def f_with_first_argument_not_self(bla):
raise NotImplementedError()
for cls in (SomeClass, SomeOldStyleClass):
self.assertFalse(FunctionSignature(cls.f).is_bound_method())
self.assertFalse(FunctionSignature(cls.f_with_args).is_bound_method())
self.assertFalse(FunctionSignature(cls.f_with_first_argument_not_self).is_bound_method())
self.assertTrue(FunctionSignature(cls().f).is_bound_method())
self.assertTrue(FunctionSignature(cls().f_with_args).is_bound_method())
self.assertTrue(FunctionSignature(cls().f_with_first_argument_not_self).is_bound_method())
def test__is_class_method(self):
class New(object):
@classmethod
def class_method(cls):
raise NotImplementedError()
def regular_method(self):
raise NotImplementedError()
class Old(object):
@classmethod
def class_method(cls):
raise NotImplementedError()
def regular_method(self):
raise NotImplementedError()
self.assertTrue(FunctionSignature(New.class_method).is_class_method())
self.assertTrue(FunctionSignature(Old.class_method).is_class_method())
self.assertFalse(FunctionSignature(New.regular_method).is_class_method())
self.assertFalse(FunctionSignature(Old.regular_method).is_class_method())
def test__copy(self):
f = FunctionSignature(lambda a, b: 2)
f2 = f.copy()
self.assertIsNot(f, f2)
self.assertIsNot(f._args, f2._args)
class BinaryFunctionSignatureTest(TestCase):
def test__binary_global_function_with_no_parameters(self):
sig = FunctionSignature(time.time)
self.assertEqual(sig._args, [])
if sys.version_info[:2] < (3, 13):
self.assertTrue(sig.has_variable_args())
self.assertTrue(sig.has_variable_kwargs())
else:
# Starting 3.13, inspect succeed (not raise TypeError) for buildin functions, like `time.time`
self.assertFalse(sig.has_variable_args())
self.assertFalse(sig.has_variable_kwargs())
def test__binary_global_function_with_parameters(self):
sig = FunctionSignature(time.sleep)
if sys.version_info[:2] < (3, 13):
self.assertEqual(sig._args, [])
self.assertTrue(sig.has_variable_args())
self.assertTrue(sig.has_variable_kwargs())
else:
self.assertEqual(len(sig._args), 1)
self.assertFalse(sig.has_variable_args())
self.assertFalse(sig.has_variable_kwargs())
def test__object_method_placeholders(self):
class SomeObject(object):
pass
sig = FunctionSignature(SomeObject.__ge__)
|