def test_cap_missing(self):
     """
     Return None if capability is missing for terminal
     """
     jinxed.setupterm('xterm')
     self.assertEqual(jinxed.tigetstr('howmuchwoodawoodchuckwillchuck'),
                      None)
 def test_unsupported_term(self):
     """
     Raise error if no terminfo for terminal
     """
     with self.assertRaisesRegex(jinxed.error,
                                 'Could not find terminal foobar'):
         jinxed.setupterm('foobar')
 def test_bad_term_type(self):
     """
     Raise error if term is not a string
     """
     with self.assertRaisesRegex(TypeError,
                                 'term must be a string or None'):
         jinxed.setupterm(100)
 def test_cap_unknown(self):
     """
     Return -1 if capability is unknown
     """
     jinxed.setupterm('xterm')
     self.assertEqual(jinxed.tigetflag('howmuchwoodawoodchuckwillchuck'),
                      -1)
    def test_fd_error(self):
        """
        Set fd to None if known error is encountered
        """

        with mock.patch.object(sys, 'stdout', wraps=sys.stdout) as mockstdout:

            for error in (AttributeError, TypeError, io.UnsupportedOperation):
                mockstdout.fileno.side_effect = error()
                jinxed.setupterm('xterm')
                self.assertIs(jinxed._terminal.TERM.stream_fd, None)
    def test_term_none(self):
        """
        If term is none, determine dynamically
        """
        term = os.environ.get('TERM', None)
        jinxed._terminal.TERM = None

        try:
            os.environ['TERM'] = 'xterm'
            jinxed.setupterm()
            self.assertIs(jinxed._terminal.TERM.terminfo,
                          jinxed.terminfo.xterm)

        finally:
            if term is None:
                del os.environ['TERM']
            else:
                os.environ['TERM'] = term
Beispiel #7
0
    def __init__(self, kind=None, stream=None, force_styling=False):
        """
        Initialize the terminal.

        :arg str kind: A terminal string as taken by :func:`curses.setupterm`.
            Defaults to the value of the ``TERM`` environment variable.

            .. note:: Terminals withing a single process must share a common
                ``kind``. See :obj:`_CUR_TERM`.

        :arg file stream: A file-like object representing the Terminal output.
            Defaults to the original value of :obj:`sys.__stdout__`, like
            :func:`curses.initscr` does.

            If ``stream`` is not a tty, empty Unicode strings are returned for
            all capability values, so things like piping your program output to
            a pipe or file does not emit terminal sequences.

        :arg bool force_styling: Whether to force the emission of capabilities
            even if :obj:`sys.__stdout__` does not seem to be connected to a
            terminal. If you want to force styling to not happen, use
            ``force_styling=None``.

            This comes in handy if users are trying to pipe your output through
            something like ``less -r`` or build systems which support decoding
            of terminal sequences.
        """
        # pylint: disable=global-statement,too-many-branches
        global _CUR_TERM
        self._keyboard_fd = None

        # Default stream is stdout, keyboard valid as stdin only when
        # output stream is stdout or stderr and is a tty.
        if stream is None:
            stream = sys.__stdout__
        if stream in (sys.__stdout__, sys.__stderr__):
            self._keyboard_fd = sys.__stdin__.fileno()

        # we assume our input stream to be line-buffered until either the
        # cbreak of raw context manager methods are entered with an
        # attached tty.
        self._line_buffered = True

        try:
            stream_fd = (stream.fileno() if hasattr(stream, 'fileno')
                         and callable(stream.fileno) else None)
        except io.UnsupportedOperation:
            stream_fd = None

        self._stream = stream
        self._is_a_tty = stream_fd is not None and os.isatty(stream_fd)
        self._does_styling = ((self.is_a_tty or force_styling)
                              and force_styling is not None)

        # _keyboard_fd only non-None if both stdin and stdout is a tty.
        self._keyboard_fd = (self._keyboard_fd
                             if self._keyboard_fd is not None and self.is_a_tty
                             and os.isatty(self._keyboard_fd) else None)
        self._normal = None  # cache normal attr, preventing recursive lookups

        # The descriptor to direct terminal initialization sequences to.
        self._init_descriptor = (sys.__stdout__.fileno()
                                 if stream_fd is None else stream_fd)

        if platform.system() == 'Windows':
            self._kind = kind or curses.get_term(self._init_descriptor)
        else:
            self._kind = kind or os.environ.get('TERM', 'unknown')

        if self.does_styling:
            # Initialize curses (call setupterm).
            #
            # Make things like tigetstr() work. Explicit args make setupterm()
            # work even when -s is passed to nosetests. Lean toward sending
            # init sequences to the stream if it has a file descriptor, and
            # send them to stdout as a fallback, since they have to go
            # somewhere.
            try:
                curses.setupterm(self._kind, self._init_descriptor)
            except curses.error as err:
                warnings.warn('Failed to setupterm(kind={0!r}): {1}'.format(
                    self._kind, err))
                self._kind = None
                self._does_styling = False
            else:
                if _CUR_TERM is None or self._kind == _CUR_TERM:
                    _CUR_TERM = self._kind
                else:
                    warnings.warn(
                        'A terminal of kind "%s" has been requested; due to an'
                        ' internal python curses bug, terminal capabilities'
                        ' for a terminal of kind "%s" will continue to be'
                        ' returned for the remainder of this process.' % (
                            self._kind,
                            _CUR_TERM,
                        ))

        # initialize capabilities and terminal keycodes database
        self.__init__capabilities()
        self.__init__keycodes()
 def test_fd_explicit(self):
     """
     Use fd is given explicitly
     """
     jinxed.setupterm('xterm', fd=sys.stderr.fileno())
     self.assertEqual(jinxed._terminal.TERM.stream_fd, sys.stderr.fileno())
 def test_bad_fd_type(self):
     """
     Raise error if fd is not an integer
     """
     with self.assertRaisesRegex(TypeError, 'fd must be an integer'):
         jinxed.setupterm('xterm', fd='banana')
 def test_cap_present(self):
     """
     Return capability if present for terminal
     """
     jinxed.setupterm('xterm')
     self.assertEqual(jinxed.tigetstr('bold'), b'\x1b[1m')
 def test_cap_missing(self):
     """
     Return 0 if capability is missing for terminal
     """
     jinxed.setupterm('xterm')
     self.assertEqual(jinxed.tigetnum('bitwin'), -1)
 def test_cap_present(self):
     """
     Return 1 if capability is present for terminal
     """
     jinxed.setupterm('xterm')
     self.assertEqual(jinxed.tigetnum('colors'), 8)
 def test_cap_missing(self):
     """
     Return 0 if capability is missing for terminal
     """
     jinxed.setupterm('xterm')
     self.assertEqual(jinxed.tigetflag('hz'), 0)