Refactor tf.Operation.traceback
implementation in to methods of tf.Graph.
Adds an `_extract_frame_info` method to allow derived classes to extend the information available in each op traceback, if desired. The default result of `tf.Operation.traceback` is unchanged. Also fixes a poorly scoped `pylint disable=line-too-long`, so adds the necessary enable/disable blocks to silence pylint for the offending docstrings. PiperOrigin-RevId: 157466174
This commit is contained in:
parent
f7ca8db7d8
commit
b73fea6e27
@ -88,70 +88,6 @@ def _override_helper(clazz_object, operator, func):
|
|||||||
setattr(clazz_object, operator, func)
|
setattr(clazz_object, operator, func)
|
||||||
|
|
||||||
|
|
||||||
def _convert_stack(stack, include_func_start_lineno=False):
|
|
||||||
"""Converts a stack extracted using _extract_stack() to a traceback stack.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
stack: A list of n 5-tuples,
|
|
||||||
(filename, lineno, name, frame_globals, func_start_lineno).
|
|
||||||
include_func_start_lineno: True if function start line number should be
|
|
||||||
included as the 5th entry in return tuples.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of n 4-tuples or 5-tuples
|
|
||||||
(filename, lineno, name, code, [optional: func_start_lineno]), where the
|
|
||||||
code tuple element is calculated from the corresponding elements of the
|
|
||||||
input tuple.
|
|
||||||
"""
|
|
||||||
ret = []
|
|
||||||
for filename, lineno, name, frame_globals, func_start_lineno in stack:
|
|
||||||
linecache.checkcache(filename)
|
|
||||||
line = linecache.getline(filename, lineno, frame_globals)
|
|
||||||
if line:
|
|
||||||
line = line.strip()
|
|
||||||
else:
|
|
||||||
line = None
|
|
||||||
if include_func_start_lineno:
|
|
||||||
ret.append((filename, lineno, name, line, func_start_lineno))
|
|
||||||
else:
|
|
||||||
ret.append((filename, lineno, name, line))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=line-too-long
|
|
||||||
def _extract_stack():
|
|
||||||
"""A lightweight re-implementation of traceback.extract_stack.
|
|
||||||
|
|
||||||
NOTE(mrry): traceback.extract_stack eagerly retrieves the line of code for
|
|
||||||
each stack frame using linecache, which results in an abundance of stat()
|
|
||||||
calls. This implementation does not retrieve the code, and any consumer
|
|
||||||
should apply _convert_stack to the result to obtain a traceback that can
|
|
||||||
be formatted etc. using traceback methods.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of 5-tuples
|
|
||||||
(filename, lineno, name, frame_globals, func_start_lineno) corresponding to
|
|
||||||
the call stack of the current thread.
|
|
||||||
"""
|
|
||||||
# pylint: enable=line-too-long
|
|
||||||
try:
|
|
||||||
raise ZeroDivisionError
|
|
||||||
except ZeroDivisionError:
|
|
||||||
f = sys.exc_info()[2].tb_frame.f_back
|
|
||||||
ret = []
|
|
||||||
while f is not None:
|
|
||||||
lineno = f.f_lineno
|
|
||||||
co = f.f_code
|
|
||||||
filename = co.co_filename
|
|
||||||
name = co.co_name
|
|
||||||
frame_globals = f.f_globals
|
|
||||||
func_start_lineno = co.co_firstlineno
|
|
||||||
ret.append((filename, lineno, name, frame_globals, func_start_lineno))
|
|
||||||
f = f.f_back
|
|
||||||
ret.reverse()
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def _as_graph_element(obj):
|
def _as_graph_element(obj):
|
||||||
"""Convert `obj` to a graph element if possible, otherwise return `None`.
|
"""Convert `obj` to a graph element if possible, otherwise return `None`.
|
||||||
|
|
||||||
@ -1264,7 +1200,7 @@ class Operation(object):
|
|||||||
|
|
||||||
self._original_op = original_op
|
self._original_op = original_op
|
||||||
self._op_def = op_def
|
self._op_def = op_def
|
||||||
self._traceback = _extract_stack()
|
self._traceback = self._graph._extract_stack() # pylint: disable=protected-access
|
||||||
# Add this op to the current control flow context:
|
# Add this op to the current control flow context:
|
||||||
self._control_flow_context = g._get_control_flow_context()
|
self._control_flow_context = g._get_control_flow_context()
|
||||||
if self._control_flow_context is not None:
|
if self._control_flow_context is not None:
|
||||||
@ -1613,6 +1549,7 @@ class Operation(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def node_def(self):
|
def node_def(self):
|
||||||
|
# pylint: disable=line-too-long
|
||||||
"""Returns a serialized `NodeDef` representation of this operation.
|
"""Returns a serialized `NodeDef` representation of this operation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -1620,10 +1557,12 @@ class Operation(object):
|
|||||||
[`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/node_def.proto)
|
[`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/node_def.proto)
|
||||||
protocol buffer.
|
protocol buffer.
|
||||||
"""
|
"""
|
||||||
|
# pylint: enable=line-too-long
|
||||||
return self._node_def
|
return self._node_def
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def op_def(self):
|
def op_def(self):
|
||||||
|
# pylint: disable=line-too-long
|
||||||
"""Returns the `OpDef` proto that represents the type of this op.
|
"""Returns the `OpDef` proto that represents the type of this op.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -1631,12 +1570,13 @@ class Operation(object):
|
|||||||
[`OpDef`](https://www.tensorflow.org/code/tensorflow/core/framework/op_def.proto)
|
[`OpDef`](https://www.tensorflow.org/code/tensorflow/core/framework/op_def.proto)
|
||||||
protocol buffer.
|
protocol buffer.
|
||||||
"""
|
"""
|
||||||
|
# pylint: enable=line-too-long
|
||||||
return self._op_def
|
return self._op_def
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def traceback(self):
|
def traceback(self):
|
||||||
"""Returns the call stack from when this operation was constructed."""
|
"""Returns the call stack from when this operation was constructed."""
|
||||||
return _convert_stack(self._traceback)
|
return self._graph._convert_stack(self._traceback) # pylint: disable=protected-access
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def traceback_with_start_lines(self):
|
def traceback_with_start_lines(self):
|
||||||
@ -1645,7 +1585,8 @@ class Operation(object):
|
|||||||
Returns:
|
Returns:
|
||||||
A list of 5-tuples (filename, lineno, name, code, func_start_lineno).
|
A list of 5-tuples (filename, lineno, name, code, func_start_lineno).
|
||||||
"""
|
"""
|
||||||
return _convert_stack(self._traceback, include_func_start_lineno=True)
|
return self._graph._convert_stack( # pylint: disable=protected-access
|
||||||
|
self._traceback, include_func_start_lineno=True)
|
||||||
|
|
||||||
def get_attr(self, name):
|
def get_attr(self, name):
|
||||||
"""Returns the value of the attr of this op with the given `name`.
|
"""Returns the value of the attr of this op with the given `name`.
|
||||||
@ -2170,6 +2111,76 @@ class Graph(object):
|
|||||||
else:
|
else:
|
||||||
self._scoped_c_graph = None
|
self._scoped_c_graph = None
|
||||||
|
|
||||||
|
def _convert_stack(self, stack, include_func_start_lineno=False):
|
||||||
|
"""Converts a stack extracted using _extract_stack() to a traceback stack.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
stack: A list of n 5-tuples,
|
||||||
|
(filename, lineno, name, frame_globals, func_start_lineno).
|
||||||
|
include_func_start_lineno: True if function start line number should be
|
||||||
|
included as the 5th entry in return tuples.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of n 4-tuples or 5-tuples
|
||||||
|
(filename, lineno, name, code, [optional: func_start_lineno]), where the
|
||||||
|
code tuple element is calculated from the corresponding elements of the
|
||||||
|
input tuple.
|
||||||
|
"""
|
||||||
|
ret = []
|
||||||
|
for (filename, lineno, name, frame_globals, func_start_lineno,
|
||||||
|
unused_frame_info) in stack:
|
||||||
|
linecache.checkcache(filename)
|
||||||
|
line = linecache.getline(filename, lineno, frame_globals)
|
||||||
|
if line:
|
||||||
|
line = line.strip()
|
||||||
|
else:
|
||||||
|
line = None
|
||||||
|
if include_func_start_lineno:
|
||||||
|
ret.append((filename, lineno, name, line, func_start_lineno))
|
||||||
|
else:
|
||||||
|
ret.append((filename, lineno, name, line))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _extract_stack(self):
|
||||||
|
"""A lightweight, extensible re-implementation of traceback.extract_stack.
|
||||||
|
|
||||||
|
NOTE(mrry): traceback.extract_stack eagerly retrieves the line of code for
|
||||||
|
each stack frame using linecache, which results in an abundance of stat()
|
||||||
|
calls. This implementation does not retrieve the code, and any consumer
|
||||||
|
should apply _convert_stack to the result to obtain a traceback that can
|
||||||
|
be formatted etc. using traceback methods.
|
||||||
|
|
||||||
|
Derived classes can implement _extract_frame_info() to add extra information
|
||||||
|
to the traceback.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of 6-tuples
|
||||||
|
(filename, lineno, name, frame_globals, func_start_lineno, custom_info)
|
||||||
|
corresponding to the call stack of the current thread.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
raise ZeroDivisionError
|
||||||
|
except ZeroDivisionError:
|
||||||
|
f = sys.exc_info()[2].tb_frame.f_back
|
||||||
|
ret = []
|
||||||
|
while f is not None:
|
||||||
|
lineno = f.f_lineno
|
||||||
|
co = f.f_code
|
||||||
|
filename = co.co_filename
|
||||||
|
name = co.co_name
|
||||||
|
frame_globals = f.f_globals
|
||||||
|
func_start_lineno = co.co_firstlineno
|
||||||
|
frame_info = self._extract_frame_info(f)
|
||||||
|
ret.append((filename, lineno, name, frame_globals, func_start_lineno,
|
||||||
|
frame_info))
|
||||||
|
f = f.f_back
|
||||||
|
ret.reverse()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _extract_frame_info(self, frame): # pylint: disable=unused-argument
|
||||||
|
"""Extracts custom information from a frame in an op traceback."""
|
||||||
|
return None
|
||||||
|
|
||||||
def _check_not_finalized(self):
|
def _check_not_finalized(self):
|
||||||
"""Check if the graph is finalized.
|
"""Check if the graph is finalized.
|
||||||
|
|
||||||
@ -2226,6 +2237,7 @@ class Graph(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def graph_def_versions(self):
|
def graph_def_versions(self):
|
||||||
|
# pylint: disable=line-too-long
|
||||||
"""The GraphDef version information of this graph.
|
"""The GraphDef version information of this graph.
|
||||||
|
|
||||||
For details on the meaning of each version, see
|
For details on the meaning of each version, see
|
||||||
@ -2234,6 +2246,7 @@ class Graph(object):
|
|||||||
Returns:
|
Returns:
|
||||||
A `VersionDef`.
|
A `VersionDef`.
|
||||||
"""
|
"""
|
||||||
|
# pylint: enable=line-too-long
|
||||||
return self._graph_def_versions
|
return self._graph_def_versions
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -2287,6 +2300,7 @@ class Graph(object):
|
|||||||
self._control_flow_context = context
|
self._control_flow_context = context
|
||||||
|
|
||||||
def _as_graph_def(self, from_version=None, add_shapes=False):
|
def _as_graph_def(self, from_version=None, add_shapes=False):
|
||||||
|
# pylint: disable=line-too-long
|
||||||
"""Returns a serialized `GraphDef` representation of this graph.
|
"""Returns a serialized `GraphDef` representation of this graph.
|
||||||
|
|
||||||
The serialized `GraphDef` can be imported into another `Graph`
|
The serialized `GraphDef` can be imported into another `Graph`
|
||||||
@ -2312,6 +2326,7 @@ class Graph(object):
|
|||||||
ValueError: If the `graph_def` would be too large.
|
ValueError: If the `graph_def` would be too large.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# pylint: enable=line-too-long
|
||||||
with self._lock:
|
with self._lock:
|
||||||
graph = graph_pb2.GraphDef()
|
graph = graph_pb2.GraphDef()
|
||||||
graph.versions.CopyFrom(self._graph_def_versions)
|
graph.versions.CopyFrom(self._graph_def_versions)
|
||||||
@ -2341,6 +2356,7 @@ class Graph(object):
|
|||||||
return graph, self._version
|
return graph, self._version
|
||||||
|
|
||||||
def as_graph_def(self, from_version=None, add_shapes=False):
|
def as_graph_def(self, from_version=None, add_shapes=False):
|
||||||
|
# pylint: disable=line-too-long
|
||||||
"""Returns a serialized `GraphDef` representation of this graph.
|
"""Returns a serialized `GraphDef` representation of this graph.
|
||||||
|
|
||||||
The serialized `GraphDef` can be imported into another `Graph`
|
The serialized `GraphDef` can be imported into another `Graph`
|
||||||
@ -2363,6 +2379,7 @@ class Graph(object):
|
|||||||
Raises:
|
Raises:
|
||||||
ValueError: If the `graph_def` would be too large.
|
ValueError: If the `graph_def` would be too large.
|
||||||
"""
|
"""
|
||||||
|
# pylint: enable=line-too-long
|
||||||
result, _ = self._as_graph_def(from_version, add_shapes)
|
result, _ = self._as_graph_def(from_version, add_shapes)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -2930,7 +2947,7 @@ class Graph(object):
|
|||||||
finally:
|
finally:
|
||||||
self._default_original_op = old_original_op
|
self._default_original_op = old_original_op
|
||||||
|
|
||||||
# pylint: disable=g-doc-return-or-yield
|
# pylint: disable=g-doc-return-or-yield,line-too-long
|
||||||
@tf_contextlib.contextmanager
|
@tf_contextlib.contextmanager
|
||||||
def name_scope(self, name):
|
def name_scope(self, name):
|
||||||
r"""Returns a context manager that creates hierarchical names for operations.
|
r"""Returns a context manager that creates hierarchical names for operations.
|
||||||
@ -3040,7 +3057,7 @@ class Graph(object):
|
|||||||
yield "" if new_stack is None else new_stack + "/"
|
yield "" if new_stack is None else new_stack + "/"
|
||||||
finally:
|
finally:
|
||||||
self._name_stack = old_stack
|
self._name_stack = old_stack
|
||||||
# pylint: enable=g-doc-return-or-yield
|
# pylint: enable=g-doc-return-or-yield,line-too-long
|
||||||
|
|
||||||
def unique_name(self, name, mark_as_used=True):
|
def unique_name(self, name, mark_as_used=True):
|
||||||
"""Return a unique operation name for `name`.
|
"""Return a unique operation name for `name`.
|
||||||
@ -3181,6 +3198,7 @@ class Graph(object):
|
|||||||
|
|
||||||
@tf_contextlib.contextmanager
|
@tf_contextlib.contextmanager
|
||||||
def device(self, device_name_or_function):
|
def device(self, device_name_or_function):
|
||||||
|
# pylint: disable=line-too-long
|
||||||
"""Returns a context manager that specifies the default device to use.
|
"""Returns a context manager that specifies the default device to use.
|
||||||
|
|
||||||
The `device_name_or_function` argument may either be a device name
|
The `device_name_or_function` argument may either be a device name
|
||||||
@ -3237,6 +3255,7 @@ class Graph(object):
|
|||||||
created ops.
|
created ops.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# pylint: enable=line-too-long
|
||||||
if (device_name_or_function is not None
|
if (device_name_or_function is not None
|
||||||
and not callable(device_name_or_function)):
|
and not callable(device_name_or_function)):
|
||||||
device_function = pydev.merge_device(device_name_or_function)
|
device_function = pydev.merge_device(device_name_or_function)
|
||||||
|
Loading…
Reference in New Issue
Block a user