diff --git a/NEWS.rst b/NEWS.rst index 3c7db04..592a15d 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -31,6 +31,11 @@ Bug Fixes * `hy2py` can now handle format strings. * Fixed crashes from inaccessible history files. +Misc. Improvements +------------------------------ +* Drop the use of the long-abandoned `clint `_ library + for colors. `colorama `_ is now used instead. + 0.17.0 ============================== diff --git a/docs/language/internals.rst b/docs/language/internals.rst index 2fb29bc..ec52c5f 100644 --- a/docs/language/internals.rst +++ b/docs/language/internals.rst @@ -44,9 +44,9 @@ If this is causing issues, it can be turned off globally by setting ``hy.models.PRETTY`` to ``False``, or temporarily by using the ``hy.models.pretty`` context manager. -Hy also attempts to color pretty reprs using ``clint.textui.colored``. -This module has a flag to disable coloring, -and a method ``clean`` to strip colored strings of their color tags. +Hy also attempts to color pretty reprs and errors using ``colorama``. These can +be turned off globally by setting ``hy.models.COLORED`` and ``hy.errors.COLORED``, +respectively, to ``False``. .. _hysequence: diff --git a/hy/cmdline.py b/hy/cmdline.py index 4c0c1fa..9ccb644 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -4,6 +4,9 @@ from __future__ import print_function +import colorama +colorama.init() + import argparse import code import ast diff --git a/hy/errors.py b/hy/errors.py index 0b7619e..c19cf6c 100644 --- a/hy/errors.py +++ b/hy/errors.py @@ -9,14 +9,13 @@ import traceback import pkgutil from functools import reduce +from colorama import Fore from contextlib import contextmanager from hy import _initialize_env_var -from clint.textui import colored - _hy_filter_internal_errors = _initialize_env_var('HY_FILTER_INTERNAL_ERRORS', True) -_hy_colored_errors = _initialize_env_var('HY_COLORED_ERRORS', False) +COLORED = _initialize_env_var('HY_COLORED_ERRORS', False) class HyError(Exception): @@ -108,15 +107,12 @@ class HyLanguageError(HyError): """Provide an exception message that includes SyntaxError-like source line information when available. """ - global _hy_colored_errors - # Syntax errors are special and annotate the traceback (instead of what # we would do in the message that follows the traceback). if isinstance(self, SyntaxError): return super(HyLanguageError, self).__str__() - # When there isn't extra source information, use the normal message. - if not isinstance(self, SyntaxError) and not self.text: + elif not self.text: return super(HyLanguageError, self).__str__() # Re-purpose Python's builtin syntax error formatting. @@ -142,15 +138,14 @@ class HyLanguageError(HyError): output[arrow_idx] = '{}{}^\n'.format(output[arrow_idx].rstrip('\n'), '-' * (self.arrow_offset - 1)) - if _hy_colored_errors: - from clint.textui import colored - output[msg_idx:] = [colored.yellow(o) for o in output[msg_idx:]] + if COLORED: + output[msg_idx:] = [Fore.YELLOW + o + Fore.RESET for o in output[msg_idx:]] if arrow_idx: - output[arrow_idx] = colored.green(output[arrow_idx]) + output[arrow_idx] = Fore.GREEN + output[arrow_idx] + Fore.RESET for idx, line in enumerate(output[::msg_idx]): if line.strip().startswith( 'File "{}", line'.format(self.filename)): - output[idx] = colored.red(line) + output[idx] = Fore.RED + line + Fore.RESET # This resulting string will come after a ":" prompt, so # put it down a line. diff --git a/hy/models.py b/hy/models.py index 55d0b79..6f42815 100644 --- a/hy/models.py +++ b/hy/models.py @@ -8,10 +8,10 @@ from math import isnan, isinf from hy import _initialize_env_var from hy.errors import HyWrapperError from fractions import Fraction -from clint.textui import colored +from colorama import Fore PRETTY = True -_hy_colored_ast_objects = _initialize_env_var('HY_COLORED_AST_OBJECTS', False) +COLORED = _initialize_env_var('HY_COLORED_AST_OBJECTS', False) @contextmanager @@ -28,6 +28,18 @@ def pretty(pretty=True): PRETTY = old +class _ColoredModel: + """ + Mixin that provides a helper function for models that have color. + """ + + def _colored(self, text): + if COLORED: + return self.color + text + Fore.RESET + else: + return text + + class HyObject(object): """ Generic Hy Object model. This is helpful to inject things into all the @@ -243,7 +255,7 @@ class HyComplex(HyObject, complex): _wrappers[complex] = HyComplex -class HySequence(HyObject, tuple): +class HySequence(HyObject, tuple, _ColoredModel): """ An abstract type for sequence-like models to inherit from. """ @@ -276,21 +288,25 @@ class HySequence(HyObject, tuple): return str(self) if PRETTY else super(HySequence, self).__repr__() def __str__(self): - global _hy_colored_ast_objects with pretty(): - c = self.color if _hy_colored_ast_objects else str if self: - return ("{}{}\n {}{}").format( - c(self.__class__.__name__), - c("(["), - (c(",") + "\n ").join([repr_indent(e) for e in self]), - c("])")) + return self._colored("{}{}\n {}{}".format( + self._colored(self.__class__.__name__), + self._colored("(["), + self._colored(",\n ").join(map(repr_indent, self)), + self._colored("])"), + )) + return self._colored("{}([\n {}])".format( + self.__class__.__name__, + ','.join(repr_indent(e) for e in self), + )) else: - return '' + c(self.__class__.__name__ + "()") + return self._colored(self.__class__.__name__ + "()") class HyList(HySequence): - color = staticmethod(colored.cyan) + color = Fore.CYAN + def recwrap(f): return lambda l: f(wrap_value(x) for x in l) @@ -300,16 +316,14 @@ _wrappers[list] = recwrap(HyList) _wrappers[tuple] = recwrap(HyList) -class HyDict(HySequence): +class HyDict(HySequence, _ColoredModel): """ HyDict (just a representation of a dict) """ - color = staticmethod(colored.green) + color = Fore.GREEN def __str__(self): - global _hy_colored_ast_objects with pretty(): - g = self.color if _hy_colored_ast_objects else str if self: pairs = [] for k, v in zip(self[::2],self[1::2]): @@ -317,14 +331,16 @@ class HyDict(HySequence): pairs.append( ("{0}{c}\n {1}\n " if '\n' in k+v - else "{0}{c} {1}").format(k, v, c=g(','))) + else "{0}{c} {1}").format(k, v, c=self._colored(','))) if len(self) % 2 == 1: pairs.append("{} {}\n".format( - repr_indent(self[-1]), g("# odd"))) + repr_indent(self[-1]), self._colored("# odd"))) return "{}\n {}{}".format( - g("HyDict(["), ("{c}\n ".format(c=g(',')).join(pairs)), g("])")) + self._colored("HyDict(["), + "{c}\n ".format(c=self._colored(',')).join(pairs), + self._colored("])")) else: - return '' + g("HyDict()") + return self._colored("HyDict()") def keys(self): return list(self[0::2]) @@ -343,7 +359,7 @@ class HyExpression(HySequence): """ Hy S-Expression. Basically just a list. """ - color = staticmethod(colored.yellow) + color = Fore.YELLOW _wrappers[HyExpression] = recwrap(HyExpression) _wrappers[Fraction] = lambda e: HyExpression( @@ -354,7 +370,7 @@ class HySet(HySequence): """ Hy set (just a representation of a set) """ - color = staticmethod(colored.red) + color = Fore.RED _wrappers[HySet] = recwrap(HySet) _wrappers[set] = recwrap(HySet) diff --git a/setup.py b/setup.py index 9499601..eaebf95 100755 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ install_requires = [ 'rply>=0.7.7', 'astor>=0.8', 'funcparserlib>=0.3.6', - 'clint>=0.4'] + 'colorama'] if os.name == 'nt': install_requires.append('pyreadline>=2.1') diff --git a/tests/test_models.py b/tests/test_models.py index 52d4518..3670974 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -4,10 +4,11 @@ import copy import hy -from clint.textui.colored import clean from hy.models import (wrap_value, replace_hy_obj, HyString, HyInteger, HyList, HyDict, HySet, HyExpression, HyComplex, HyFloat, pretty) +hy.models.COLORED = False + def test_wrap_int(): """ Test conversion of integers.""" @@ -182,13 +183,13 @@ def test_compound_model_repr(): assert eval(repr(model([1, 2, 3]))) == model([1, 2, 3]) for k, v in PRETTY_STRINGS.items(): # `str` should be pretty, even under `pretty(False)`. - assert clean(str(hy.read_str(k))) == v + assert str(hy.read_str(k)) == v for k in PRETTY_STRINGS.keys(): assert eval(repr(hy.read_str(k))) == hy.read_str(k) with pretty(True): for model in HY_LIST_MODELS: - assert eval(clean(repr(model()))).__class__ is model - assert eval(clean(repr(model([1, 2])))) == model([1, 2]) - assert eval(clean(repr(model([1, 2, 3])))) == model([1, 2, 3]) + assert eval(repr(model())).__class__ is model + assert eval(repr(model([1, 2]))) == model([1, 2]) + assert eval(repr(model([1, 2, 3]))) == model([1, 2, 3]) for k, v in PRETTY_STRINGS.items(): - assert clean(repr(hy.read_str(k))) == v + assert repr(hy.read_str(k)) == v