• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Unit tests for tf_inspect."""
16
17# pylint: disable=unused-import
18from __future__ import absolute_import
19from __future__ import division
20from __future__ import print_function
21
22import functools
23import inspect
24
25from tensorflow.python.platform import test
26from tensorflow.python.platform import tf_logging as logging
27from tensorflow.python.util import tf_decorator
28from tensorflow.python.util import tf_inspect
29
30
31def test_decorator(decorator_name, decorator_doc=None):
32
33  def make_tf_decorator(target):
34    return tf_decorator.TFDecorator(decorator_name, target, decorator_doc)
35
36  return make_tf_decorator
37
38
39def test_undecorated_function():
40  pass
41
42
43@test_decorator('decorator 1')
44@test_decorator('decorator 2')
45@test_decorator('decorator 3')
46def test_decorated_function(x):
47  """Test Decorated Function Docstring."""
48  return x * 2
49
50
51@test_decorator('decorator')
52def test_decorated_function_with_defaults(a, b=2, c='Hello'):
53  """Test Decorated Function With Defaults Docstring."""
54  return [a, b, c]
55
56
57@test_decorator('decorator')
58class TestDecoratedClass(object):
59  """Test Decorated Class."""
60
61  def __init__(self):
62    pass
63
64  def two(self):
65    return 2
66
67
68class TfInspectTest(test.TestCase):
69
70  def testCurrentFrame(self):
71    self.assertEqual(inspect.currentframe(), tf_inspect.currentframe())
72
73  def testGetArgSpecOnDecoratorsThatDontProvideArgspec(self):
74    argspec = tf_inspect.getargspec(test_decorated_function_with_defaults)
75    self.assertEqual(['a', 'b', 'c'], argspec.args)
76    self.assertEqual((2, 'Hello'), argspec.defaults)
77
78  def testGetArgSpecOnDecoratorThatChangesArgspec(self):
79    argspec = tf_inspect.ArgSpec(
80        args=['a', 'b', 'c'],
81        varargs=None,
82        keywords=None,
83        defaults=(1, 'hello'))
84
85    decorator = tf_decorator.TFDecorator('', test_undecorated_function, '',
86                                         argspec)
87    self.assertEqual(argspec, tf_inspect.getargspec(decorator))
88
89  def testGetArgSpecIgnoresDecoratorsThatDontProvideArgspec(self):
90    argspec = tf_inspect.ArgSpec(
91        args=['a', 'b', 'c'],
92        varargs=None,
93        keywords=None,
94        defaults=(1, 'hello'))
95
96    inner_decorator = tf_decorator.TFDecorator('', test_undecorated_function,
97                                               '', argspec)
98    outer_decorator = tf_decorator.TFDecorator('', inner_decorator)
99    self.assertEqual(argspec, tf_inspect.getargspec(outer_decorator))
100
101  def testGetArgSpecReturnsOutermostDecoratorThatChangesArgspec(self):
102    outer_argspec = tf_inspect.ArgSpec(
103        args=['a'], varargs=None, keywords=None, defaults=None)
104    inner_argspec = tf_inspect.ArgSpec(
105        args=['b'], varargs=None, keywords=None, defaults=None)
106
107    inner_decorator = tf_decorator.TFDecorator('', test_undecorated_function,
108                                               '', inner_argspec)
109    outer_decorator = tf_decorator.TFDecorator('', inner_decorator, '',
110                                               outer_argspec)
111    self.assertEqual(outer_argspec, tf_inspect.getargspec(outer_decorator))
112
113  def testGetArgSpecOnPartialPositionalArgumentOnly(self):
114    """Tests getargspec on partial function with only positional arguments."""
115
116    def func(m, n):
117      return 2 * m + n
118
119    partial_func = functools.partial(func, 7)
120    argspec = tf_inspect.ArgSpec(
121        args=['n'], varargs=None, keywords=None, defaults=None)
122
123    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
124
125  def testGetArgSpecOnPartialArgumentWithConvertibleToFalse(self):
126    """Tests getargspec on partial function with args that convert to False."""
127
128    def func(m, n):
129      return 2 * m + n
130
131    partial_func = functools.partial(func, m=0)
132
133    exception_message = (r"Some arguments \['n'\] do not have default value, "
134                         "but they are positioned after those with default "
135                         "values. This can not be expressed with ArgSpec.")
136    with self.assertRaisesRegex(ValueError, exception_message):
137      tf_inspect.getargspec(partial_func)
138
139  def testGetArgSpecOnPartialInvalidArgspec(self):
140    """Tests getargspec on partial function that doesn't have valid argspec."""
141
142    def func(m, n, l, k=4):
143      return 2 * m + l + n * k
144
145    partial_func = functools.partial(func, n=7)
146
147    exception_message = (r"Some arguments \['l'\] do not have default value, "
148                         "but they are positioned after those with default "
149                         "values. This can not be expressed with ArgSpec.")
150    with self.assertRaisesRegex(ValueError, exception_message):
151      tf_inspect.getargspec(partial_func)
152
153  def testGetArgSpecOnPartialValidArgspec(self):
154    """Tests getargspec on partial function with valid argspec."""
155
156    def func(m, n, l, k=4):
157      return 2 * m + l + n * k
158
159    partial_func = functools.partial(func, n=7, l=2)
160    argspec = tf_inspect.ArgSpec(
161        args=['m', 'n', 'l', 'k'],
162        varargs=None,
163        keywords=None,
164        defaults=(7, 2, 4))
165
166    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
167
168  def testGetArgSpecOnPartialNoArgumentsLeft(self):
169    """Tests getargspec on partial function that prunes all arguments."""
170
171    def func(m, n):
172      return 2 * m + n
173
174    partial_func = functools.partial(func, 7, 10)
175    argspec = tf_inspect.ArgSpec(
176        args=[], varargs=None, keywords=None, defaults=None)
177
178    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
179
180  def testGetArgSpecOnPartialKeywordArgument(self):
181    """Tests getargspec on partial function that prunes some arguments."""
182
183    def func(m, n):
184      return 2 * m + n
185
186    partial_func = functools.partial(func, n=7)
187    argspec = tf_inspect.ArgSpec(
188        args=['m', 'n'], varargs=None, keywords=None, defaults=(7,))
189
190    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
191
192  def testGetArgSpecOnPartialKeywordArgumentWithDefaultValue(self):
193    """Tests getargspec on partial function that prunes argument by keyword."""
194
195    def func(m=1, n=2):
196      return 2 * m + n
197
198    partial_func = functools.partial(func, n=7)
199    argspec = tf_inspect.ArgSpec(
200        args=['m', 'n'], varargs=None, keywords=None, defaults=(1, 7))
201
202    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
203
204  def testGetArgSpecOnPartialWithVarargs(self):
205    """Tests getargspec on partial function with variable arguments."""
206
207    def func(m, *arg):
208      return m + len(arg)
209
210    partial_func = functools.partial(func, 7, 8)
211    argspec = tf_inspect.ArgSpec(
212        args=[], varargs='arg', keywords=None, defaults=None)
213
214    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
215
216  def testGetArgSpecOnPartialWithVarkwargs(self):
217    """Tests getargspec on partial function with variable keyword arguments."""
218
219    def func(m, n, **kwarg):
220      return m * n + len(kwarg)
221
222    partial_func = functools.partial(func, 7)
223    argspec = tf_inspect.ArgSpec(
224        args=['n'], varargs=None, keywords='kwarg', defaults=None)
225
226    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
227
228  def testGetArgSpecOnPartialWithDecorator(self):
229    """Tests getargspec on decorated partial function."""
230
231    @test_decorator('decorator')
232    def func(m=1, n=2):
233      return 2 * m + n
234
235    partial_func = functools.partial(func, n=7)
236    argspec = tf_inspect.ArgSpec(
237        args=['m', 'n'], varargs=None, keywords=None, defaults=(1, 7))
238
239    self.assertEqual(argspec, tf_inspect.getargspec(partial_func))
240
241  def testGetArgSpecOnPartialWithDecoratorThatChangesArgspec(self):
242    """Tests getargspec on partial function with decorated argspec."""
243
244    argspec = tf_inspect.ArgSpec(
245        args=['a', 'b', 'c'],
246        varargs=None,
247        keywords=None,
248        defaults=(1, 'hello'))
249    decorator = tf_decorator.TFDecorator('', test_undecorated_function, '',
250                                         argspec)
251    partial_argspec = tf_inspect.ArgSpec(
252        args=['a', 'b', 'c'],
253        varargs=None,
254        keywords=None,
255        defaults=(2, 1, 'hello'))
256    partial_with_decorator = functools.partial(decorator, a=2)
257
258    self.assertEqual(argspec, tf_inspect.getargspec(decorator))
259    self.assertEqual(partial_argspec,
260                     tf_inspect.getargspec(partial_with_decorator))
261
262  def testGetArgSpecOnCallableObject(self):
263
264    class Callable(object):
265
266      def __call__(self, a, b=1, c='hello'):
267        pass
268
269    argspec = tf_inspect.ArgSpec(
270        args=['self', 'a', 'b', 'c'],
271        varargs=None,
272        keywords=None,
273        defaults=(1, 'hello'))
274
275    test_obj = Callable()
276    self.assertEqual(argspec, tf_inspect.getargspec(test_obj))
277
278  def testGetArgSpecOnInitClass(self):
279
280    class InitClass(object):
281
282      def __init__(self, a, b=1, c='hello'):
283        pass
284
285    argspec = tf_inspect.ArgSpec(
286        args=['self', 'a', 'b', 'c'],
287        varargs=None,
288        keywords=None,
289        defaults=(1, 'hello'))
290
291    self.assertEqual(argspec, tf_inspect.getargspec(InitClass))
292
293  def testGetArgSpecOnNewClass(self):
294
295    class NewClass(object):
296
297      def __new__(cls, a, b=1, c='hello'):
298        pass
299
300    argspec = tf_inspect.ArgSpec(
301        args=['cls', 'a', 'b', 'c'],
302        varargs=None,
303        keywords=None,
304        defaults=(1, 'hello'))
305
306    self.assertEqual(argspec, tf_inspect.getargspec(NewClass))
307
308  def testGetFullArgSpecOnDecoratorsThatDontProvideFullArgSpec(self):
309    argspec = tf_inspect.getfullargspec(test_decorated_function_with_defaults)
310    self.assertEqual(['a', 'b', 'c'], argspec.args)
311    self.assertEqual((2, 'Hello'), argspec.defaults)
312
313  def testGetFullArgSpecOnDecoratorThatChangesFullArgSpec(self):
314    argspec = tf_inspect.FullArgSpec(
315        args=['a', 'b', 'c'],
316        varargs=None,
317        varkw=None,
318        defaults=(1, 'hello'),
319        kwonlyargs=[],
320        kwonlydefaults=None,
321        annotations={})
322
323    decorator = tf_decorator.TFDecorator('', test_undecorated_function, '',
324                                         argspec)
325    self.assertEqual(argspec, tf_inspect.getfullargspec(decorator))
326
327  def testGetFullArgSpecIgnoresDecoratorsThatDontProvideFullArgSpec(self):
328    argspec = tf_inspect.FullArgSpec(
329        args=['a', 'b', 'c'],
330        varargs=None,
331        varkw=None,
332        defaults=(1, 'hello'),
333        kwonlyargs=[],
334        kwonlydefaults=None,
335        annotations={})
336
337    inner_decorator = tf_decorator.TFDecorator('', test_undecorated_function,
338                                               '', argspec)
339    outer_decorator = tf_decorator.TFDecorator('', inner_decorator)
340    self.assertEqual(argspec, tf_inspect.getfullargspec(outer_decorator))
341
342  def testGetFullArgSpecReturnsOutermostDecoratorThatChangesFullArgSpec(self):
343    outer_argspec = tf_inspect.FullArgSpec(
344        args=['a'],
345        varargs=None,
346        varkw=None,
347        defaults=None,
348        kwonlyargs=[],
349        kwonlydefaults=None,
350        annotations={})
351    inner_argspec = tf_inspect.FullArgSpec(
352        args=['b'],
353        varargs=None,
354        varkw=None,
355        defaults=None,
356        kwonlyargs=[],
357        kwonlydefaults=None,
358        annotations={})
359
360    inner_decorator = tf_decorator.TFDecorator('', test_undecorated_function,
361                                               '', inner_argspec)
362    outer_decorator = tf_decorator.TFDecorator('', inner_decorator, '',
363                                               outer_argspec)
364    self.assertEqual(outer_argspec, tf_inspect.getfullargspec(outer_decorator))
365
366  def testGetFullArgsSpecForPartial(self):
367
368    def func(a, b):
369      del a, b
370
371    partial_function = functools.partial(func, 1)
372    argspec = tf_inspect.FullArgSpec(
373        args=['b'],
374        varargs=None,
375        varkw=None,
376        defaults=None,
377        kwonlyargs=[],
378        kwonlydefaults=None,
379        annotations={})
380
381    self.assertEqual(argspec, tf_inspect.getfullargspec(partial_function))
382
383  def testGetFullArgSpecOnPartialNoArgumentsLeft(self):
384    """Tests getfullargspec on partial function that prunes all arguments."""
385
386    def func(m, n):
387      return 2 * m + n
388
389    partial_func = functools.partial(func, 7, 10)
390    argspec = tf_inspect.FullArgSpec(
391        args=[],
392        varargs=None,
393        varkw=None,
394        defaults=None,
395        kwonlyargs=[],
396        kwonlydefaults=None,
397        annotations={})
398
399    self.assertEqual(argspec, tf_inspect.getfullargspec(partial_func))
400
401  def testGetFullArgSpecOnPartialWithVarargs(self):
402    """Tests getfullargspec on partial function with variable arguments."""
403
404    def func(m, *arg):
405      return m + len(arg)
406
407    partial_func = functools.partial(func, 7, 8)
408    argspec = tf_inspect.FullArgSpec(
409        args=[],
410        varargs='arg',
411        varkw=None,
412        defaults=None,
413        kwonlyargs=[],
414        kwonlydefaults=None,
415        annotations={})
416
417    self.assertEqual(argspec, tf_inspect.getfullargspec(partial_func))
418
419  def testGetFullArgSpecOnPartialWithVarkwargs(self):
420    """Tests getfullargspec.
421
422    Tests on partial function with variable keyword arguments.
423    """
424
425    def func(m, n, **kwarg):
426      return m * n + len(kwarg)
427
428    partial_func = functools.partial(func, 7)
429    argspec = tf_inspect.FullArgSpec(
430        args=['n'],
431        varargs=None,
432        varkw='kwarg',
433        defaults=None,
434        kwonlyargs=[],
435        kwonlydefaults=None,
436        annotations={})
437
438    self.assertEqual(argspec, tf_inspect.getfullargspec(partial_func))
439
440  def testGetFullArgSpecOnCallableObject(self):
441
442    class Callable(object):
443
444      def __call__(self, a, b=1, c='hello'):
445        pass
446
447    argspec = tf_inspect.FullArgSpec(
448        args=['self', 'a', 'b', 'c'],
449        varargs=None,
450        varkw=None,
451        defaults=(1, 'hello'),
452        kwonlyargs=[],
453        kwonlydefaults=None,
454        annotations={})
455
456    test_obj = Callable()
457    self.assertEqual(argspec, tf_inspect.getfullargspec(test_obj))
458
459  def testGetFullArgSpecOnInitClass(self):
460
461    class InitClass(object):
462
463      def __init__(self, a, b=1, c='hello'):
464        pass
465
466    argspec = tf_inspect.FullArgSpec(
467        args=['self', 'a', 'b', 'c'],
468        varargs=None,
469        varkw=None,
470        defaults=(1, 'hello'),
471        kwonlyargs=[],
472        kwonlydefaults=None,
473        annotations={})
474
475    self.assertEqual(argspec, tf_inspect.getfullargspec(InitClass))
476
477  def testGetFullArgSpecOnNewClass(self):
478
479    class NewClass(object):
480
481      def __new__(cls, a, b=1, c='hello'):
482        pass
483
484    argspec = tf_inspect.FullArgSpec(
485        args=['cls', 'a', 'b', 'c'],
486        varargs=None,
487        varkw=None,
488        defaults=(1, 'hello'),
489        kwonlyargs=[],
490        kwonlydefaults=None,
491        annotations={})
492
493    self.assertEqual(argspec, tf_inspect.getfullargspec(NewClass))
494
495  def testSignatureOnDecoratorsThatDontProvideFullArgSpec(self):
496    signature = tf_inspect.signature(test_decorated_function_with_defaults)
497
498    self.assertEqual([
499        tf_inspect.Parameter('a', tf_inspect.Parameter.POSITIONAL_OR_KEYWORD),
500        tf_inspect.Parameter(
501            'b', tf_inspect.Parameter.POSITIONAL_OR_KEYWORD, default=2),
502        tf_inspect.Parameter(
503            'c', tf_inspect.Parameter.POSITIONAL_OR_KEYWORD, default='Hello')
504    ], list(signature.parameters.values()))
505
506  def testSignatureFollowsNestedDecorators(self):
507    signature = tf_inspect.signature(test_decorated_function)
508
509    self.assertEqual(
510        [tf_inspect.Parameter('x', tf_inspect.Parameter.POSITIONAL_OR_KEYWORD)],
511        list(signature.parameters.values()))
512
513  def testGetDoc(self):
514    self.assertEqual('Test Decorated Function With Defaults Docstring.',
515                     tf_inspect.getdoc(test_decorated_function_with_defaults))
516
517  def testGetFile(self):
518    self.assertTrue('tf_inspect_test.py' in tf_inspect.getfile(
519        test_decorated_function_with_defaults))
520    self.assertTrue('tf_decorator.py' in tf_inspect.getfile(
521        test_decorator('decorator')(tf_decorator.unwrap)))
522
523  def testGetMembers(self):
524    self.assertEqual(
525        inspect.getmembers(TestDecoratedClass),
526        tf_inspect.getmembers(TestDecoratedClass))
527
528  def testGetModule(self):
529    self.assertEqual(
530        inspect.getmodule(TestDecoratedClass),
531        tf_inspect.getmodule(TestDecoratedClass))
532    self.assertEqual(
533        inspect.getmodule(test_decorated_function),
534        tf_inspect.getmodule(test_decorated_function))
535    self.assertEqual(
536        inspect.getmodule(test_undecorated_function),
537        tf_inspect.getmodule(test_undecorated_function))
538
539  def testGetSource(self):
540    expected = '''@test_decorator('decorator')
541def test_decorated_function_with_defaults(a, b=2, c='Hello'):
542  """Test Decorated Function With Defaults Docstring."""
543  return [a, b, c]
544'''
545    self.assertEqual(
546        expected, tf_inspect.getsource(test_decorated_function_with_defaults))
547
548  def testGetSourceFile(self):
549    self.assertEqual(
550        __file__,
551        tf_inspect.getsourcefile(test_decorated_function_with_defaults))
552
553  def testGetSourceLines(self):
554    expected = inspect.getsourcelines(
555        test_decorated_function_with_defaults.decorated_target)
556    self.assertEqual(
557        expected,
558        tf_inspect.getsourcelines(test_decorated_function_with_defaults))
559
560  def testIsBuiltin(self):
561    self.assertEqual(
562        tf_inspect.isbuiltin(TestDecoratedClass),
563        inspect.isbuiltin(TestDecoratedClass))
564    self.assertEqual(
565        tf_inspect.isbuiltin(test_decorated_function),
566        inspect.isbuiltin(test_decorated_function))
567    self.assertEqual(
568        tf_inspect.isbuiltin(test_undecorated_function),
569        inspect.isbuiltin(test_undecorated_function))
570    self.assertEqual(tf_inspect.isbuiltin(range), inspect.isbuiltin(range))
571    self.assertEqual(tf_inspect.isbuiltin(max), inspect.isbuiltin(max))
572
573  def testIsClass(self):
574    self.assertTrue(tf_inspect.isclass(TestDecoratedClass))
575    self.assertFalse(tf_inspect.isclass(test_decorated_function))
576
577  def testIsFunction(self):
578    self.assertTrue(tf_inspect.isfunction(test_decorated_function))
579    self.assertFalse(tf_inspect.isfunction(TestDecoratedClass))
580
581  def testIsMethod(self):
582    self.assertTrue(tf_inspect.ismethod(TestDecoratedClass().two))
583    self.assertFalse(tf_inspect.ismethod(test_decorated_function))
584
585  def testIsModule(self):
586    self.assertTrue(
587        tf_inspect.ismodule(inspect.getmodule(inspect.currentframe())))
588    self.assertFalse(tf_inspect.ismodule(test_decorated_function))
589
590  def testIsRoutine(self):
591    self.assertTrue(tf_inspect.isroutine(len))
592    self.assertFalse(tf_inspect.isroutine(TestDecoratedClass))
593
594  def testStack(self):
595    expected_stack = inspect.stack()
596    actual_stack = tf_inspect.stack()
597    self.assertEqual(len(expected_stack), len(actual_stack))
598    self.assertEqual(expected_stack[0][0], actual_stack[0][0])  # Frame object
599    self.assertEqual(expected_stack[0][1], actual_stack[0][1])  # Filename
600    self.assertEqual(expected_stack[0][2],
601                     actual_stack[0][2] - 1)  # Line number
602    self.assertEqual(expected_stack[0][3], actual_stack[0][3])  # Function name
603    self.assertEqual(expected_stack[1:], actual_stack[1:])
604
605
606class TfInspectGetCallArgsTest(test.TestCase):
607
608  def testReturnsEmptyWhenUnboundFuncHasNoParameters(self):
609
610    def empty():
611      pass
612
613    self.assertEqual({}, tf_inspect.getcallargs(empty))
614
615  def testClashingParameterNames(self):
616
617    def func(positional, func=1, func_and_positional=2, kwargs=3):
618      return positional, func, func_and_positional, kwargs
619
620    kwargs = {}
621    self.assertEqual(
622        tf_inspect.getcallargs(func, 0, **kwargs), {
623            'positional': 0,
624            'func': 1,
625            'func_and_positional': 2,
626            'kwargs': 3
627        })
628    kwargs = dict(func=4, func_and_positional=5, kwargs=6)
629    self.assertEqual(
630        tf_inspect.getcallargs(func, 0, **kwargs), {
631            'positional': 0,
632            'func': 4,
633            'func_and_positional': 5,
634            'kwargs': 6
635        })
636
637  def testUnboundFuncWithOneParamPositional(self):
638
639    def func(a):
640      return a
641
642    self.assertEqual({'a': 5}, tf_inspect.getcallargs(func, 5))
643
644  def testUnboundFuncWithTwoParamsPositional(self):
645
646    def func(a, b):
647      return (a, b)
648
649    self.assertEqual({'a': 10, 'b': 20}, tf_inspect.getcallargs(func, 10, 20))
650
651  def testUnboundFuncWithOneParamKeyword(self):
652
653    def func(a):
654      return a
655
656    self.assertEqual({'a': 5}, tf_inspect.getcallargs(func, a=5))
657
658  def testUnboundFuncWithTwoParamsKeyword(self):
659
660    def func(a, b):
661      return (a, b)
662
663    self.assertEqual({'a': 6, 'b': 7}, tf_inspect.getcallargs(func, a=6, b=7))
664
665  def testUnboundFuncWithOneParamDefault(self):
666
667    def func(a=13):
668      return a
669
670    self.assertEqual({'a': 13}, tf_inspect.getcallargs(func))
671
672  def testUnboundFuncWithOneParamDefaultOnePositional(self):
673
674    def func(a=0):
675      return a
676
677    self.assertEqual({'a': 1}, tf_inspect.getcallargs(func, 1))
678
679  def testUnboundFuncWithTwoParamsDefaultOnePositional(self):
680
681    def func(a=1, b=2):
682      return (a, b)
683
684    self.assertEqual({'a': 5, 'b': 2}, tf_inspect.getcallargs(func, 5))
685
686  def testUnboundFuncWithTwoParamsDefaultTwoPositional(self):
687
688    def func(a=1, b=2):
689      return (a, b)
690
691    self.assertEqual({'a': 3, 'b': 4}, tf_inspect.getcallargs(func, 3, 4))
692
693  def testUnboundFuncWithOneParamDefaultOneKeyword(self):
694
695    def func(a=1):
696      return a
697
698    self.assertEqual({'a': 3}, tf_inspect.getcallargs(func, a=3))
699
700  def testUnboundFuncWithTwoParamsDefaultOneKeywordFirst(self):
701
702    def func(a=1, b=2):
703      return (a, b)
704
705    self.assertEqual({'a': 3, 'b': 2}, tf_inspect.getcallargs(func, a=3))
706
707  def testUnboundFuncWithTwoParamsDefaultOneKeywordSecond(self):
708
709    def func(a=1, b=2):
710      return (a, b)
711
712    self.assertEqual({'a': 1, 'b': 4}, tf_inspect.getcallargs(func, b=4))
713
714  def testUnboundFuncWithTwoParamsDefaultTwoKeywords(self):
715
716    def func(a=1, b=2):
717      return (a, b)
718
719    self.assertEqual({'a': 3, 'b': 4}, tf_inspect.getcallargs(func, a=3, b=4))
720
721  def testBoundFuncWithOneParam(self):
722
723    class Test(object):
724
725      def bound(self):
726        pass
727
728    t = Test()
729    self.assertEqual({'self': t}, tf_inspect.getcallargs(t.bound))
730
731  def testBoundFuncWithManyParamsAndDefaults(self):
732
733    class Test(object):
734
735      def bound(self, a, b=2, c='Hello'):
736        return (a, b, c)
737
738    t = Test()
739    self.assertEqual({
740        'self': t,
741        'a': 3,
742        'b': 2,
743        'c': 'Goodbye'
744    }, tf_inspect.getcallargs(t.bound, 3, c='Goodbye'))
745
746  def testClassMethod(self):
747
748    class Test(object):
749
750      @classmethod
751      def test(cls, a, b=3, c='hello'):
752        return (a, b, c)
753
754    self.assertEqual({
755        'cls': Test,
756        'a': 5,
757        'b': 3,
758        'c': 'goodbye'
759    }, tf_inspect.getcallargs(Test.test, 5, c='goodbye'))
760
761  def testUsesOutermostDecoratorsArgSpec(self):
762
763    def func():
764      pass
765
766    def wrapper(*args, **kwargs):
767      return func(*args, **kwargs)
768
769    decorated = tf_decorator.make_decorator(
770        func,
771        wrapper,
772        decorator_argspec=tf_inspect.ArgSpec(
773            args=['a', 'b', 'c'],
774            varargs=None,
775            keywords=None,
776            defaults=(3, 'hello')))
777
778    self.assertEqual({
779        'a': 4,
780        'b': 3,
781        'c': 'goodbye'
782    }, tf_inspect.getcallargs(decorated, 4, c='goodbye'))
783
784
785if __name__ == '__main__':
786  test.main()
787