Example #1
0
    def testFrameSummaryEquality(self):
        frames1 = tf_stack.extract_stack()
        frames2 = tf_stack.extract_stack()

        self.assertNotEqual(frames1[0], frames1[1])
        self.assertEqual(frames1[0], frames1[0])
        self.assertEqual(frames1[0], frames2[0])
Example #2
0
  def testFrameSummaryEquality(self):
    frame0, frame1 = tf_stack.extract_stack(limit=2)
    self.assertNotEqual(frame0, frame1)
    self.assertEqual(frame0, frame0)

    another_frame0, _ = tf_stack.extract_stack(limit=2)
    self.assertEqual(frame0, another_frame0)
Example #3
0
 def testFrameSummaryEqualityAndHash(self):
     # Both defined on the same line to produce identical stacks.
     frame1, frame2 = tf_stack.extract_stack(), tf_stack.extract_stack()
     self.assertEqual(len(frame1), len(frame2))
     for f1, f2 in zip(frame1, frame2):
         self.assertEqual(f1, f2)
         self.assertEqual(hash(f1), hash(f1))
         self.assertEqual(hash(f1), hash(f2))
     self.assertEqual(frame1, frame2)
     self.assertEqual(hash(tuple(frame1)), hash(tuple(frame2)))
Example #4
0
  def register(self, candidate, name=None):
    """Registers a Python object "candidate" for the given "name".

    Args:
      candidate: The candidate object to add to the registry.
      name: An optional string specifying the registry key for the candidate.
            If None, candidate.__name__ will be used.
    Raises:
      KeyError: If same name is used twice.
    """
    if not name:
      name = candidate.__name__
    if name in self._registry:
      (filename, line_number, function_name, _) = (
          self._registry[name][_LOCATION_TAG])
      raise KeyError("Registering two %s with name '%s'! "
                     "(Previous registration was in %s %s:%d)" %
                     (self._name, name, function_name, filename, line_number))

    logging.vlog(1, "Registering %s (%s) in %s.", name, candidate, self._name)
    # stack trace is [this_function, Register(), user_function,...]
    # so the user function is #2.
    stack = tf_stack.extract_stack()
    stack_index = min(2, len(stack)-1)
    if stack_index >= 0:
      user_function = stack[stack_index]
      location_tag = tf_stack.convert_stack([user_function])[0]
    else:
      location_tag = "UNKNOWN"
    self._registry[name] = {_TYPE_TAG: candidate, _LOCATION_TAG: location_tag}
Example #5
0
    def _process_stack_frames(self):
        """Process stack frames.

    Send the content of source-files, on a best-effort basis.

    Returns:
      A list of stack frame IDs.
    """
        stack_frames = tf_stack.extract_stack()
        stack_frame_ids = []
        writer = None
        for file_path, lineno, func, _ in stack_frames:
            if (file_path, lineno, func) in self._stack_frame_to_id:
                stack_frame_ids.append(self._stack_frame_to_id[(file_path,
                                                                lineno, func)])
                continue
            with self._stack_frame_to_id_lock:
                if (file_path, lineno, func) not in self._stack_frame_to_id:
                    stack_frame_id = _get_id()
                    self._stack_frame_to_id[(file_path, lineno,
                                             func)] = stack_frame_id
                    file_index = self._write_source_file_content(file_path)
                    file_line_col = graph_debug_info_pb2.GraphDebugInfo.FileLineCol(
                        file_index=file_index, line=lineno, func=func)
                    stack_frame_with_id = debug_event_pb2.StackFrameWithId(
                        id=stack_frame_id, file_line_col=file_line_col)
                    writer = self.get_writer()
                    writer.WriteStackFrameWithId(stack_frame_with_id)
                stack_frame_ids.append(self._stack_frame_to_id[(file_path,
                                                                lineno, func)])

        code_location = debug_event_pb2.CodeLocation(
            host_name=self._hostname, stack_frame_ids=stack_frame_ids)
        return code_location
