diff options
| author | kotfu <kotfu@kotfu.net> | 2018-05-06 17:55:30 -0600 |
|---|---|---|
| committer | kotfu <kotfu@kotfu.net> | 2018-05-06 17:55:30 -0600 |
| commit | fc495a4201cee744807bee058115824287cd6b33 (patch) | |
| tree | e3d6e644360c2a874b201348ee10eb0f6a401ed8 /cmd2 | |
| parent | 09abad2aa79bc7b591448943a2e01a261e053b0f (diff) | |
| download | cmd2-git-fc495a4201cee744807bee058115824287cd6b33.tar.gz | |
Move more code from cmd2.py into utils.py
Diffstat (limited to 'cmd2')
| -rwxr-xr-x | cmd2/cmd2.py | 102 | ||||
| -rw-r--r-- | cmd2/utils.py | 89 |
2 files changed, 93 insertions, 98 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index c90d7dab..7547c012 100755 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -125,17 +125,6 @@ def categorize(func: Union[Callable, Iterable], category: str) -> None: else: setattr(func, HELP_CATEGORY, category) - -def _which(editor: str) -> Optional[str]: - import subprocess - try: - editor_path = subprocess.check_output(['which', editor], stderr=subprocess.STDOUT).strip() - editor_path = editor_path.decode() - except subprocess.CalledProcessError: - editor_path = None - return editor_path - - def parse_quoted_string(cmdline: str) -> List[str]: """Parse a quoted string into a list of arguments.""" if isinstance(cmdline, list): @@ -347,7 +336,7 @@ class Cmd(cmd.Cmd): else: # Favor command-line editors first so we don't leave the terminal to edit for editor in ['vim', 'vi', 'emacs', 'nano', 'pico', 'gedit', 'kate', 'subl', 'geany', 'atom']: - if _which(editor): + if utils.which(editor): break feedback_to_output = False # Do not include nonessentials in >, | output by default (things like timing) locals_in_py = False @@ -2437,7 +2426,7 @@ Usage: Usage: unalias [-a] name [name ...] if (val[0] == val[-1]) and val[0] in ("'", '"'): val = val[1:-1] else: - val = cast(current_val, val) + val = utils.cast(current_val, val) setattr(self, param_name, val) self.poutput('%s - was: %s\nnow: %s\n' % (param_name, current_val, val)) if current_val != val: @@ -2865,7 +2854,7 @@ Script should contain one command per line, just like command would be typed in return # Make sure the file is ASCII or UTF-8 encoded text - if not self.is_text_file(expanded_path): + if not utils.is_text_file(expanded_path): self.perror('{} is not an ASCII or UTF-8 encoded text file'.format(expanded_path), traceback_war=False) return @@ -2886,42 +2875,6 @@ Script should contain one command per line, just like command would be typed in index_dict = {1: self.path_complete} return self.index_based_complete(text, line, begidx, endidx, index_dict) - @staticmethod - def is_text_file(file_path): - """ - Returns if a file contains only ASCII or UTF-8 encoded text - :param file_path: path to the file being checked - """ - import codecs - - expanded_path = os.path.abspath(os.path.expanduser(file_path.strip())) - valid_text_file = False - - # Check if the file is ASCII - try: - with codecs.open(expanded_path, encoding='ascii', errors='strict') as f: - # Make sure the file has at least one line of text - # noinspection PyUnusedLocal - if sum(1 for line in f) > 0: - valid_text_file = True - except IOError: # pragma: no cover - pass - except UnicodeDecodeError: - # The file is not ASCII. Check if it is UTF-8. - try: - with codecs.open(expanded_path, encoding='utf-8', errors='strict') as f: - # Make sure the file has at least one line of text - # noinspection PyUnusedLocal - if sum(1 for line in f) > 0: - valid_text_file = True - except IOError: # pragma: no cover - pass - except UnicodeDecodeError: - # Not UTF-8 - pass - - return valid_text_file - def run_transcript_tests(self, callargs): """Runs transcript tests for provided file(s). @@ -3119,36 +3072,6 @@ class History(list): return [itm for itm in self if isin(itm)] -def cast(current, new): - """Tries to force a new value into the same type as the current when trying to set the value for a parameter. - - :param current: current value for the parameter, type varies - :param new: str - new value - :return: new value with same type as current, or the current value if there was an error casting - """ - typ = type(current) - if typ == bool: - try: - return bool(int(new)) - except (ValueError, TypeError): - pass - try: - new = new.lower() - except AttributeError: - pass - if (new == 'on') or (new[0] in ('y', 't')): - return True - if (new == 'off') or (new[0] in ('n', 'f')): - return False - else: - try: - return typ(new) - except (ValueError, TypeError): - pass - print("Problem setting parameter (now %s) to %s; incorrect type?" % (current, new)) - return current - - class Statekeeper(object): """Class used to save and restore state during load and py commands as well as when redirecting output or pipes.""" def __init__(self, obj, attribs): @@ -3174,22 +3097,7 @@ class Statekeeper(object): setattr(self.obj, attrib, getattr(self, attrib)) -def namedtuple_with_two_defaults(typename, field_names, default_values=('', '')): - """Wrapper around namedtuple which lets you treat the last value as optional. - - :param typename: str - type name for the Named tuple - :param field_names: List[str] or space-separated string of field names - :param default_values: (optional) 2-element tuple containing the default values for last 2 parameters in named tuple - Defaults to an empty string for both of them - :return: namedtuple type - """ - T = collections.namedtuple(typename, field_names) - # noinspection PyUnresolvedReferences - T.__new__.__defaults__ = default_values - return T - - -class CmdResult(namedtuple_with_two_defaults('CmdResult', ['out', 'err', 'war'])): +class CmdResult(utils.namedtuple_with_two_defaults('CmdResult', ['out', 'err', 'war'])): """Derive a class to store results from a named tuple so we can tweak dunder methods for convenience. This is provided as a convenience and an example for one possible way for end users to store results in @@ -3209,5 +3117,3 @@ class CmdResult(namedtuple_with_two_defaults('CmdResult', ['out', 'err', 'war']) def __bool__(self): """If err is an empty string, treat the result as a success; otherwise treat it as a failure.""" return not self.err - - diff --git a/cmd2/utils.py b/cmd2/utils.py index dbe39213..a61fd5fd 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -3,6 +3,9 @@ """Shared utility functions""" import collections +import os +from typing import Optional + from . import constants def strip_ansi(text: str) -> str: @@ -55,3 +58,89 @@ def namedtuple_with_defaults(typename, field_names, default_values=()): T.__new__.__defaults__ = tuple(prototype) return T +def namedtuple_with_two_defaults(typename, field_names, default_values=('', '')): + """Wrapper around namedtuple which lets you treat the last value as optional. + + :param typename: str - type name for the Named tuple + :param field_names: List[str] or space-separated string of field names + :param default_values: (optional) 2-element tuple containing the default values for last 2 parameters in named tuple + Defaults to an empty string for both of them + :return: namedtuple type + """ + T = collections.namedtuple(typename, field_names) + # noinspection PyUnresolvedReferences + T.__new__.__defaults__ = default_values + return T + +def cast(current, new): + """Tries to force a new value into the same type as the current when trying to set the value for a parameter. + + :param current: current value for the parameter, type varies + :param new: str - new value + :return: new value with same type as current, or the current value if there was an error casting + """ + typ = type(current) + if typ == bool: + try: + return bool(int(new)) + except (ValueError, TypeError): + pass + try: + new = new.lower() + except AttributeError: + pass + if (new == 'on') or (new[0] in ('y', 't')): + return True + if (new == 'off') or (new[0] in ('n', 'f')): + return False + else: + try: + return typ(new) + except (ValueError, TypeError): + pass + print("Problem setting parameter (now %s) to %s; incorrect type?" % (current, new)) + return current + +def which(editor: str) -> Optional[str]: + import subprocess + try: + editor_path = subprocess.check_output(['which', editor], stderr=subprocess.STDOUT).strip() + editor_path = editor_path.decode() + except subprocess.CalledProcessError: + editor_path = None + return editor_path + +def is_text_file(file_path): + """ + Returns if a file contains only ASCII or UTF-8 encoded text + :param file_path: path to the file being checked + """ + import codecs + + expanded_path = os.path.abspath(os.path.expanduser(file_path.strip())) + valid_text_file = False + + # Check if the file is ASCII + try: + with codecs.open(expanded_path, encoding='ascii', errors='strict') as f: + # Make sure the file has at least one line of text + # noinspection PyUnusedLocal + if sum(1 for line in f) > 0: + valid_text_file = True + except IOError: # pragma: no cover + pass + except UnicodeDecodeError: + # The file is not ASCII. Check if it is UTF-8. + try: + with codecs.open(expanded_path, encoding='utf-8', errors='strict') as f: + # Make sure the file has at least one line of text + # noinspection PyUnusedLocal + if sum(1 for line in f) > 0: + valid_text_file = True + except IOError: # pragma: no cover + pass + except UnicodeDecodeError: + # Not UTF-8 + pass + + return valid_text_file |
