|
''' |
|
Utilities for showing progress bars, controlling default verbosity, etc. |
|
''' |
|
|
|
|
|
|
|
import sys, types, builtins |
|
try: |
|
from tqdm import tqdm |
|
try: |
|
from tqdm.notebook import tqdm as tqdm_nb |
|
except: |
|
from tqdm import tqdm_notebook as tqdm_nb |
|
except: |
|
tqdm = None |
|
|
|
default_verbosity = True |
|
next_description = None |
|
python_print = builtins.print |
|
|
|
def post(**kwargs): |
|
''' |
|
When within a progress loop, pbar.post(k=str) will display |
|
the given k=str status on the right-hand-side of the progress |
|
status bar. If not within a visible progress bar, does nothing. |
|
''' |
|
innermost = innermost_tqdm() |
|
if innermost is not None: |
|
innermost.set_postfix(**kwargs) |
|
|
|
def desc(desc): |
|
''' |
|
When within a progress loop, pbar.desc(str) changes the |
|
left-hand-side description of the loop toe the given description. |
|
''' |
|
innermost = innermost_tqdm() |
|
if innermost is not None: |
|
innermost.set_description(str(desc)) |
|
|
|
def descnext(desc): |
|
''' |
|
Called before starting a progress loop, pbar.descnext(str) |
|
sets the description text that will be used in the following loop. |
|
''' |
|
global next_description |
|
if not default_verbosity or tqdm is None: |
|
return |
|
next_description = desc |
|
|
|
def print(*args): |
|
''' |
|
When within a progress loop, will print above the progress loop. |
|
''' |
|
global next_description |
|
next_description = None |
|
if default_verbosity: |
|
msg = ' '.join(str(s) for s in args) |
|
if tqdm is None: |
|
python_print(msg) |
|
else: |
|
tqdm.write(msg) |
|
|
|
def tqdm_terminal(it, *args, **kwargs): |
|
''' |
|
Some settings for tqdm that make it run better in resizable terminals. |
|
''' |
|
return tqdm(it, *args, dynamic_ncols=True, ascii=True, |
|
leave=(innermost_tqdm() is not None), **kwargs) |
|
|
|
def in_notebook(): |
|
''' |
|
True if running inside a Jupyter notebook. |
|
''' |
|
|
|
try: |
|
shell = get_ipython().__class__.__name__ |
|
if shell == 'ZMQInteractiveShell': |
|
return True |
|
elif shell == 'TerminalInteractiveShell': |
|
return False |
|
else: |
|
return False |
|
except NameError: |
|
return False |
|
|
|
def innermost_tqdm(): |
|
''' |
|
Returns the innermost active tqdm progress loop on the stack. |
|
''' |
|
if hasattr(tqdm, '_instances') and len(tqdm._instances) > 0: |
|
return max(tqdm._instances, key=lambda x: x.pos) |
|
else: |
|
return None |
|
|
|
def reporthook(*args, **kwargs): |
|
''' |
|
For use with urllib.request.urlretrieve. |
|
|
|
with pbar.reporthook() as hook: |
|
urllib.request.urlretrieve(url, filename, reporthook=hook) |
|
''' |
|
kwargs2 = dict(unit_scale=True, miniters=1) |
|
kwargs2.update(kwargs) |
|
bar = __call__(None, *args, **kwargs2) |
|
class ReportHook(object): |
|
def __init__(self, t): |
|
self.t = t |
|
def __call__(self, b=1, bsize=1, tsize=None): |
|
if hasattr(self.t, 'total'): |
|
if tsize is not None: |
|
self.t.total = tsize |
|
if hasattr(self.t, 'update'): |
|
self.t.update(b * bsize - self.t.n) |
|
def __enter__(self): |
|
return self |
|
def __exit__(self, *exc): |
|
if hasattr(self.t, '__exit__'): |
|
self.t.__exit__(*exc) |
|
return ReportHook(bar) |
|
|
|
def __call__(x, *args, **kwargs): |
|
''' |
|
Invokes a progress function that can wrap iterators to print |
|
progress messages, if verbose is True. |
|
|
|
If verbose is False or tqdm is unavailable, then a quiet |
|
non-printing identity function is used. |
|
|
|
verbose can also be set to a spefific progress function rather |
|
than True, and that function will be used. |
|
''' |
|
global default_verbosity, next_description |
|
if not default_verbosity or tqdm is None: |
|
return x |
|
if default_verbosity == True: |
|
fn = tqdm_nb if in_notebook() else tqdm_terminal |
|
else: |
|
fn = default_verbosity |
|
if next_description is not None: |
|
kwargs = dict(kwargs) |
|
kwargs['desc'] = next_description |
|
next_description = None |
|
return fn(x, *args, **kwargs) |
|
|
|
class VerboseContextManager(): |
|
def __init__(self, v, entered=False): |
|
self.v, self.entered, self.saved = v, False, [] |
|
if entered: |
|
self.__enter__() |
|
self.entered = True |
|
def __enter__(self): |
|
global default_verbosity |
|
if self.entered: |
|
self.entered = False |
|
else: |
|
self.saved.append(default_verbosity) |
|
default_verbosity = self.v |
|
return self |
|
def __exit__(self, exc_type, exc_value, exc_traceback): |
|
global default_verbosity |
|
default_verbosity = self.saved.pop() |
|
def __call__(self, v=True): |
|
''' |
|
Calling the context manager makes a new context that is |
|
pre-entered, so it works as both a plain function and as a |
|
factory for a context manager. |
|
''' |
|
new_v = v if self.v else not v |
|
cm = VerboseContextManager(new_v, entered=True) |
|
default_verbosity = new_v |
|
return cm |
|
|
|
|
|
|
|
verbose = VerboseContextManager(True) |
|
|
|
|
|
|
|
quiet = VerboseContextManager(False) |
|
|
|
class CallableModule(types.ModuleType): |
|
def __init__(self): |
|
|
|
types.ModuleType.__init__(self, __name__) |
|
self.__dict__.update(sys.modules[__name__].__dict__) |
|
def __call__(self, x, *args, **kwargs): |
|
return __call__(x, *args, **kwargs) |
|
|
|
sys.modules[__name__] = CallableModule() |
|
|
|
|