nodes: 0, module; 1, function_definition; 2, function_name:time_pipeline; 3, parameters; 4, block; 5, identifier:iterable; 6, list_splat_pattern; 7, expression_statement; 8, if_statement; 9, comment:# if iterable is not a function, load the whole thing; 10, comment:# into a list so it can be ran over multiple times; 11, if_statement; 12, comment:# these store timestamps for time calculations; 13, expression_statement; 14, expression_statement; 15, for_statement; 16, comment:#print(results); 17, comment:#print(durations); 18, assert_statement; 19, expression_statement; 20, expression_statement; 21, comment:#print(ratios); 22, for_statement; 23, identifier:steps; 24, string; 25, call; 26, block; 27, else_clause; 28, not_operator; 29, block; 30, assignment; 31, assignment; 32, pattern_list; 33, call; 34, block; 35, comparison_operator:sum(results) > 0; 36, assignment; 37, assignment; 38, identifier:i; 39, call; 40, block; 41, string_content:This times the steps in a pipeline. Give it an iterable to test against
  followed by the steps of the pipeline seperated in individual functions.
  
  Example Usage:
  ```
      from random import choice, randint
  
      l = [randint(0,50) for i in range(100)]
  
      step1 = lambda iterable:(i for i in iterable if i%5==0)
      step2 = lambda iterable:(i for i in iterable if i%8==3)
      step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable)
  
      print('filter first')
      time_pipeline(l, step1, step2, step3, step4)
      print('process first')
      time_pipeline(l, step3, step4, step1, step2)
      print('filter, process, filter, process')
      time_pipeline(l, step1, step3, step2, step4)
  ``` 
  
  Outputs:
      filter first
      step 1 | 2.0427s | step1 = lambda iterable:(i for i in iterable if i%5==0)
      step 2 | 2.0510s | step2 = lambda iterable:(i for i in iterable if i%8==3)
      step 3 | 2.4839s | step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step 4 | 2.8446s | step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable)
      process first
      step 1 | 7.5291s | step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step 2 | 20.6732s | step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable)
      step 3 | 16.8470s | step1 = lambda iterable:(i for i in iterable if i%5==0)
      step 4 | 16.8269s | step2 = lambda iterable:(i for i in iterable if i%8==3)
      filter, process, filter, process
      step 1 | 2.0528s | step1 = lambda iterable:(i for i in iterable if i%5==0)
      step 2 | 3.3039s | step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step 3 | 3.1385s | step2 = lambda iterable:(i for i in iterable if i%8==3)
      step 4 | 3.1489s | step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable); 42, identifier:callable; 43, argument_list; 44, try_statement; 45, block; 46, identifier:callable_base; 47, expression_statement; 48, identifier:durations; 49, list; 50, identifier:results; 51, list; 52, identifier:i; 53, identifier:_; 54, identifier:enumerate; 55, argument_list; 56, expression_statement; 57, comment:#print('testing',current_tasks); 58, expression_statement; 59, comment:# run this test x number of times; 60, for_statement; 61, expression_statement; 62, if_statement; 63, call; 64, integer:0; 65, identifier:resultsum; 66, call; 67, identifier:ratios; 68, list_comprehension; 69, identifier:range; 70, argument_list; 71, try_statement; 72, expression_statement; 73, identifier:iterable; 74, block; 75, except_clause; 76, try_statement; 77, assignment; 78, identifier:steps; 79, assignment; 80, assignment; 81, identifier:t; 82, call; 83, comment:# build the generator; 84, block; 85, call; 86, comparison_operator:len(durations) == 1; 87, block; 88, else_clause; 89, identifier:sum; 90, argument_list; 91, identifier:sum; 92, argument_list; 93, binary_operator:i/resultsum; 94, for_in_clause; 95, call; 96, block; 97, except_clause; 98, call; 99, expression_statement; 100, expression_statement; 101, block; 102, block; 103, except_clause; 104, identifier:iterable; 105, call; 106, identifier:current_tasks; 107, subscript; 108, identifier:duration; 109, float:0.0; 110, identifier:range; 111, argument_list; 112, expression_statement; 113, comment:# time its execution; 114, expression_statement; 115, for_statement; 116, for_statement; 117, expression_statement; 118, attribute; 119, argument_list; 120, call; 121, integer:1; 122, expression_statement; 123, comment:#print(durations[0],durations[0]); 124, block; 125, identifier:results; 126, identifier:results; 127, identifier:i; 128, identifier:resultsum; 129, identifier:i; 130, identifier:results; 131, identifier:len; 132, argument_list; 133, expression_statement; 134, block; 135, identifier:print; 136, argument_list; 137, call; 138, assignment; 139, raise_statement; 140, expression_statement; 141, expression_statement; 142, block; 143, identifier:tuple; 144, argument_list; 145, identifier:steps; 146, slice; 147, integer:100000; 148, assignment; 149, assignment; 150, identifier:task; 151, identifier:current_tasks; 152, block; 153, identifier:i; 154, call; 155, block; 156, augmented_assignment; 157, identifier:durations; 158, identifier:append; 159, identifier:duration; 160, identifier:len; 161, argument_list; 162, call; 163, expression_statement; 164, comment:#print(durations[-1]-durations[-2],durations[-1]); 165, identifier:ratios; 166, assignment; 167, expression_statement; 168, call; 169, identifier:iter; 170, argument_list; 171, identifier:callable_base; 172, True; 173, call; 174, call; 175, assignment; 176, raise_statement; 177, identifier:iterable; 178, binary_operator:i+1; 179, identifier:test_generator; 180, conditional_expression:iter(iterable()) if callable_base else iter(iterable); 181, identifier:start; 182, call; 183, expression_statement; 184, subscript; 185, argument_list; 186, pass_statement; 187, identifier:duration; 188, binary_operator:ts() - start; 189, identifier:durations; 190, attribute; 191, argument_list; 192, call; 193, identifier:s; 194, call; 195, assignment; 196, attribute; 197, argument_list; 198, call; 199, identifier:TypeError; 200, argument_list; 201, identifier:iter; 202, argument_list; 203, identifier:callable_base; 204, False; 205, call; 206, identifier:i; 207, integer:1; 208, call; 209, identifier:callable_base; 210, call; 211, identifier:ts; 212, argument_list; 213, assignment; 214, identifier:current_tasks; 215, unary_operator; 216, identifier:test_generator; 217, call; 218, identifier:start; 219, identifier:results; 220, identifier:append; 221, subscript; 222, attribute; 223, argument_list; 224, attribute; 225, argument_list; 226, identifier:s; 227, call; 228, string; 229, identifier:format; 230, binary_operator:i+1; 231, subscript; 232, identifier:s; 233, identifier:iterable; 234, argument_list; 235, string; 236, identifier:iterable; 237, identifier:TypeError; 238, argument_list; 239, identifier:iter; 240, argument_list; 241, identifier:iter; 242, argument_list; 243, identifier:test_generator; 244, call; 245, integer:1; 246, identifier:ts; 247, argument_list; 248, identifier:durations; 249, integer:0; 250, identifier:results; 251, identifier:append; 252, binary_operator:durations[-1]-durations[-2]; 253, subscript; 254, identifier:strip; 255, attribute; 256, argument_list; 257, string_content:step {} | {:2.4f}s | {}; 258, identifier:i; 259, integer:1; 260, identifier:durations; 261, identifier:i; 262, string_content:time_pipeline needs the first argument to be an iterable or a function that produces an iterable.; 263, string; 264, call; 265, identifier:iterable; 266, identifier:task; 267, argument_list; 268, subscript; 269, subscript; 270, call; 271, integer:0; 272, call; 273, identifier:strip; 274, string_content:time_pipeline needs the first argument to be an iterable or a function that produces an iterable.; 275, identifier:iterable; 276, argument_list; 277, identifier:test_generator; 278, identifier:durations; 279, unary_operator; 280, identifier:durations; 281, unary_operator; 282, attribute; 283, argument_list; 284, identifier:repr; 285, argument_list; 286, integer:1; 287, integer:2; 288, call; 289, identifier:splitlines; 290, subscript; 291, identifier:getsource; 292, argument_list; 293, identifier:steps; 294, identifier:i; 295, subscript; 296, identifier:steps; 297, identifier:i
