Skip to content

Commit

Permalink
Bug 1422302 - Create python/mozterm for sharing terminal blessings ac…
Browse files Browse the repository at this point in the history
…ross modules r=gps

This is a new module that will provide a place to store some common
abstractions around the 'blessings' module. The main entrypoint is:

    from mozterm import Terminal
    term = Terminal()

If blessings is available, this will return a blessings.Terminal()
object. If it isn't available, or something went wrong on import,
this will return a NullTerminal() object, which is a drop-in
replacement that does no formatting.

MozReview-Commit-ID: 6c63svm4tM5
  • Loading branch information
ahal committed Dec 4, 2017
1 parent 69ab88f commit b04eed3
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 33 deletions.
1 change: 1 addition & 0 deletions build/virtualenv_packages.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mozilla.pth:python/mach
mozilla.pth:python/mozboot
mozilla.pth:python/mozbuild
mozilla.pth:python/mozlint
mozilla.pth:python/mozterm
mozilla.pth:python/mozversioncontrol
mozilla.pth:third_party/python/blessings
mozilla.pth:third_party/python/compare-locales
Expand Down
1 change: 1 addition & 0 deletions python/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ PYTHON_UNITTEST_MANIFESTS += [
'mach/mach/test/python.ini',
'mozbuild/dumbmake/test/python.ini',
'mozlint/test/python.ini',
'mozterm/test/python.ini',
'mozversioncontrol/test/python.ini',
]

Expand Down
31 changes: 4 additions & 27 deletions python/mozlint/mozlint/formatters/stylish.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,9 @@

from __future__ import absolute_import, unicode_literals

from ..result import ResultContainer

try:
import blessings
except ImportError:
blessings = None

from mozterm import Terminal

class NullTerminal(object):
"""Replacement for `blessings.Terminal()` that does no formatting."""
class NullCallableString(unicode):
"""A dummy callable Unicode stolen from blessings"""
def __new__(cls):
new = unicode.__new__(cls, u'')
return new

def __call__(self, *args):
if len(args) != 1 or isinstance(args[0], int):
return u''
return args[0]

def __getattr__(self, attr):
return self.NullCallableString()
from ..result import ResultContainer


class StylishFormatter(object):
Expand All @@ -45,11 +25,8 @@ class StylishFormatter(object):
fmt = " {c1}{lineno}{column} {c2}{level}{normal} {message} {c1}{rule}({linter}){normal}"
fmt_summary = "{t.bold}{c}\u2716 {problem} ({error}, {warning}{failure}){t.normal}"

def __init__(self, disable_colors=None):
if disable_colors or not blessings:
self.term = NullTerminal()
else:
self.term = blessings.Terminal()
def __init__(self, disable_colors=False):
self.term = Terminal(disable_styling=disable_colors)
self.num_colors = self.term.number_of_colors

def color(self, color):
Expand Down
6 changes: 6 additions & 0 deletions python/mozterm/mozterm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import, unicode_literals

from .terminal import Terminal, NullTerminal # noqa
49 changes: 49 additions & 0 deletions python/mozterm/mozterm/terminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import, unicode_literals

import os
import sys


class NullTerminal(object):
"""Replacement for `blessings.Terminal()` that does no formatting."""
number_of_colors = 0
width = 0
height = 0

def __init__(self, stream=None, **kwargs):
self.stream = stream or sys.__stdout__
try:
self.is_a_tty = os.isatty(self.stream.fileno())
except:
self.is_a_tty = False

class NullCallableString(unicode):
"""A dummy callable Unicode stolen from blessings"""
def __new__(cls):
new = unicode.__new__(cls, '')
return new

def __call__(self, *args):
if len(args) != 1 or isinstance(args[0], int):
return ''
return args[0]

def __getattr__(self, attr):
return self.NullCallableString()


def Terminal(raises=False, disable_styling=False, **kwargs):
if disable_styling:
return NullTerminal(**kwargs)

try:
import blessings
except Exception:
if raises:
raise
return NullTerminal(**kwargs)
return blessings.Terminal(**kwargs)
4 changes: 4 additions & 0 deletions python/mozterm/test/python.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[DEFAULT]
subsuite = mozterm

[test_terminal.py]
51 changes: 51 additions & 0 deletions python/mozterm/test/test_terminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import, unicode_literals

import os
import sys

import mozunit
import pytest

from mozterm import Terminal, NullTerminal


def test_terminal():
blessings = pytest.importorskip('blessings')
term = Terminal()
assert isinstance(term, blessings.Terminal)

term = Terminal(disable_styling=True)
assert isinstance(term, NullTerminal)

del sys.modules['blessings']
orig = sys.path[:]
for path in orig:
if 'blessings' in path:
sys.path.remove(path)

term = Terminal()
assert isinstance(term, NullTerminal)

with pytest.raises(ImportError):
term = Terminal(raises=True)

sys.path = orig


def test_null_terminal():
term = NullTerminal()
assert term.red("foo") == "foo"
assert term.red == ""
assert term.color(1) == ""
assert term.number_of_colors == 0
assert term.width == 0
assert term.height == 0
assert term.is_a_tty == os.isatty(sys.stdout.fileno())


if __name__ == '__main__':
mozunit.main()
16 changes: 16 additions & 0 deletions taskcluster/ci/source-test/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,22 @@ mozlint:
files-changed:
- 'python/mozlint/**'

mozterm:
description: python/mozterm unit tests
platform: linux64/opt
treeherder:
symbol: py(term)
worker:
by-platform:
linux64.*:
docker-image: {in-tree: "lint"}
max-run-time: 3600
run:
mach: python-test --subsuite mozterm
when:
files-changed:
- 'python/mozterm/**'

mozversioncontrol:
description: python/mozversioncontrol unit tests
platform: linux64/opt
Expand Down
1 change: 1 addition & 0 deletions tools/lint/flake8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ flake8:
- python/mach_commands.py
- python/mozboot
- python/mozlint
- python/mozterm
- python/mozversioncontrol
- security/manager
- taskcluster
Expand Down
9 changes: 3 additions & 6 deletions tools/tryselect/selectors/fuzzy.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,15 @@
from distutils.spawn import find_executable

from mozboot.util import get_state_dir
from mozterm import Terminal

from .. import preset as pset
from ..cli import BaseTryParser
from ..tasks import generate_tasks
from ..vcs import VCSHelper

try:
import blessings
terminal = blessings.Terminal()
except ImportError:
from mozlint.formatters.stylish import NullTerminal
terminal = NullTerminal()
terminal = Terminal()


FZF_NOT_FOUND = """
Could not find the `fzf` binary.
Expand Down

0 comments on commit b04eed3

Please sign in to comment.