Example #6
0
    def register(self, candidate, name=None):
        """Registers a Python object "candidate" for the given "name".

    Args:
      candidate: The candidate object to add to the registry.
      name: An optional string specifying the registry key for the candidate.
            If None, candidate.__name__ will be used.
    Raises:
      KeyError: If same name is used twice.
    """
        if not name:
            name = candidate.__name__
        if name in self._registry:
            frame = self._registry[name][_LOCATION_TAG]
            raise KeyError(
                "Registering two %s with name '%s'! "
                "(Previous registration was in %s %s:%d)" %
                (self._name, name, frame.name, frame.filename, frame.lineno))

        logging.vlog(1, "Registering %s (%s) in %s.", name, candidate,
                     self._name)
        # stack trace is [this_function, Register(), user_function,...]
        # so the user function is #2.
        stack = tf_stack.extract_stack(limit=3)
        stack_index = min(2, len(stack) - 1)
        if stack_index >= 0:
            location_tag = stack[stack_index]
        else:
            location_tag = ("UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN",
                            "UNKNOWN")
        self._registry[name] = {
            _TYPE_TAG: candidate,
            _LOCATION_TAG: location_tag
        }
Example #7
0
    def register(self, candidate, name=None):
        """Registers a Python object "candidate" for the given "name".

    Args:
      candidate: The candidate object to add to the registry.
      name: An optional string specifying the registry key for the candidate.
            If None, candidate.__name__ will be used.
    Raises:
      KeyError: If same name is used twice.
    """
        if not name:
            name = candidate.__name__
        if name in self._registry:
            (filename, line_number, function_name,
             _) = (self._registry[name][_LOCATION_TAG])
            raise KeyError(
                "Registering two %s with name '%s'! "
                "(Previous registration was in %s %s:%d)" %
                (self._name, name, function_name, filename, line_number))

        logging.vlog(1, "Registering %s (%s) in %s.", name, candidate,
                     self._name)
        # stack trace is [this_function, Register(), user_function,...]
        # so the user function is #2.
        stack = tf_stack.extract_stack()
        user_function = stack[2]
        location_tag = tf_stack.convert_stack([user_function])[0]
        self._registry[name] = {
            _TYPE_TAG: candidate,
            _LOCATION_TAG: location_tag
        }
def _call_location():
    # We want to get stack frame 3 frames up from current frame,
    # i.e. above __getattr__, _tfmw_add_deprecation_warning,
    # and _call_location calls.
    stack = tf_stack.extract_stack(limit=4)
    if not stack:  # should never happen as we're in a function
        return 'UNKNOWN'
    frame = stack[0]
    return '{}:{}'.format(frame.filename, frame.lineno)
Example #9
0
def _call_location(outer=False):
    """Returns call location given level up from current call."""
    stack = tf_stack.extract_stack(limit=4)
    length = len(stack)
    if length == 0:  # should never happen as we're in a function
        return 'UNKNOWN'
    index = length - 4 if outer else length - 3
    if index < 0:
        index = 0
    frame = stack[index]
    return '{}:{}'.format(frame.filename, frame.lineno)
Example #10
0
def _call_location(outer=False):
  """Returns call location given level up from current call."""
  stack = tf_stack.extract_stack()
  length = len(stack)
  if length == 0:  # should never happen as we're in a function
    return 'UNKNOWN'
  index = length-4 if outer else length-3
  if index < 0:
    index = 0
  frame = stack[index]
  return '{filename}:{lineno}'.format(filename=frame[0], lineno=frame[1])
