1""" 2Sebastian Raschka 2014-2017 3Python Progress Indicator Utility 4 5Author: Sebastian Raschka <sebastianraschka.com> 6License: BSD 3 clause 7 8Contributors: https://github.com/rasbt/pyprind/graphs/contributors 9Code Repository: https://github.com/rasbt/pyprind 10PyPI: https://pypi.python.org/pypi/PyPrind 11""" 12 13 14import time 15import sys 16import os 17from io import UnsupportedOperation 18 19try: 20 import psutil 21 psutil_import = True 22except ImportError: 23 psutil_import = False 24 25 26class Prog(): 27 def __init__(self, iterations, track_time, stream, title, 28 monitor, update_interval=None): 29 """ Initializes tracking object. """ 30 self.cnt = 0 31 self.title = title 32 self.max_iter = float(iterations) # to support Python 2.x 33 self.track = track_time 34 self.start = time.time() 35 self.end = None 36 self.item_id = None 37 self.eta = None 38 self.total_time = 0.0 39 self.last_time = self.start 40 self.monitor = monitor 41 self.stream = stream 42 self.active = True 43 self._stream_out = self._no_stream 44 self._stream_flush = self._no_stream 45 self._check_stream() 46 self._print_title() 47 self.update_interval = update_interval 48 self._cached_output = '' 49 50 sys.stdout.flush() 51 sys.stderr.flush() 52 53 if monitor: 54 if not psutil_import: 55 raise ValueError('psutil package is required when using' 56 ' the `monitor` option.') 57 else: 58 self.process = psutil.Process() 59 if self.track: 60 self.eta = 1 61 62 def update(self, iterations=1, item_id=None, force_flush=False): 63 """ 64 Updates the progress bar / percentage indicator. 65 66 Parameters 67 ---------- 68 iterations : int (default: 1) 69 default argument can be changed to integer values 70 >=1 in order to update the progress indicators more than once 71 per iteration. 72 item_id : str (default: None) 73 Print an item_id sring behind the progress bar 74 force_flush : bool (default: False) 75 If True, flushes the progress indicator to the output screen 76 in each iteration. 77 78 """ 79 self.item_id = item_id 80 self.cnt += iterations 81 self._print(force_flush=force_flush) 82 self._finish() 83 84 def stop(self): 85 """Stops the progress bar / percentage indicator if necessary.""" 86 self.cnt = self.max_iter 87 self._finish() 88 89 def _check_stream(self): 90 """Determines which output stream (stdout, stderr, or custom) to use""" 91 if self.stream: 92 93 try: 94 supported = ('PYCHARM_HOSTED' in os.environ or 95 os.isatty(sys.stdout.fileno())) 96 97 except AttributeError: 98 supported = False 99 100 # a fix for IPython notebook "IOStream has no fileno." 101 except(UnsupportedOperation): 102 supported = True 103 104 else: 105 if self.stream is not None and hasattr(self.stream, 'write'): 106 self._stream_out = self.stream.write 107 self._stream_flush = self.stream.flush 108 109 if supported: 110 if self.stream == 1: 111 self._stream_out = sys.stdout.write 112 self._stream_flush = sys.stdout.flush 113 elif self.stream == 2: 114 self._stream_out = sys.stderr.write 115 self._stream_flush = sys.stderr.flush 116 else: 117 if self.stream is not None and hasattr(self.stream, 'write'): 118 self._stream_out = self.stream.write 119 self._stream_flush = self.stream.flush 120 else: 121 print('Warning: No valid output stream.') 122 123 def _elapsed(self): 124 """ Returns elapsed time at update. """ 125 self.last_time = time.time() 126 return self.last_time - self.start 127 128 def _calc_eta(self): 129 """ Calculates estimated time left until completion. """ 130 elapsed = self._elapsed() 131 if self.cnt == 0 or elapsed < 0.001: 132 return None 133 rate = float(self.cnt) / elapsed 134 self.eta = (float(self.max_iter) - float(self.cnt)) / rate 135 136 def _calc_percent(self): 137 """Calculates the rel. progress in percent with 2 decimal points.""" 138 return round(self.cnt / self.max_iter * 100, 2) 139 140 def _no_stream(self, text=None): 141 """ Called when no valid output stream is available. """ 142 pass 143 144 def _get_time(self, _time): 145 if (_time < 86400): 146 return time.strftime("%H:%M:%S", time.gmtime(_time)) 147 else: 148 s = (str(int(_time // 3600)) + ':' + 149 time.strftime("%M:%S", time.gmtime(_time))) 150 return s 151 152 def _finish(self): 153 """ Determines if maximum number of iterations (seed) is reached. """ 154 if self.active and self.cnt >= self.max_iter: 155 self.total_time = self._elapsed() 156 self.end = time.time() 157 self.last_progress -= 1 # to force a refreshed _print() 158 self._print() 159 if self.track: 160 self._stream_out('\nTotal time elapsed: ' + 161 self._get_time(self.total_time)) 162 self._stream_out('\n') 163 self.active = False 164 165 def _print_title(self): 166 """ Prints tracking title at initialization. """ 167 if self.title: 168 self._stream_out('{}\n'.format(self.title)) 169 self._stream_flush() 170 171 def _cache_eta(self): 172 """ Prints the estimated time left.""" 173 self._calc_eta() 174 self._cached_output += ' | ETA: ' + self._get_time(self.eta) 175 176 def _cache_item_id(self): 177 """ Prints an item id behind the tracking object.""" 178 self._cached_output += ' | Item ID: %s' % self.item_id 179 180 def __repr__(self): 181 str_start = time.strftime('%m/%d/%Y %H:%M:%S', 182 time.localtime(self.start)) 183 str_end = time.strftime('%m/%d/%Y %H:%M:%S', 184 time.localtime(self.end)) 185 self._stream_flush() 186 187 time_info = 'Title: {}\n'\ 188 ' Started: {}\n'\ 189 ' Finished: {}\n'\ 190 ' Total time elapsed: '.format(self.title, 191 str_start, 192 str_end)\ 193 + self._get_time(self.total_time) 194 if self.monitor: 195 try: 196 cpu_total = self.process.cpu_percent() 197 mem_total = self.process.memory_percent() 198 except AttributeError: # old version of psutil 199 cpu_total = self.process.get_cpu_percent() 200 mem_total = self.process.get_memory_percent() 201 202 cpu_mem_info = ' CPU %: {:.2f}\n'\ 203 ' Memory %: {:.2f}'.format(cpu_total, mem_total) 204 205 return time_info + '\n' + cpu_mem_info 206 else: 207 return time_info 208 209 def __str__(self): 210 return self.__repr__() 211