Source code for nnsa.utils.other

"""
Utils that do not need their own category.
"""
import datetime
import sys
import time
import traceback
import numpy as np

from ast import literal_eval
from termcolor import cprint

__all__ = [
    'convert_string',
    'convert_string_auto',
    'enumerate_label',
    'iqr',
    'is_numeric',
    'print_exception_info',
]


[docs]def convert_string(value, target_type): """ Convert a string to the specified data type. Supported types: strings, numbers, tuples, lists, dicts, booleans, and None. Args: value (str): string to be converted. target_type (str): string specifying the type to convert the string to (from type(a).__name__) Returns: converted_value: value converted to corresponding data type. """ # Verify input is a string. if type(value) is not str: raise TypeError('Invalid type {}. Expected str.'.format(type(value))) # None. if target_type == 'NoneType': converted_value = None # NaN. elif target_type in ['int', 'float'] and value == 'nan': converted_value = np.nan # String. elif target_type == 'str': converted_value = value # Use literal_eval, which converts strings, numbers, tuples, lists, dicts, booleans, and None. elif target_type in ['int', 'float', 'tuple', 'list', 'dict', 'bool']: converted_value = literal_eval(value) elif target_type == 'type' and "<class 'numpy.float" in value: # We have a type parameter specifying a numpy float type. We convert it to a string, e.g. 'np.float32'. v = value.replace('<class ', '').replace('>', '').replace("'", "").replace('numpy', 'np') converted_value = eval(v) else: raise NotImplementedError('Unsupported target type "{}".'.format(target_type)) return converted_value
[docs]def convert_string_auto(value): """ Convert a string to the corresponding data type, automatically chosing the data type. Supported types: strings, numbers, tuples, lists, dicts, booleans, and None. Note that if the first character of value is alphabetical, it is considered a string, unless its 'False', 'True', or 'None'. E.g. a = convert_string('10') print(a) # 10 print(type(a)) # <class 'int'> Args: value (str): string to be converted. Returns: converted_value: value converted to corresponding data type. """ # Verify input is a string. if type(value) is not str: raise TypeError('Invalid type {}. Expected str.'.format(type(value))) # Convert empty strings and 'None' to None. if not value or value == 'None': # value is an empty string. converted_value = None # Check if value is bool. elif value == 'False': converted_value = False elif value == 'True': converted_value = True # Check if value is a string by checking if the first character is alphabetic. elif value[0].isalpha(): converted_value = value # Use literal_eval, which converts strings, numbers, tuples, lists, dicts, booleans, and None. else: converted_value = literal_eval(value) return converted_value
[docs]def enumerate_label(n, label='Label'): """ Enumerate n labels with text label. Args: n (int): number of labels to create. label (str, optional): label text. Returns: (list of str): enumerated labels. """ return ['{} {}'.format(label, i+1) for i in range(n)]
[docs]def iqr(x, *args, **kwargs): """ Compute the inter quartile range. Ignores nan values. Args: x (np.ndarray): array with the data. *args (optional): positional arguments for np.percentile. **kwargs (optional): keyword arguments for np.percentile. Returns: (float): IQR. """ q75, q25 = np.nanpercentile(x, [75, 25], *args, **kwargs) return q75 - q25
[docs]def is_numeric(s): """ Check if a string is numeric. Args: s (str): string to check. Returns: (bool): True or False indicating whether the string is a number. """ try: float(s) return True except ValueError: return False
class Logger(object): """ Print both to output window and a log file. From https://stackoverflow.com/questions/14906764/how-to-redirect-stdout-to-both-file-and-console-with-scripting """ def __init__(self, log_fp=None): if log_fp is None: unid = datetime.datetime.now().strftime('%y%m%d%H%M%S') log_fp = 'logs_{}.log'.format(unid) self.terminal = sys.stdout self.log = open(log_fp, "a") def write(self, message): self.terminal.write(message) self.log.write(message) def flush(self): # this flush method is needed for python 3 compatibility. # this handles the flush command by doing nothing. # you might want to specify some extra behavior here. pass def print_to_all(msg, *args): """ Print message to all outputs. Will direct stdout to each of the element in *args and print the message. In the end will set stdout to the original one (the one that was active when calling the function). Args: msg (str): message to print. *args: all outputs to print to. """ for out in args: print(msg, file=out)