Example #11
0
def make_decorator(target,
                   decorator_func,
                   decorator_name=None,
                   decorator_doc='',
                   decorator_argspec=None):
    """Make a decorator from a wrapper and a target.

  Args:
    target: The final callable to be wrapped.
    decorator_func: The wrapper function.
    decorator_name: The name of the decorator. If `None`, the name of the
      function calling make_decorator.
    decorator_doc: Documentation specific to this application of
      `decorator_func` to `target`.
    decorator_argspec: The new callable signature of this decorator.

  Returns:
    The `decorator_func` argument with new metadata attached.
  """
    if decorator_name is None:
        frame = tf_stack.extract_stack(limit=2)[0]
        decorator_name = frame[2]  # Caller's name
    decorator = TFDecorator(decorator_name, target, decorator_doc,
                            decorator_argspec)
    setattr(decorator_func, '_tf_decorator', decorator)
    # Objects that are callables (e.g., a functools.partial object) may not have
    # the following attributes.
    if hasattr(target, '__name__'):
        decorator_func.__name__ = target.__name__
    if hasattr(target, '__qualname__'):
        decorator_func.__qualname__ = target.__qualname__
    if hasattr(target, '__module__'):
        decorator_func.__module__ = target.__module__
    if hasattr(target, '__dict__'):
        # Copy dict entries from target which are not overridden by decorator_func.
        for name in target.__dict__:
            if name not in decorator_func.__dict__:
                decorator_func.__dict__[name] = target.__dict__[name]
    if hasattr(target, '__doc__'):
        decorator_func.__doc__ = decorator.__doc__
    decorator_func.__wrapped__ = target
    # Keeping a second handle to `target` allows callers to detect whether the
    # decorator was modified using `rewrap`.
    decorator_func.__original_wrapped__ = target
    return decorator_func
Example #12
0
def make_decorator(target,
                   decorator_func,
                   decorator_name=None,
                   decorator_doc='',
                   decorator_argspec=None):
  """Make a decorator from a wrapper and a target.

  Args:
    target: The final callable to be wrapped.
    decorator_func: The wrapper function.
    decorator_name: The name of the decorator. If `None`, the name of the
      function calling make_decorator.
    decorator_doc: Documentation specific to this application of
      `decorator_func` to `target`.
    decorator_argspec: The new callable signature of this decorator.

  Returns:
    The `decorator_func` argument with new metadata attached.
  """
  if decorator_name is None:
    frame = tf_stack.extract_stack(limit=2)[0]
    decorator_name = frame[2]  # Caller's name
  decorator = TFDecorator(decorator_name, target, decorator_doc,
                          decorator_argspec)
  setattr(decorator_func, '_tf_decorator', decorator)
  # Objects that are callables (e.g., a functools.partial object) may not have
  # the following attributes.
  if hasattr(target, '__name__'):
    decorator_func.__name__ = target.__name__
  if hasattr(target, '__module__'):
    decorator_func.__module__ = target.__module__
  if hasattr(target, '__dict__'):
    # Copy dict entries from target which are not overridden by decorator_func.
    for name in target.__dict__:
      if name not in decorator_func.__dict__:
        decorator_func.__dict__[name] = target.__dict__[name]
  if hasattr(target, '__doc__'):
    decorator_func.__doc__ = decorator.__doc__
  decorator_func.__wrapped__ = target
  # Keeping a second handle to `target` allows callers to detect whether the
  # decorator was modified using `rewrap`.
  decorator_func.__original_wrapped__ = target
  return decorator_func
Example #13
0
  def set_filename_and_line_from_caller(self, offset=0):
    """Set filename and line using the caller's stack frame.

    If the requested stack information is not available, a heuristic may
    be applied and self.HEURISTIC USED will be returned.  If the heuristic
    fails then no change will be made to the filename and lineno members
    (None by default) and self.FAILURE will be returned.

    Args:
      offset: Integer.  If 0, the caller's stack frame is used.  If 1,
          the caller's caller's stack frame is used.  Larger values are
          permissible but if out-of-range (larger than the number of stack
          frames available) the outermost stack frame will be used.

    Returns:
      TraceableObject.SUCCESS if appropriate stack information was found,
      TraceableObject.HEURISTIC_USED if the offset was larger than the stack,
      and TraceableObject.FAILURE if the stack was empty.
    """
    # Offset is defined in "Args" as relative to the caller.  We are one frame
    # beyond the caller.
    local_offset = offset + 1

    frame_records = tf_stack.extract_stack(
        limit=local_offset + 1)
    if not frame_records:
      return self.FAILURE
    if len(frame_records) > local_offset:
      frame = frame_records[len(frame_records) - (local_offset + 1)]
      self.filename = frame.filename
      self.lineno = frame.lineno
      return self.SUCCESS
    else:
      # If the offset is too large then we use the largest offset possible,
      # meaning we use the outermost stack frame at index 0.
      frame = frame_records[0]
      self.filename = frame.filename
      self.lineno = frame.lineno
      return self.HEURISTIC_USED
