class_docstr: Configuration object defines retry behaviour and is composed of these fields:
      * `retriable` - function that decides if an exception should trigger retrying
      * `get_delay` - function that returns a number of seconds retrier must wait before doing the next attempt
      * `max_time` - maximum `datetime.timedelta` that can pass after the first call for any retry attempt to be done
      * `max_times` - maximum number of retry attempts (note retries, not tries/calls)
      * `handle_error` - function that is called for each failed call attempt
      * `logger` - logger object to record retry warnings with
      * `sleep` - custom sleep function to use for waiting
  
  >>> RetryConf(max_time=datetime.timedelta(seconds=30), max_times=10)
  
  Empty configuration retries indefinitely on any exceptions raised.
  
  By default `DEFAULT_CONF` if used, which retries indefinitely, waiting 1 sec with 1.2 backoff between attempts, and
  also logging with built-in logger object.
  
  Configuration must be cloned before modification to create separate configuration:
  
  >>> DEFAULT_CONF.clone()
  
  There are various methods that provide convenient clone-and-modify shortcuts and "retry recipes".
class_docstr_tok: ["Configuration","object","defines","retry","behaviour","and","is","composed","of","these","fields",":","*","`","retriable","`","-","function","that","decides","if","an","exception","should","trigger","retrying","*","`","get_delay","`","-","function","that","returns","a","number","of","seconds","retrier","must","wait","before","doing","the","next","attempt","*","`","max_time","`","-","maximum","`","datetime.timedelta","`","that","can","pass","after","the","first","call","for","any","retry","attempt","to","be","done","*","`","max_times","`","-","maximum","number","of","retry","attempts","(","note","retries",",","not","tries\/calls",")","*","`","handle_error","`","-","function","that","is","called","for","each","failed","call","attempt","*","`","logger","`","-","logger","object","to","record","retry","warnings","with","*","`","sleep","`","-","custom","sleep","function","to","use","for","waiting",">",">",">","RetryConf","(","max_time=datetime.timedelta","(","seconds=30",")",",","max_times=10",")","Empty","configuration","retries","indefinitely","on","any","exceptions","raised",".","By","default","`","DEFAULT_CONF","`","if","used",",","which","retries","indefinitely",",","waiting","1","sec","with","1.2","backoff","between","attempts",",","and","also","logging","with","built-in","logger","object",".","Configuration","must","be","cloned","before","modification","to","create","separate","configuration",":",">",">",">","DEFAULT_CONF.clone","(",")","There","are","various","methods","that","provide","convenient","clone-and-modify","shortcuts","and","``","retry","recipes","''","."]
docstr: Clone and wait between attempts with backoff, jitter and limit (get_delay shortcut):
  
  >>> conf = conf.waiting(delay)
  >>> conf = conf.waiting(delay, backoff=2.0)  # initial delay with backoff x2 on each attempt
  >>> conf = conf.waiting(delay, jitter=3)  # jitter from 0 to 3 seconds
  >>> conf = conf.waiting(delay, backoff=2.0, limit=60)  # delay with backoff, but not greater than a minute
  
  All these options can be combined together, of course.
docstr_tok: ["Clone","and","wait","between","attempts","with","backoff",",","jitter","and","limit","(","get_delay","shortcut",")",":",">",">",">","conf","=","conf.waiting","(","delay",")",">",">",">","conf","=","conf.waiting","(","delay",",","backoff=2.0",")","#","initial","delay","with","backoff","x2","on","each","attempt",">",">",">","conf","=","conf.waiting","(","delay",",","jitter=3",")","#","jitter","from","0","to","3","seconds",">",">",">","conf","=","conf.waiting","(","delay",",","backoff=2.0",",","limit=60",")","#","delay","with","backoff",",","but","not","greater","than","a","minute","All","these","options","can","be","combined","together",",","of","course","."]
code: def waiting(self, delay=0, backoff=1.0, jitter=0, limit=None):
      """
      Clone and wait between attempts with backoff, jitter and limit (get_delay shortcut):
  
      >>> conf = conf.waiting(delay)
      >>> conf = conf.waiting(delay, backoff=2.0)  # initial delay with backoff x2 on each attempt
      >>> conf = conf.waiting(delay, jitter=3)  # jitter from 0 to 3 seconds
      >>> conf = conf.waiting(delay, backoff=2.0, limit=60)  # delay with backoff, but not greater than a minute
  
      All these options can be combined together, of course.
      """
  
      def get_delay(n, raised_after, last):
          if n == 1:
              return delay
  
          s = last * backoff
          s += random.uniform(0, jitter)
          if limit is not None:
              s = min(s, limit)
          return s
  
      obj = self.clone()
      obj.get_delay = get_delay
      return obj
  
imports: import copy
  import datetime
  import functools
  import itertools
  import logging
  import random
  import time
label_desc: Use image node_id 5 for calling the RetryConf obj's underlying member method code with example usage: obj.waiting(delay, backoff, jitter, limit) and returns: obj, s, delay