code: def call(self, fn, *args, **kwargs):
      start_time = int(round(time.time() * 1000))
      attempt_number = 1
      while True:
          if self._before_attempts:
              self._before_attempts(attempt_number)
  
          try:
              attempt = Attempt(
                  fn(*args, **kwargs), attempt_number, False
              )
          except:
              tb = sys.exc_info()
              attempt = Attempt(tb, attempt_number, True)
  
          if not self.should_reject(attempt):
              return attempt.get(self._wrap_exception)
  
          if self._after_attempts:
              self._after_attempts(attempt_number)
  
          delay_since_first_attempt_ms = (
              int(round(time.time() * 1000)) - start_time
          )
          if self.stop(attempt_number, delay_since_first_attempt_ms):
              if not self._wrap_exception and attempt.has_exception:
                  # get() on an attempt with an exception should cause it to be raised, but raise just in case
                  raise attempt.get()
              else:
                  raise RetryError(attempt)
          else:
              sleep = self.wait(
                  attempt_number, delay_since_first_attempt_ms
              )
              if self._wait_jitter_max:
                  jitter = random.random() * self._wait_jitter_max
                  sleep = sleep + max(0, jitter)
              time.sleep(sleep / 1000.0)
  
          attempt_number += 1
  
imports: import random
  import six
  import sys
  import time
  import traceback
label_desc: Use image node_id 12 for calling the Retrying obj's underlying member method code with example usage: obj.call(fn) and returns: attempt