diff --git a/README.md b/README.md index 29850b0..31777f0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ lightweight, has zero dependencies and works across Python 2 and 3. [![Travis](https://img.shields.io/travis/ines/wasabi/master.svg?style=flat-square&logo=travis)](https://travis-ci.org/ines/wasabi) [![PyPi](https://img.shields.io/pypi/v/wasabi.svg?style=flat-square)](https://pypi.python.org/pypi/wasabi) [![GitHub](https://img.shields.io/github/release/ines/wasabi/all.svg?style=flat-square)](https://github.com/ines/wasabi) +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square)](https://github.com/ambv/black) diff --git a/setup.py b/setup.py index 12d3d77..fed79ad 100644 --- a/setup.py +++ b/setup.py @@ -7,35 +7,35 @@ def setup_package(): - package_name = 'wasabi' + package_name = "wasabi" root = Path(__file__).parent.resolve() # Read in package meta from about.py - about_path = root / package_name / 'about.py' - with about_path.open('r', encoding='utf8') as f: + about_path = root / package_name / "about.py" + with about_path.open("r", encoding="utf8") as f: about = {} exec(f.read(), about) # Get readme - readme_path = root / 'README.md' - with readme_path.open('r', encoding='utf8') as f: + readme_path = root / "README.md" + with readme_path.open("r", encoding="utf8") as f: readme = f.read() setup( name=package_name, - description=about['__summary__'], + description=about["__summary__"], long_description=readme, - long_description_content_type='text/markdown', - author=about['__author__'], - author_email=about['__email__'], - url=about['__uri__'], - version=about['__version__'], - license=about['__license__'], + long_description_content_type="text/markdown", + author=about["__author__"], + author_email=about["__email__"], + url=about["__uri__"], + version=about["__version__"], + license=about["__license__"], packages=find_packages(), install_requires=[], zip_safe=False, ) -if __name__ == '__main__': +if __name__ == "__main__": setup_package() diff --git a/tests/test_printer.py b/tests/test_printer.py index 8b58b2f..f2c6ed0 100644 --- a/tests/test_printer.py +++ b/tests/test_printer.py @@ -28,11 +28,12 @@ def test_printer_no_pretty(): def test_printer_custom(): - colors = {'yellow': 220, 'purple': 99} - icons = {'warn': '\u26a0\ufe0f', 'question': "?"} + colors = {"yellow": 220, "purple": 99} + icons = {"warn": "\u26a0\ufe0f", "question": "?"} p = Printer(no_print=True, colors=colors, icons=icons) text = "This is a test." - assert p.text(text, color='purple', icon='question') == "\x1b[38;5;99m? This is a test.\x1b[0m" + purple_questipn = p.text(text, color="purple", icon="question") + assert purple_question == "\x1b[38;5;99m? This is a test.\x1b[0m" assert p.warn(text) == "\x1b[38;5;3m\u26a0\ufe0f This is a test.\x1b[0m" @@ -53,16 +54,19 @@ def test_printer_counts(): def test_printer_divider(): p = Printer(line_max=20, no_print=True) p.divider() == "\x1b[1m\n================\x1b[0m" - p.divider('test') == "\x1b[1m\n====== test ======\x1b[0m" - p.divider('test', char='*') == "\x1b[1m\n****** test ******\x1b[0m" - p.divider('This is a very long text, it is very long') == "\x1b[1m\n This is a very long text, it is very long \x1b[0m" + p.divider("test") == "\x1b[1m\n====== test ======\x1b[0m" + p.divider("test", char="*") == "\x1b[1m\n****** test ******\x1b[0m" + assert ( + p.divider("This is a very long text, it is very long") + == "\x1b[1m\n This is a very long text, it is very long \x1b[0m" + ) with pytest.raises(ValueError): - p.divider('test', char='~.') + p.divider("test", char="~.") def test_printer_loading(): p = Printer() - print('\n') + print("\n") with p.loading("Loading..."): time.sleep(1) p.good("Success!") diff --git a/tests/test_util.py b/tests/test_util.py index 481bc37..fd15549 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -6,10 +6,12 @@ def test_color(): - assert color('test', fg='green') == '\x1b[38;5;2mtest\x1b[0m' - assert color('test', fg=4) == '\x1b[38;5;4mtest\x1b[0m' - assert color('test', bold=True) == '\x1b[1mtest\x1b[0m' - assert color('test', fg=7, bg='red', bold=True) == '\x1b[1;38;5;7;48;5;1mtest\x1b[0m' + assert color("test", fg="green") == "\x1b[38;5;2mtest\x1b[0m" + assert color("test", fg=4) == "\x1b[38;5;4mtest\x1b[0m" + assert color("test", bold=True) == "\x1b[1mtest\x1b[0m" + assert ( + color("test", fg=7, bg="red", bold=True) == "\x1b[1;38;5;7;48;5;1mtest\x1b[0m" + ) def test_wrap(): @@ -17,9 +19,12 @@ def test_wrap(): assert wrap(text, indent=0) == text assert wrap(text, indent=4) == " Hello world, this is a test." assert wrap(text, wrap_max=10, indent=0) == "Hello\nworld,\nthis is a\ntest." - assert wrap(text, wrap_max=5, indent=2) == " Hello\n world,\n this\n is\n a\n test." + assert ( + wrap(text, wrap_max=5, indent=2) + == " Hello\n world,\n this\n is\n a\n test." + ) -@pytest.mark.parametrize('text', ['abc', '\u2714 abc', '👻']) +@pytest.mark.parametrize("text", ["abc", "\u2714 abc", "👻"]) def test_locale_escape(text): assert locale_escape(text) diff --git a/wasabi/about.py b/wasabi/about.py index f647789..b77fa5b 100644 --- a/wasabi/about.py +++ b/wasabi/about.py @@ -1,7 +1,7 @@ -__title__ = 'wasabi' -__version__ = '0.0.3' -__summary__ = 'A lightweight console printing and formatting toolkit' -__uri__ = 'https://ines.io' -__author__ = 'Ines Montani' -__email__ = 'ines@explosion.ai' -__license__ = 'MIT' +__title__ = "wasabi" +__version__ = "0.0.3" +__summary__ = "A lightweight console printing and formatting toolkit" +__uri__ = "https://ines.io" +__author__ = "Ines Montani" +__email__ = "ines@explosion.ai" +__license__ = "MIT" diff --git a/wasabi/printer.py b/wasabi/printer.py index 7ee396e..d5d5398 100644 --- a/wasabi/printer.py +++ b/wasabi/printer.py @@ -14,9 +14,17 @@ class Printer(object): - def __init__(self, pretty=True, no_print=False, colors=None, icons=None, - line_max=80, animation='⠙⠹⠸⠼⠴⠦⠧⠇⠏', animation_ascii='|/-\\', - ignore_warnings=False): + def __init__( + self, + pretty=True, + no_print=False, + colors=None, + icons=None, + line_max=80, + animation="⠙⠹⠸⠼⠴⠦⠧⠇⠏", + animation_ascii="|/-\\", + ignore_warnings=False, + ): """Initialize the command-line printer. pretty (bool): Pretty-print output (colors, icons). @@ -50,23 +58,23 @@ def counts(self): """ return self._counts - def good(self, text='', show=True): + def good(self, text="", show=True): """Print a success message.""" return self._get_msg(text, style=MESSAGES.GOOD, show=show) - def fail(self, text='', show=True): + def fail(self, text="", show=True): """Print an error message.""" return self._get_msg(text, style=MESSAGES.FAIL, show=show) - def warn(self, text='', show=True): + def warn(self, text="", show=True): """Print a warning message.""" return self._get_msg(text, style=MESSAGES.WARN, show=show) - def info(self, text='', show=True): + def info(self, text="", show=True): """Print an error message.""" return self._get_msg(text, style=MESSAGES.INFO, show=show) - def text(self, text='', color=None, icon=None, show=True): + def text(self, text="", color=None, icon=None, show=True): """Print a message. text (unicode): The text to print. @@ -80,13 +88,13 @@ def text(self, text='', color=None, icon=None, show=True): if self.pretty and self.supports_ansi: color = self.colors.get(color) icon = self.icons.get(icon) - text = locale_escape('{} {}'.format(icon, text) if icon else text) + text = locale_escape("{} {}".format(icon, text) if icon else text) text = _color(text, fg=color) if self.no_print: return text print(text) - def divider(self, text='', char='=', show=True): + def divider(self, text="", char="=", show=True): """Print a divider with a headline: ============================ Headline here =========================== @@ -95,13 +103,16 @@ def divider(self, text='', char='=', show=True): show (bool): Whether to print or not. """ if len(char) != 1: - raise ValueError("Divider chars need to be one character long. " - "Received: {}".format(char)) + raise ValueError( + "Divider chars need to be one character long. " + "Received: {}".format(char) + ) if self.pretty: deco = char * (int(round((self.line_max - len(text))) / 2) - 2) - text = ' {} '.format(text) if text else '' - text = _color('\n{deco}{text}{deco}'.format(deco=deco, text=text), - bold=True) + text = " {} ".format(text) if text else "" + text = _color( + "\n{deco}{text}{deco}".format(deco=deco, text=text), bold=True + ) if len(text) < self.line_max: text = text + char * (self.line_max - len(text)) if self.no_print: @@ -109,18 +120,18 @@ def divider(self, text='', char='=', show=True): print(text) @contextmanager - def loading(self, text=''): + def loading(self, text=""): sys.stdout.flush() t = Process(target=self._spinner, args=(text,)) t.start() yield t.terminate() - sys.stdout.write('\r\x1b[2K') # erase line + sys.stdout.write("\r\x1b[2K") # erase line sys.stdout.flush() - def _spinner(self, text='Loading...'): + def _spinner(self, text="Loading..."): for char in itertools.cycle(self.anim): - sys.stdout.write('\r{} {}'.format(char, text)) + sys.stdout.write("\r{} {}".format(char, text)) sys.stdout.flush() time.sleep(0.1) @@ -137,18 +148,18 @@ def print_message(*texts, **kwargs): *texts (unicode): Texts to print. Each argument is rendered as paragraph. **kwargs: 'title' becomes headline. exits=1 performs sys exit. """ - exits = kwargs.get('exits') - indent = kwargs.get('indent', 4) - nowrap = kwargs.get('nowrap', False) - title = kwargs.get('title', None) - title_tpl = '{}\n' + exits = kwargs.get("exits") + indent = kwargs.get("indent", 4) + nowrap = kwargs.get("nowrap", False) + title = kwargs.get("title", None) + title_tpl = "{}\n" if nowrap: - title = title_tpl.format(title) if title else '' - message = '\n\n'.join(texts) + title = title_tpl.format(title) if title else "" + message = "\n\n".join(texts) else: - title = title_tpl.format(wrap(title, indent=indent)) if title else '' - message = '\n\n'.join([wrap(text, indent=indent) for text in texts]) - print('\n{}{}\n'.format(title, message)) + title = title_tpl.format(wrap(title, indent=indent)) if title else "" + message = "\n\n".join([wrap(text, indent=indent) for text in texts]) + print("\n{}{}\n".format(title, message)) if exits is not None: sys.stdout.flush() sys.stderr.flush() diff --git a/wasabi/util.py b/wasabi/util.py index b5ae141..65984aa 100644 --- a/wasabi/util.py +++ b/wasabi/util.py @@ -8,10 +8,10 @@ class MESSAGES(object): - GOOD = 'good' - FAIL = 'fail' - WARN = 'warn' - INFO = 'info' + GOOD = "good" + FAIL = "fail" + WARN = "warn" + INFO = "info" COLORS = { @@ -19,21 +19,21 @@ class MESSAGES(object): MESSAGES.FAIL: 1, MESSAGES.WARN: 3, MESSAGES.INFO: 4, - 'red': 1, - 'green': 2, - 'yellow': 3, - 'blue': 4, - 'pink': 5, - 'cyan': 6, - 'white': 7, - 'grey': 8 + "red": 1, + "green": 2, + "yellow": 3, + "blue": 4, + "pink": 5, + "cyan": 6, + "white": 7, + "grey": 8, } ICONS = { - MESSAGES.GOOD: '\u2714', - MESSAGES.FAIL: '\u2718', - MESSAGES.WARN: '\u26a0', - MESSAGES.INFO: '\u2139' + MESSAGES.GOOD: "\u2714", + MESSAGES.FAIL: "\u2718", + MESSAGES.WARN: "\u26a0", + MESSAGES.INFO: "\u2139", } @@ -52,12 +52,12 @@ def color(text, fg=None, bg=None, bold=False): return text styles = [] if bold: - styles.append('1') + styles.append("1") if fg: - styles.append('38;5;{}'.format(fg)) + styles.append("38;5;{}".format(fg)) if bg: - styles.append('48;5;{}'.format(bg)) - return '\x1b[{}m{}\x1b[0m'.format(';'.join(styles), text) + styles.append("48;5;{}".format(bg)) + return "\x1b[{}m{}\x1b[0m".format(";".join(styles), text) def wrap(text, wrap_max=80, indent=4): @@ -68,15 +68,20 @@ def wrap(text, wrap_max=80, indent=4): indent (int): Number of spaces used for indentation. Defaults to 4. RETURNS (unicode): The wrapped text with line breaks. """ - indent = indent * ' ' + indent = indent * " " wrap_width = wrap_max - len(indent) text = to_string(text) - return textwrap.fill(text, width=wrap_width, initial_indent=indent, - subsequent_indent=indent, break_long_words=False, - break_on_hyphens=False) + return textwrap.fill( + text, + width=wrap_width, + initial_indent=indent, + subsequent_indent=indent, + break_long_words=False, + break_on_hyphens=False, + ) -def locale_escape(string, errors='ignore'): +def locale_escape(string, errors="ignore"): """Mangle non-supported characters, for savages with ASCII terminals. string (unicode): The string to escape. @@ -85,7 +90,7 @@ def locale_escape(string, errors='ignore'): """ encoding = locale.getpreferredencoding() string = to_string(string) - string = string.encode(encoding, errors).decode('utf8') + string = string.encode(encoding, errors).decode("utf8") return string @@ -112,8 +117,9 @@ def supports_ansi(): """ # See: https://stackoverflow.com/q/7445658/6400719 plat = sys.platform - supported_platform = plat != 'Pocket PC' and (plat != 'win32' or - 'ANSICON' in os.environ) + supported_platform = plat != "Pocket PC" and ( + plat != "win32" or "ANSICON" in os.environ + ) if not supported_platform: return False return True @@ -133,7 +139,7 @@ def to_string(text): basestring_ = str if not isinstance(text, basestring_): if is_python2: - text = str(text).decode('utf8') + text = str(text).decode("utf8") else: text = str(text) return text