Source code for cratepy.ioput.ioutilities

"""I/O utility tools.

This module includes the '.screen' file path global definition as well as
several useful tools associated with input/output procedures.

Functions
---------
print2(*objects)
    Double output printer.
setdisplayfeatures()
    Set output display features.
escapeANSI(string)
    Remove ANSI escape sequences from string.
checknumber(x)
    Check if instance is or represents a number.
checkposint(x)
    Check if instance is a positive integer.
checkvalidname(x)
    Check if string contains only letters, numbers or underscores.
is_between(x, lower_bound=0, upper_bound=1)
    Check if numeric instance is between lower and upper values (included).
query_yn(question, default_answer='yes')
    Prompt the user to answer yes/no question.
"""
#
#                                                                       Modules
# =============================================================================
# Standard
import sys
import re
# Third-party
import numpy as np
#
#                                                          Authorship & Credits
# =============================================================================
__author__ = 'Bernardo Ferreira (bernardo_ferreira@brown.edu)'
__credits__ = ['Bernardo Ferreira', ]
__status__ = 'Stable'
# =============================================================================
#
# =============================================================================
# Set '.screen' file path as a global variable
screen_file_path = None
# =============================================================================
[docs]def print2(*objects): """Double output printer. Output to both default standard output device (e.g., terminal) and to the '.screen' output file. Parameters ---------- objects : list Objects to print. """ # Print to default sys.stdout print(*objects) # Print to '.screen' file global screen_file_path if screen_file_path is not None: screen_file = open(screen_file_path, 'a', encoding='utf-8') objects_esc = list() for i in range(len(objects)): objects_esc.append(escapeANSI(objects[i])) print(*objects_esc, file=screen_file) screen_file.close()
# =============================================================================
[docs]def setdisplayfeatures(): """Set output display features. Returns ------- display_features : tuple Output display features: * output_width (int) : \ Maximum line length of '.screen' output file. * dashed_line (str) : \ Dashed line of length `output_width`. * indent (str) : \ Indentation spacing. * asterisk_line (str) : \ Asterisks line of length `output_width`. * tilde_line (str) : \ Tildes line of length `output_width`. * equal_line (str) : \ Tildes line of length `output_width`. """ # Set display features output_width = 92 dashed_line = '-'*output_width indent = ' ' asterisk_line = '*'*output_width tilde_line = '~'*output_width equal_line = '='*output_width # Build display features display_features = (output_width, dashed_line, indent, asterisk_line, tilde_line, equal_line) # Return return display_features
# =============================================================================
[docs]def escapeANSI(string): """Remove ANSI escape sequences from string. Parameters ---------- string : str String. """ ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]') return ansi_escape.sub('', string)
# =============================================================================
[docs]def checknumber(x): """Check if instance is or represents a number. Parameters ---------- x Object. Returns ------- is_number : bool `True` if `x` is or represents a number, `False` otherwise. """ is_number = True try: float(x) return is_number except Exception: is_number = False return is_number
# ============================================================================= # Check if a given instance is a positive integer
[docs]def checkposint(x): """Check if instance is a positive integer. Parameters ---------- x Object. Returns ------- is_posint : bool `True` if `x` is a positive integer, `False` otherwise. """ is_posint = True if isinstance(x, int) or isinstance(x, np.integer): if x <= 0: is_posint = False elif not re.match('^[1-9][0-9]*$', str(x)): is_posint = False return is_posint
# =============================================================================
[docs]def checkvalidname(x): """Check if string contains only letters, numbers or underscores. Parameters ---------- x : str String. Returns ------- is_valid : bool `True` if `x` contains only letters, numbers or underscores, `False` otherwise. """ is_valid = True if not re.match('^[A-Za-z0-9_]+$', str(x)): is_valid = False return is_valid
# =============================================================================
[docs]def is_between(x, lower_bound=0, upper_bound=1): """Check if numeric instance is between lower and upper values (included). Parameters ---------- x : {int, float} Numerical type instance. lower_bound : {int, float}, default=0 Lower boundary value (included). upper_bound : {int, float}, default=1 Upper boundary value (included). Returns ------- bool : bool `True` if numeric instance is between lower and upper values, `False` otherwise. """ try: x = float(x) lower_bound = float(lower_bound) upper_bound = float(upper_bound) except ValueError: print('Instance and bounds must be of numeric type.') raise if lower_bound > upper_bound: raise RuntimeError('Lower boundary value (' + str(lower_bound) + ') must be greater or equal than the upper ' 'boundary value (' + str(upper_bound) + ').') if x >= lower_bound and x <= upper_bound: return True else: return False
# =============================================================================
[docs]def query_yn(question, default_answer='yes'): """Prompt the user to answer yes/no question. Parameters ---------- question : str Yes/No question. default_answer : {'yes', 'no'}, default='yes' Default answer to yes/no question. Returns ------- bool : bool `True` if answer if 'yes', `False` if anwers is 'no'. """ answer = {'yes': True, 'y': True, 'ye': True, 'no': False, 'n': False} if default_answer is None: prompt = ' [y/n] ' elif default_answer == 'yes': prompt = ' [Y/n] ' elif default_answer == 'no': prompt = ' [y/N] ' n_invalid_ans = 0 while True: option = input(question + prompt).lower() screen_file = open(screen_file_path, 'a') print(question + prompt + option, file=screen_file) screen_file.close() if default_answer is not None and option == '': return answer[default_answer] elif option in answer: return answer[option] else: n_invalid_ans = n_invalid_ans + 1 if n_invalid_ans > 3 or str(option).lower() == 'exit': print2('\nProgram aborted.\n') sys.exit(1) print2('Please answer with \'yes\' or \'no\' (or \'exit\' to ' 'quit).')
# =============================================================================
[docs]def useraction(message): """Prompt user to perform action before proceeding execution. Parameters ---------- message : str Prompt message. """ option = input(message) screen_file = open(screen_file_path, 'a') print(message + option, file=screen_file) screen_file.close() if str(option).lower() == 'exit': print2('\nProgram aborted.\n') sys.exit(1)