Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/keras/src/utils/tf_inspect.py: 34%
136 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
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"""TFDecorator-aware replacements for the inspect module."""
16import collections
17import functools
18import inspect as _inspect
20import tensorflow.compat.v2 as tf
22if hasattr(_inspect, "ArgSpec"):
23 ArgSpec = _inspect.ArgSpec
24else:
25 ArgSpec = collections.namedtuple(
26 "ArgSpec",
27 [
28 "args",
29 "varargs",
30 "keywords",
31 "defaults",
32 ],
33 )
35if hasattr(_inspect, "FullArgSpec"):
36 FullArgSpec = _inspect.FullArgSpec
37else:
38 FullArgSpec = collections.namedtuple(
39 "FullArgSpec",
40 [
41 "args",
42 "varargs",
43 "varkw",
44 "defaults",
45 "kwonlyargs",
46 "kwonlydefaults",
47 "annotations",
48 ],
49 )
52def _convert_maybe_argspec_to_fullargspec(argspec):
53 if isinstance(argspec, FullArgSpec):
54 return argspec
55 return FullArgSpec(
56 args=argspec.args,
57 varargs=argspec.varargs,
58 varkw=argspec.keywords,
59 defaults=argspec.defaults,
60 kwonlyargs=[],
61 kwonlydefaults=None,
62 annotations={},
63 )
66if hasattr(_inspect, "getfullargspec"):
67 _getfullargspec = _inspect.getfullargspec
69 def _getargspec(target):
70 """A python3 version of getargspec.
72 Calls `getfullargspec` and assigns args, varargs,
73 varkw, and defaults to a python 2/3 compatible `ArgSpec`.
75 The parameter name 'varkw' is changed to 'keywords' to fit the
76 `ArgSpec` struct.
78 Args:
79 target: the target object to inspect.
81 Returns:
82 An ArgSpec with args, varargs, keywords, and defaults parameters
83 from FullArgSpec.
84 """
85 fullargspecs = getfullargspec(target)
86 argspecs = ArgSpec(
87 args=fullargspecs.args,
88 varargs=fullargspecs.varargs,
89 keywords=fullargspecs.varkw,
90 defaults=fullargspecs.defaults,
91 )
92 return argspecs
94else:
95 _getargspec = _inspect.getargspec
97 def _getfullargspec(target):
98 """A python2 version of getfullargspec.
100 Args:
101 target: the target object to inspect.
103 Returns:
104 A FullArgSpec with empty kwonlyargs, kwonlydefaults and annotations.
105 """
106 return _convert_maybe_argspec_to_fullargspec(getargspec(target))
109def currentframe():
110 """TFDecorator-aware replacement for inspect.currentframe."""
111 return _inspect.stack()[1][0]
114def getargspec(obj):
115 """TFDecorator-aware replacement for `inspect.getargspec`.
117 Note: `getfullargspec` is recommended as the python 2/3 compatible
118 replacement for this function.
120 Args:
121 obj: A function, partial function, or callable object, possibly decorated.
123 Returns:
124 The `ArgSpec` that describes the signature of the outermost decorator that
125 changes the callable's signature, or the `ArgSpec` that describes
126 the object if not decorated.
128 Raises:
129 ValueError: When callable's signature can not be expressed with
130 ArgSpec.
131 TypeError: For objects of unsupported types.
132 """
133 if isinstance(obj, functools.partial):
134 return _get_argspec_for_partial(obj)
136 decorators, target = tf.__internal__.decorator.unwrap(obj)
138 spec = next(
139 (
140 d.decorator_argspec
141 for d in decorators
142 if d.decorator_argspec is not None
143 ),
144 None,
145 )
146 if spec:
147 return spec
149 try:
150 # Python3 will handle most callables here (not partial).
151 return _getargspec(target)
152 except TypeError:
153 pass
155 if isinstance(target, type):
156 try:
157 return _getargspec(target.__init__)
158 except TypeError:
159 pass
161 try:
162 return _getargspec(target.__new__)
163 except TypeError:
164 pass
166 # The `type(target)` ensures that if a class is received we don't return
167 # the signature of its __call__ method.
168 return _getargspec(type(target).__call__)
171def _get_argspec_for_partial(obj):
172 """Implements `getargspec` for `functools.partial` objects.
174 Args:
175 obj: The `functools.partial` object
176 Returns:
177 An `inspect.ArgSpec`
178 Raises:
179 ValueError: When callable's signature can not be expressed with
180 ArgSpec.
181 """
182 # When callable is a functools.partial object, we construct its ArgSpec with
183 # following strategy:
184 # - If callable partial contains default value for positional arguments (ie.
185 # object.args), then final ArgSpec doesn't contain those positional
186 # arguments.
187 # - If callable partial contains default value for keyword arguments (ie.
188 # object.keywords), then we merge them with wrapped target. Default values
189 # from callable partial takes precedence over those from wrapped target.
190 #
191 # However, there is a case where it is impossible to construct a valid
192 # ArgSpec. Python requires arguments that have no default values must be
193 # defined before those with default values. ArgSpec structure is only valid
194 # when this presumption holds true because default values are expressed as a
195 # tuple of values without keywords and they are always assumed to belong to
196 # last K arguments where K is number of default values present.
197 #
198 # Since functools.partial can give default value to any argument, this
199 # presumption may no longer hold in some cases. For example:
200 #
201 # def func(m, n):
202 # return 2 * m + n
203 # partialed = functools.partial(func, m=1)
204 #
205 # This example will result in m having a default value but n doesn't. This
206 # is usually not allowed in Python and can not be expressed in ArgSpec
207 # correctly.
208 #
209 # Thus, we must detect cases like this by finding first argument with
210 # default value and ensures all following arguments also have default
211 # values. When this is not true, a ValueError is raised.
213 n_prune_args = len(obj.args)
214 partial_keywords = obj.keywords or {}
216 args, varargs, keywords, defaults = getargspec(obj.func)
218 # Pruning first n_prune_args arguments.
219 args = args[n_prune_args:]
221 # Partial function may give default value to any argument, therefore length
222 # of default value list must be len(args) to allow each argument to
223 # potentially be given a default value.
224 no_default = object()
225 all_defaults = [no_default] * len(args)
227 if defaults:
228 all_defaults[-len(defaults) :] = defaults
230 # Fill in default values provided by partial function in all_defaults.
231 for kw, default in partial_keywords.items():
232 if kw in args:
233 idx = args.index(kw)
234 all_defaults[idx] = default
235 elif not keywords:
236 raise ValueError(
237 "Function does not have **kwargs parameter, but "
238 "contains an unknown partial keyword."
239 )
241 # Find first argument with default value set.
242 first_default = next(
243 (idx for idx, x in enumerate(all_defaults) if x is not no_default), None
244 )
246 # If no default values are found, return ArgSpec with defaults=None.
247 if first_default is None:
248 return ArgSpec(args, varargs, keywords, None)
250 # Checks if all arguments have default value set after first one.
251 invalid_default_values = [
252 args[i]
253 for i, j in enumerate(all_defaults)
254 if j is no_default and i > first_default
255 ]
257 if invalid_default_values:
258 raise ValueError(
259 f"Some arguments {invalid_default_values} do not have "
260 "default value, but they are positioned after those with "
261 "default values. This can not be expressed with ArgSpec."
262 )
264 return ArgSpec(args, varargs, keywords, tuple(all_defaults[first_default:]))
267def getfullargspec(obj):
268 """TFDecorator-aware replacement for `inspect.getfullargspec`.
270 This wrapper emulates `inspect.getfullargspec` in[^)]* Python2.
272 Args:
273 obj: A callable, possibly decorated.
275 Returns:
276 The `FullArgSpec` that describes the signature of
277 the outermost decorator that changes the callable's signature. If the
278 callable is not decorated, `inspect.getfullargspec()` will be called
279 directly on the callable.
280 """
281 decorators, target = tf.__internal__.decorator.unwrap(obj)
283 for d in decorators:
284 if d.decorator_argspec is not None:
285 return _convert_maybe_argspec_to_fullargspec(d.decorator_argspec)
286 return _getfullargspec(target)
289def getcallargs(*func_and_positional, **named):
290 """TFDecorator-aware replacement for inspect.getcallargs.
292 Args:
293 *func_and_positional: A callable, possibly decorated, followed by any
294 positional arguments that would be passed to `func`.
295 **named: The named argument dictionary that would be passed to `func`.
297 Returns:
298 A dictionary mapping `func`'s named arguments to the values they would
299 receive if `func(*positional, **named)` were called.
301 `getcallargs` will use the argspec from the outermost decorator that
302 provides it. If no attached decorators modify argspec, the final unwrapped
303 target's argspec will be used.
304 """
305 func = func_and_positional[0]
306 positional = func_and_positional[1:]
307 argspec = getfullargspec(func)
308 call_args = named.copy()
309 this = getattr(func, "im_self", None) or getattr(func, "__self__", None)
310 if ismethod(func) and this:
311 positional = (this,) + positional
312 remaining_positionals = [
313 arg for arg in argspec.args if arg not in call_args
314 ]
315 call_args.update(dict(zip(remaining_positionals, positional)))
316 default_count = 0 if not argspec.defaults else len(argspec.defaults)
317 if default_count:
318 for arg, value in zip(argspec.args[-default_count:], argspec.defaults):
319 if arg not in call_args:
320 call_args[arg] = value
321 if argspec.kwonlydefaults is not None:
322 for k, v in argspec.kwonlydefaults.items():
323 if k not in call_args:
324 call_args[k] = v
325 return call_args
328def getframeinfo(*args, **kwargs):
329 return _inspect.getframeinfo(*args, **kwargs)
332def getdoc(obj):
333 """TFDecorator-aware replacement for inspect.getdoc.
335 Args:
336 obj: An object, possibly decorated.
338 Returns:
339 The docstring associated with the object.
341 The outermost-decorated object is intended to have the most complete
342 documentation, so the decorated parameter is not unwrapped.
343 """
344 return _inspect.getdoc(obj)
347def getfile(obj):
348 """TFDecorator-aware replacement for inspect.getfile."""
349 unwrapped_object = tf.__internal__.decorator.unwrap(obj)[1]
351 # Work around for the case when object is a stack frame
352 # and only .pyc files are used. In this case, getfile
353 # might return incorrect path. So, we get the path from f_globals
354 # instead.
355 if (
356 hasattr(unwrapped_object, "f_globals")
357 and "__file__" in unwrapped_object.f_globals
358 ):
359 return unwrapped_object.f_globals["__file__"]
360 return _inspect.getfile(unwrapped_object)
363def getmembers(obj, predicate=None):
364 """TFDecorator-aware replacement for inspect.getmembers."""
365 return _inspect.getmembers(obj, predicate)
368def getmodule(obj):
369 """TFDecorator-aware replacement for inspect.getmodule."""
370 return _inspect.getmodule(obj)
373def getmro(cls):
374 """TFDecorator-aware replacement for inspect.getmro."""
375 return _inspect.getmro(cls)
378def getsource(obj):
379 """TFDecorator-aware replacement for inspect.getsource."""
380 return _inspect.getsource(tf.__internal__.decorator.unwrap(obj)[1])
383def getsourcefile(obj):
384 """TFDecorator-aware replacement for inspect.getsourcefile."""
385 return _inspect.getsourcefile(tf.__internal__.decorator.unwrap(obj)[1])
388def getsourcelines(obj):
389 """TFDecorator-aware replacement for inspect.getsourcelines."""
390 return _inspect.getsourcelines(tf.__internal__.decorator.unwrap(obj)[1])
393def isbuiltin(obj):
394 """TFDecorator-aware replacement for inspect.isbuiltin."""
395 return _inspect.isbuiltin(tf.__internal__.decorator.unwrap(obj)[1])
398def isclass(obj):
399 """TFDecorator-aware replacement for inspect.isclass."""
400 return _inspect.isclass(tf.__internal__.decorator.unwrap(obj)[1])
403def isfunction(obj):
404 """TFDecorator-aware replacement for inspect.isfunction."""
405 return _inspect.isfunction(tf.__internal__.decorator.unwrap(obj)[1])
408def isframe(obj):
409 """TFDecorator-aware replacement for inspect.ismodule."""
410 return _inspect.isframe(tf.__internal__.decorator.unwrap(obj)[1])
413def isgenerator(obj):
414 """TFDecorator-aware replacement for inspect.isgenerator."""
415 return _inspect.isgenerator(tf.__internal__.decorator.unwrap(obj)[1])
418def isgeneratorfunction(obj):
419 """TFDecorator-aware replacement for inspect.isgeneratorfunction."""
420 return _inspect.isgeneratorfunction(
421 tf.__internal__.decorator.unwrap(obj)[1]
422 )
425def ismethod(obj):
426 """TFDecorator-aware replacement for inspect.ismethod."""
427 return _inspect.ismethod(tf.__internal__.decorator.unwrap(obj)[1])
430def ismodule(obj):
431 """TFDecorator-aware replacement for inspect.ismodule."""
432 return _inspect.ismodule(tf.__internal__.decorator.unwrap(obj)[1])
435def isroutine(obj):
436 """TFDecorator-aware replacement for inspect.isroutine."""
437 return _inspect.isroutine(tf.__internal__.decorator.unwrap(obj)[1])
440def stack(context=1):
441 """TFDecorator-aware replacement for inspect.stack."""
442 return _inspect.stack(context)[1:]