Example #14
0
  def set_filename_and_line_from_caller(self, offset=0):
    """Set filename and line using the caller's stack frame.

    If the requested stack information is not available, a heuristic may
    be applied and self.HEURISTIC USED will be returned.  If the heuristic
    fails then no change will be made to the filename and lineno members
    (None by default) and self.FAILURE will be returned.

    Args:
      offset: Integer.  If 0, the caller's stack frame is used.  If 1,
          the caller's caller's stack frame is used.  Larger values are
          permissible but if out-of-range (larger than the number of stack
          frames available) the outermost stack frame will be used.

    Returns:
      TraceableObject.SUCCESS if appropriate stack information was found,
      TraceableObject.HEURISTIC_USED if the offset was larger than the stack,
      and TraceableObject.FAILURE if the stack was empty.
    """
    # Offset is defined in "Args" as relative to the caller.  We are one frame
    # beyond the caller.
    local_offset = offset + 1

    frame_records = tf_stack.extract_stack()
    if not frame_records:
      return self.FAILURE
    if len(frame_records) >= local_offset:
      # Negative indexing is one-indexed instead of zero-indexed.
      negative_offset = -(local_offset + 1)
      self.filename, self.lineno = frame_records[negative_offset][:2]
      return self.SUCCESS
    else:
      # If the offset is too large then we use the largest offset possible,
      # meaning we use the outermost stack frame at index 0.
      self.filename, self.lineno = frame_records[0][:2]
      return self.HEURISTIC_USED
Example #15
0
 def func(n):
     if n == 0:
         return tf_stack.extract_stack()  # COMMENT
     else:
         return func(n - 1)
Example #16
0
 def testFormatStackSelfConsistency(self):
     # Both defined on the same line to produce identical stacks.
     stacks = tf_stack.extract_stack(), traceback.extract_stack()
     self.assertEqual(traceback.format_list(stacks[0]),
                      traceback.format_list(stacks[1]))
Example #17
0
def extract_stack(limit=None):
  # Both defined on the same line to produce identical stacks.
  return tf_stack.extract_stack(limit), traceback.extract_stack(limit)
Example #18
0
 def func():
     trace = tf_stack.extract_stack()  # COMMENT
     frames = list(trace.get_user_frames())
     return frames
Example #19
0
 def testLimit(self):
   self.assertEmpty(tf_stack.extract_stack(limit=0))
   self.assertLen(tf_stack.extract_stack(limit=1), 1)
   self.assertEqual(
       len(tf_stack.extract_stack(limit=-1)),
       len(tf_stack.extract_stack()))
Example #20
0
def _call_location(outer=False):
  """Returns call location given level up from current call."""
  stack = tf_stack.extract_stack()
  frame = stack[-4 if outer else -3]
  return '{filename}:{lineno}'.format(filename=frame[0], lineno=frame[1])
Example #21
0
def extract_stack(limit=None):
    # Both defined on the same line to produce identical stacks.
    return tf_stack.extract_stack(limit), traceback.extract_stack(limit)  # pylint: disable=too-many-function-args
Example #22
0
 def testLastUserFrame(self):
   trace = tf_stack.extract_stack()  # COMMENT
   frame = trace.last_user_frame()
   self.assertRegex(frame.line, "# COMMENT")
Example #23
0
def _call_location(outer=False):
    """Returns call location given level up from current call."""
    stack = tf_stack.extract_stack()
    frame = stack[-4 if outer else -3]
    return '{filename}:{lineno}'.format(filename=frame[0], lineno=frame[1])
Example #24
0
def extract_stack(limit=None):
    convert = tf_stack.convert_stack
    # Both defined on the same line to produce identical stacks.
    return convert(
        tf_stack.extract_stack(limit)), traceback.extract_stack(limit)