code: def time_pipeline(iterable, *steps):
      '''
  This times the steps in a pipeline. Give it an iterable to test against
  followed by the steps of the pipeline seperated in individual functions.
  
  Example Usage:
  ```
      from random import choice, randint
  
      l = [randint(0,50) for i in range(100)]
  
      step1 = lambda iterable:(i for i in iterable if i%5==0)
      step2 = lambda iterable:(i for i in iterable if i%8==3)
      step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable)
  
      print('filter first')
      time_pipeline(l, step1, step2, step3, step4)
      print('process first')
      time_pipeline(l, step3, step4, step1, step2)
      print('filter, process, filter, process')
      time_pipeline(l, step1, step3, step2, step4)
  ``` 
  
  Outputs:
      filter first
      step 1 | 2.0427s | step1 = lambda iterable:(i for i in iterable if i%5==0)
      step 2 | 2.0510s | step2 = lambda iterable:(i for i in iterable if i%8==3)
      step 3 | 2.4839s | step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step 4 | 2.8446s | step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable)
      process first
      step 1 | 7.5291s | step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step 2 | 20.6732s | step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable)
      step 3 | 16.8470s | step1 = lambda iterable:(i for i in iterable if i%5==0)
      step 4 | 16.8269s | step2 = lambda iterable:(i for i in iterable if i%8==3)
      filter, process, filter, process
      step 1 | 2.0528s | step1 = lambda iterable:(i for i in iterable if i%5==0)
      step 2 | 3.3039s | step3 = lambda iterable:sorted((1.0*i)/50 for i in iterable)
      step 3 | 3.1385s | step2 = lambda iterable:(i for i in iterable if i%8==3)
      step 4 | 3.1489s | step4 = lambda iterable:(float(float(float(float(i*3)))) for i in iterable)
  '''
      if callable(iterable):
          try:
              iter(iterable())
              callable_base = True
          except:
              raise TypeError('time_pipeline needs the first argument to be an iterable or a function that produces an iterable.')
      else:
          try:
              iter(iterable)
              callable_base = False
          except:
              raise TypeError('time_pipeline needs the first argument to be an iterable or a function that produces an iterable.')
      # if iterable is not a function, load the whole thing
      # into a list so it can be ran over multiple times
      if not callable_base:
          iterable = tuple(iterable)
      # these store timestamps for time calculations
      durations = []
      results = []
      for i,_ in enumerate(steps):
          current_tasks = steps[:i+1]
          #print('testing',current_tasks)
          duration = 0.0
          # run this test x number of times
          for t in range(100000):
              # build the generator
              test_generator = iter(iterable()) if callable_base else iter(iterable)
              # time its execution
              start = ts()
              for task in current_tasks:
                  test_generator = task(test_generator)
              for i in current_tasks[-1](test_generator):
                  pass
              duration += ts() - start
          durations.append(duration)
          if len(durations) == 1:
              results.append(durations[0])
              #print(durations[0],durations[0])
          else:
              results.append(durations[-1]-durations[-2])
              #print(durations[-1]-durations[-2],durations[-1])
      #print(results)
      #print(durations)
      assert sum(results) > 0
      resultsum = sum(results)
      ratios = [i/resultsum for i in results]
      #print(ratios)
      for i in range(len(ratios)):
          try:
              s = getsource(steps[i]).splitlines()[0].strip()
          except:
              s = repr(steps[i]).strip()
          print('step {} | {:2.4f}s | {}'.format(i+1, durations[i], s))