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 18 from __future__ import absolute_import 19 from __future__ import division 20 from __future__ import print_function 21 22 import inspect 23 24 from tensorflow.python.platform import test 25 from tensorflow.python.platform import tf_logging as logging 26 from tensorflow.python.util import tf_decorator 27 from tensorflow.python.util import tf_inspect 28 29 30 def test_decorator(decorator_name, decorator_doc=None): 31 32 def make_tf_decorator(target): 33 return tf_decorator.TFDecorator(decorator_name, target, decorator_doc) 34 35 return make_tf_decorator 36 37 38 def test_undecorated_function(): 39 pass 40 41 42 @test_decorator('decorator 1') 43 @test_decorator('decorator 2') 44 @test_decorator('decorator 3') 45 def test_decorated_function(x): 46 """Test Decorated Function Docstring.""" 47 return x * 2 48 49 50 @test_decorator('decorator') 51 def test_decorated_function_with_defaults(a, b=2, c='Hello'): 52 """Test Decorated Function With Defaults Docstring.""" 53 return [a, b, c] 54 55 56 @test_decorator('decorator') 57 class TestDecoratedClass(object): 58 """Test Decorated Class.""" 59 60 def __init__(self): 61 pass 62 63 def two(self): 64 return 2 65 66 67 class TfInspectTest(test.TestCase): 68 69 def testCurrentFrame(self): 70 self.assertEqual(inspect.currentframe(), tf_inspect.currentframe()) 71 72 def testGetArgSpecOnDecoratorsThatDontProvideArgspec(self): 73 argspec = tf_inspect.getargspec(test_decorated_function_with_defaults) 74 self.assertEqual(['a', 'b', 'c'], argspec.args) 75 self.assertEqual((2, 'Hello'), argspec.defaults) 76 77 def testGetArgSpecOnDecoratorThatChangesArgspec(self): 78 argspec = tf_inspect.ArgSpec( 79 args=['a', 'b', 'c'], 80 varargs=None, 81 keywords=None, 82 defaults=(1, 'hello')) 83 84 decorator = tf_decorator.TFDecorator('', test_undecorated_function, '', 85 argspec) 86 self.assertEqual(argspec, tf_inspect.getargspec(decorator)) 87 88 def testGetArgSpecIgnoresDecoratorsThatDontProvideArgspec(self): 89 argspec = tf_inspect.ArgSpec( 90 args=['a', 'b', 'c'], 91 varargs=None, 92 keywords=None, 93 defaults=(1, 'hello')) 94 95 inner_decorator = tf_decorator.TFDecorator('', test_undecorated_function, 96 '', argspec) 97 outer_decorator = tf_decorator.TFDecorator('', inner_decorator) 98 self.assertEqual(argspec, tf_inspect.getargspec(outer_decorator)) 99 100 def testGetArgSpecReturnsOutermostDecoratorThatChangesArgspec(self): 101 outer_argspec = tf_inspect.ArgSpec( 102 args=['a'], varargs=None, keywords=None, defaults=None) 103 inner_argspec = tf_inspect.ArgSpec( 104 args=['b'], varargs=None, keywords=None, defaults=None) 105 106 inner_decorator = tf_decorator.TFDecorator('', test_undecorated_function, 107 '', inner_argspec) 108 outer_decorator = tf_decorator.TFDecorator('', inner_decorator, '', 109 outer_argspec) 110 self.assertEqual(outer_argspec, tf_inspect.getargspec(outer_decorator)) 111 112 def testGetDoc(self): 113 self.assertEqual('Test Decorated Function With Defaults Docstring.', 114 tf_inspect.getdoc(test_decorated_function_with_defaults)) 115 116 def testGetFile(self): 117 self.assertTrue('tf_inspect_test.py' in tf_inspect.getfile( 118 test_decorated_function_with_defaults)) 119 self.assertTrue('tf_decorator.py' in tf_inspect.getfile( 120 test_decorator('decorator')(tf_decorator.unwrap))) 121 122 def testGetMembers(self): 123 self.assertEqual( 124 inspect.getmembers(TestDecoratedClass), 125 tf_inspect.getmembers(TestDecoratedClass)) 126 127 def testGetModule(self): 128 self.assertEqual( 129 inspect.getmodule(TestDecoratedClass), 130 tf_inspect.getmodule(TestDecoratedClass)) 131 self.assertEqual( 132 inspect.getmodule(test_decorated_function), 133 tf_inspect.getmodule(test_decorated_function)) 134 self.assertEqual( 135 inspect.getmodule(test_undecorated_function), 136 tf_inspect.getmodule(test_undecorated_function)) 137 138 def testGetSource(self): 139 expected = '''@test_decorator('decorator') 140 def test_decorated_function_with_defaults(a, b=2, c='Hello'): 141 """Test Decorated Function With Defaults Docstring.""" 142 return [a, b, c] 143 ''' 144 self.assertEqual( 145 expected, tf_inspect.getsource(test_decorated_function_with_defaults)) 146 147 def testIsClass(self): 148 self.assertTrue(tf_inspect.isclass(TestDecoratedClass)) 149 self.assertFalse(tf_inspect.isclass(test_decorated_function)) 150 151 def testIsFunction(self): 152 self.assertTrue(tf_inspect.isfunction(test_decorated_function)) 153 self.assertFalse(tf_inspect.isfunction(TestDecoratedClass)) 154 155 def testIsMethod(self): 156 self.assertTrue(tf_inspect.ismethod(TestDecoratedClass().two)) 157 self.assertFalse(tf_inspect.ismethod(test_decorated_function)) 158 159 def testIsModule(self): 160 self.assertTrue( 161 tf_inspect.ismodule(inspect.getmodule(inspect.currentframe()))) 162 self.assertFalse(tf_inspect.ismodule(test_decorated_function)) 163 164 def testIsRoutine(self): 165 self.assertTrue(tf_inspect.isroutine(len)) 166 self.assertFalse(tf_inspect.isroutine(TestDecoratedClass)) 167 168 def testStack(self): 169 expected_stack = inspect.stack() 170 actual_stack = tf_inspect.stack() 171 self.assertEqual(len(expected_stack), len(actual_stack)) 172 self.assertEqual(expected_stack[0][0], actual_stack[0][0]) # Frame object 173 self.assertEqual(expected_stack[0][1], actual_stack[0][1]) # Filename 174 self.assertEqual(expected_stack[0][2], 175 actual_stack[0][2] - 1) # Line number 176 self.assertEqual(expected_stack[0][3], actual_stack[0][3]) # Function name 177 self.assertEqual(expected_stack[1:], actual_stack[1:]) 178 179 180 class TfInspectGetCallArgsTest(test.TestCase): 181 182 def testReturnsEmptyWhenUnboundFuncHasNoParameters(self): 183 184 def empty(): 185 pass 186 187 self.assertEqual({}, tf_inspect.getcallargs(empty)) 188 189 def testUnboundFuncWithOneParamPositional(self): 190 191 def func(a): 192 return a 193 194 self.assertEqual({'a': 5}, tf_inspect.getcallargs(func, 5)) 195 196 def testUnboundFuncWithTwoParamsPositional(self): 197 198 def func(a, b): 199 return (a, b) 200 201 self.assertEqual({'a': 10, 'b': 20}, tf_inspect.getcallargs(func, 10, 20)) 202 203 def testUnboundFuncWithOneParamKeyword(self): 204 205 def func(a): 206 return a 207 208 self.assertEqual({'a': 5}, tf_inspect.getcallargs(func, a=5)) 209 210 def testUnboundFuncWithTwoParamsKeyword(self): 211 212 def func(a, b): 213 return (a, b) 214 215 self.assertEqual({'a': 6, 'b': 7}, tf_inspect.getcallargs(func, a=6, b=7)) 216 217 def testUnboundFuncWithOneParamDefault(self): 218 219 def func(a=13): 220 return a 221 222 self.assertEqual({'a': 13}, tf_inspect.getcallargs(func)) 223 224 def testUnboundFuncWithOneParamDefaultOnePositional(self): 225 226 def func(a=0): 227 return a 228 229 self.assertEqual({'a': 1}, tf_inspect.getcallargs(func, 1)) 230 231 def testUnboundFuncWithTwoParamsDefaultOnePositional(self): 232 233 def func(a=1, b=2): 234 return (a, b) 235 236 self.assertEqual({'a': 5, 'b': 2}, tf_inspect.getcallargs(func, 5)) 237 238 def testUnboundFuncWithTwoParamsDefaultTwoPositional(self): 239 240 def func(a=1, b=2): 241 return (a, b) 242 243 self.assertEqual({'a': 3, 'b': 4}, tf_inspect.getcallargs(func, 3, 4)) 244 245 def testUnboundFuncWithOneParamDefaultOneKeyword(self): 246 247 def func(a=1): 248 return a 249 250 self.assertEqual({'a': 3}, tf_inspect.getcallargs(func, a=3)) 251 252 def testUnboundFuncWithTwoParamsDefaultOneKeywordFirst(self): 253 254 def func(a=1, b=2): 255 return (a, b) 256 257 self.assertEqual({'a': 3, 'b': 2}, tf_inspect.getcallargs(func, a=3)) 258 259 def testUnboundFuncWithTwoParamsDefaultOneKeywordSecond(self): 260 261 def func(a=1, b=2): 262 return (a, b) 263 264 self.assertEqual({'a': 1, 'b': 4}, tf_inspect.getcallargs(func, b=4)) 265 266 def testUnboundFuncWithTwoParamsDefaultTwoKeywords(self): 267 268 def func(a=1, b=2): 269 return (a, b) 270 271 self.assertEqual({'a': 3, 'b': 4}, tf_inspect.getcallargs(func, a=3, b=4)) 272 273 def testBoundFuncWithOneParam(self): 274 275 class Test(object): 276 277 def bound(self): 278 pass 279 280 t = Test() 281 self.assertEqual({'self': t}, tf_inspect.getcallargs(t.bound)) 282 283 def testBoundFuncWithManyParamsAndDefaults(self): 284 285 class Test(object): 286 287 def bound(self, a, b=2, c='Hello'): 288 return (a, b, c) 289 290 t = Test() 291 self.assertEqual({ 292 'self': t, 293 'a': 3, 294 'b': 2, 295 'c': 'Goodbye' 296 }, tf_inspect.getcallargs(t.bound, 3, c='Goodbye')) 297 298 def testClassMethod(self): 299 300 class Test(object): 301 302 @classmethod 303 def test(cls, a, b=3, c='hello'): 304 return (a, b, c) 305 306 self.assertEqual({ 307 'cls': Test, 308 'a': 5, 309 'b': 3, 310 'c': 'goodbye' 311 }, tf_inspect.getcallargs(Test.test, 5, c='goodbye')) 312 313 def testUsesOutermostDecoratorsArgSpec(self): 314 315 def func(): 316 pass 317 318 def wrapper(*args, **kwargs): 319 return func(*args, **kwargs) 320 321 decorated = tf_decorator.make_decorator( 322 func, 323 wrapper, 324 decorator_argspec=tf_inspect.ArgSpec( 325 args=['a', 'b', 'c'], 326 varargs=None, 327 keywords=None, 328 defaults=(3, 'hello'))) 329 330 self.assertEqual({ 331 'a': 4, 332 'b': 3, 333 'c': 'goodbye' 334 }, tf_inspect.getcallargs(decorated, 4, c='goodbye')) 335 336 337 if __name__ == '__main__': 338 test.main() 339