1"Test calltip, coverage 60%" 2 3from idlelib import calltip 4import unittest 5import textwrap 6import types 7import re 8 9 10# Test Class TC is used in multiple get_argspec test methods 11class TC(): 12 'doc' 13 tip = "(ai=None, *b)" 14 def __init__(self, ai=None, *b): 'doc' 15 __init__.tip = "(self, ai=None, *b)" 16 def t1(self): 'doc' 17 t1.tip = "(self)" 18 def t2(self, ai, b=None): 'doc' 19 t2.tip = "(self, ai, b=None)" 20 def t3(self, ai, *args): 'doc' 21 t3.tip = "(self, ai, *args)" 22 def t4(self, *args): 'doc' 23 t4.tip = "(self, *args)" 24 def t5(self, ai, b=None, *args, **kw): 'doc' 25 t5.tip = "(self, ai, b=None, *args, **kw)" 26 def t6(no, self): 'doc' 27 t6.tip = "(no, self)" 28 def __call__(self, ci): 'doc' 29 __call__.tip = "(self, ci)" 30 def nd(self): pass # No doc. 31 # attaching .tip to wrapped methods does not work 32 @classmethod 33 def cm(cls, a): 'doc' 34 @staticmethod 35 def sm(b): 'doc' 36 37 38tc = TC() 39default_tip = calltip._default_callable_argspec 40get_spec = calltip.get_argspec 41 42 43class Get_argspecTest(unittest.TestCase): 44 # The get_spec function must return a string, even if blank. 45 # Test a variety of objects to be sure that none cause it to raise 46 # (quite aside from getting as correct an answer as possible). 47 # The tests of builtins may break if inspect or the docstrings change, 48 # but a red buildbot is better than a user crash (as has happened). 49 # For a simple mismatch, change the expected output to the actual. 50 51 def test_builtins(self): 52 53 def tiptest(obj, out): 54 self.assertEqual(get_spec(obj), out) 55 56 # Python class that inherits builtin methods 57 class List(list): "List() doc" 58 59 # Simulate builtin with no docstring for default tip test 60 class SB: __call__ = None 61 62 if List.__doc__ is not None: 63 tiptest(List, 64 f'(iterable=(), /){calltip._argument_positional}' 65 f'\n{List.__doc__}') 66 tiptest(list.__new__, 67 '(*args, **kwargs)\n' 68 'Create and return a new object. ' 69 'See help(type) for accurate signature.') 70 tiptest(list.__init__, 71 '(self, /, *args, **kwargs)' 72 + calltip._argument_positional + '\n' + 73 'Initialize self. See help(type(self)) for accurate signature.') 74 append_doc = (calltip._argument_positional 75 + "\nAppend object to the end of the list.") 76 tiptest(list.append, '(self, object, /)' + append_doc) 77 tiptest(List.append, '(self, object, /)' + append_doc) 78 tiptest([].append, '(object, /)' + append_doc) 79 80 tiptest(types.MethodType, "method(function, instance)") 81 tiptest(SB(), default_tip) 82 83 p = re.compile('') 84 tiptest(re.sub, '''\ 85(pattern, repl, string, count=0, flags=0) 86Return the string obtained by replacing the leftmost 87non-overlapping occurrences of the pattern in string by the 88replacement repl. repl can be either a string or a callable; 89if a string, backslash escapes in it are processed. If it is 90a callable, it's passed the Match object and must return''') 91 tiptest(p.sub, '''\ 92(repl, string, count=0) 93Return the string obtained by replacing the leftmost \ 94non-overlapping occurrences o...''') 95 96 def test_signature_wrap(self): 97 if textwrap.TextWrapper.__doc__ is not None: 98 self.assertEqual(get_spec(textwrap.TextWrapper), '''\ 99(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, 100 replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, 101 drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, 102 placeholder=' [...]')''') 103 104 def test_properly_formated(self): 105 106 def foo(s='a'*100): 107 pass 108 109 def bar(s='a'*100): 110 """Hello Guido""" 111 pass 112 113 def baz(s='a'*100, z='b'*100): 114 pass 115 116 indent = calltip._INDENT 117 118 sfoo = "(s='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\ 119 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + indent + "aaaaaaaaa"\ 120 "aaaaaaaaaa')" 121 sbar = "(s='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\ 122 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + indent + "aaaaaaaaa"\ 123 "aaaaaaaaaa')\nHello Guido" 124 sbaz = "(s='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\ 125 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + indent + "aaaaaaaaa"\ 126 "aaaaaaaaaa', z='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"\ 127 "bbbbbbbbbbbbbbbbb\n" + indent + "bbbbbbbbbbbbbbbbbbbbbb"\ 128 "bbbbbbbbbbbbbbbbbbbbbb')" 129 130 for func,doc in [(foo, sfoo), (bar, sbar), (baz, sbaz)]: 131 with self.subTest(func=func, doc=doc): 132 self.assertEqual(get_spec(func), doc) 133 134 def test_docline_truncation(self): 135 def f(): pass 136 f.__doc__ = 'a'*300 137 self.assertEqual(get_spec(f), f"()\n{'a'*(calltip._MAX_COLS-3) + '...'}") 138 139 def test_multiline_docstring(self): 140 # Test fewer lines than max. 141 self.assertEqual(get_spec(range), 142 "range(stop) -> range object\n" 143 "range(start, stop[, step]) -> range object") 144 145 # Test max lines 146 self.assertEqual(get_spec(bytes), '''\ 147bytes(iterable_of_ints) -> bytes 148bytes(string, encoding[, errors]) -> bytes 149bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer 150bytes(int) -> bytes object of size given by the parameter initialized with null bytes 151bytes() -> empty bytes object''') 152 153 # Test more than max lines 154 def f(): pass 155 f.__doc__ = 'a\n' * 15 156 self.assertEqual(get_spec(f), '()' + '\na' * calltip._MAX_LINES) 157 158 def test_functions(self): 159 def t1(): 'doc' 160 t1.tip = "()" 161 def t2(a, b=None): 'doc' 162 t2.tip = "(a, b=None)" 163 def t3(a, *args): 'doc' 164 t3.tip = "(a, *args)" 165 def t4(*args): 'doc' 166 t4.tip = "(*args)" 167 def t5(a, b=None, *args, **kw): 'doc' 168 t5.tip = "(a, b=None, *args, **kw)" 169 170 doc = '\ndoc' if t1.__doc__ is not None else '' 171 for func in (t1, t2, t3, t4, t5, TC): 172 with self.subTest(func=func): 173 self.assertEqual(get_spec(func), func.tip + doc) 174 175 def test_methods(self): 176 doc = '\ndoc' if TC.__doc__ is not None else '' 177 for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__): 178 with self.subTest(meth=meth): 179 self.assertEqual(get_spec(meth), meth.tip + doc) 180 self.assertEqual(get_spec(TC.cm), "(a)" + doc) 181 self.assertEqual(get_spec(TC.sm), "(b)" + doc) 182 183 def test_bound_methods(self): 184 # test that first parameter is correctly removed from argspec 185 doc = '\ndoc' if TC.__doc__ is not None else '' 186 for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), 187 (tc.t6, "(self)"), (tc.__call__, '(ci)'), 188 (tc, '(ci)'), (TC.cm, "(a)"),): 189 with self.subTest(meth=meth, mtip=mtip): 190 self.assertEqual(get_spec(meth), mtip + doc) 191 192 def test_starred_parameter(self): 193 # test that starred first parameter is *not* removed from argspec 194 class C: 195 def m1(*args): pass 196 c = C() 197 for meth, mtip in ((C.m1, '(*args)'), (c.m1, "(*args)"),): 198 with self.subTest(meth=meth, mtip=mtip): 199 self.assertEqual(get_spec(meth), mtip) 200 201 def test_invalid_method_get_spec(self): 202 class C: 203 def m2(**kwargs): pass 204 class Test: 205 def __call__(*, a): pass 206 207 mtip = calltip._invalid_method 208 self.assertEqual(get_spec(C().m2), mtip) 209 self.assertEqual(get_spec(Test()), mtip) 210 211 def test_non_ascii_name(self): 212 # test that re works to delete a first parameter name that 213 # includes non-ascii chars, such as various forms of A. 214 uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" 215 assert calltip._first_param.sub('', uni) == '(a)' 216 217 def test_no_docstring(self): 218 for meth, mtip in ((TC.nd, "(self)"), (tc.nd, "()")): 219 with self.subTest(meth=meth, mtip=mtip): 220 self.assertEqual(get_spec(meth), mtip) 221 222 def test_buggy_getattr_class(self): 223 class NoCall: 224 def __getattr__(self, name): # Not invoked for class attribute. 225 raise IndexError # Bug. 226 class CallA(NoCall): 227 def __call__(self, ci): # Bug does not matter. 228 pass 229 class CallB(NoCall): 230 def __call__(oui, a, b, c): # Non-standard 'self'. 231 pass 232 233 for meth, mtip in ((NoCall, default_tip), (CallA, default_tip), 234 (NoCall(), ''), (CallA(), '(ci)'), 235 (CallB(), '(a, b, c)')): 236 with self.subTest(meth=meth, mtip=mtip): 237 self.assertEqual(get_spec(meth), mtip) 238 239 def test_metaclass_class(self): # Failure case for issue 38689. 240 class Type(type): # Type() requires 3 type args, returns class. 241 __class__ = property({}.__getitem__, {}.__setitem__) 242 class Object(metaclass=Type): 243 __slots__ = '__class__' 244 for meth, mtip in ((Type, default_tip), (Object, default_tip), 245 (Object(), '')): 246 with self.subTest(meth=meth, mtip=mtip): 247 self.assertEqual(get_spec(meth), mtip) 248 249 def test_non_callables(self): 250 for obj in (0, 0.0, '0', b'0', [], {}): 251 with self.subTest(obj=obj): 252 self.assertEqual(get_spec(obj), '') 253 254 255class Get_entityTest(unittest.TestCase): 256 def test_bad_entity(self): 257 self.assertIsNone(calltip.get_entity('1/0')) 258 def test_good_entity(self): 259 self.assertIs(calltip.get_entity('int'), int) 260 261 262if __name__ == '__main__': 263 unittest.main(verbosity=2) 264