Hello community, here is the log from the commit of package python3-pyte for openSUSE:Factory checked in at 2016-03-17 16:35:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python3-pyte (Old) and /work/SRC/openSUSE:Factory/.python3-pyte.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python3-pyte" Changes: -------- --- /work/SRC/openSUSE:Factory/python3-pyte/python3-pyte.changes 2016-02-01 19:57:16.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python3-pyte.new/python3-pyte.changes 2016-03-17 16:48:20.000000000 +0100 @@ -1,0 +2,9 @@ +Tue Mar 15 04:41:36 UTC 2016 - [email protected] + +- specfile: + * added python3-pytest-runner + +- update to version 0.5.2: + * Fixed a bug in handling DA request. See issue #46 on GitHub. + +------------------------------------------------------------------- Old: ---- pyte-0.5.1.tar.gz New: ---- pyte-0.5.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python3-pyte.spec ++++++ --- /var/tmp/diff_new_pack.Nv8vrR/_old 2016-03-17 16:48:20.000000000 +0100 +++ /var/tmp/diff_new_pack.Nv8vrR/_new 2016-03-17 16:48:20.000000000 +0100 @@ -17,7 +17,7 @@ Name: python3-pyte -Version: 0.5.1 +Version: 0.5.2 Release: 0 Summary: Simple VTXXX-compatible linux terminal emulator License: LGPL-3.0 @@ -26,6 +26,7 @@ Source: https://pypi.python.org/packages/source/p/pyte/pyte-%{version}.tar.gz BuildRequires: python3-devel BuildRequires: python3-pytest +BuildRequires: python3-pytest-runner BuildRequires: python3-setuptools BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildArch: noarch ++++++ pyte-0.5.1.tar.gz -> pyte-0.5.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/CHANGES new/pyte-0.5.2/CHANGES --- old/pyte-0.5.1/CHANGES 2016-01-10 20:44:45.000000000 +0100 +++ new/pyte-0.5.2/CHANGES 2016-03-14 20:48:50.000000000 +0100 @@ -3,12 +3,19 @@ Here you can see the full list of changes between each pyte release. +Version 0.5.2 +------------- + +Pi Day bugfix release, released on March 14th, 2016 + +- Fixed a bug in handling DA request. See issue #46 on GitHub. + Version 0.5.1 ------------- Bugfix release, released on January 10th 2015 -- Fixed dependencies in ``setup.py``. +- Fixed dependencies in setup.py. Version 0.5.0 ------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/PKG-INFO new/pyte-0.5.2/PKG-INFO --- old/pyte-0.5.1/PKG-INFO 2016-01-10 20:45:41.000000000 +0100 +++ new/pyte-0.5.2/PKG-INFO 2016-03-14 20:53:20.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyte -Version: 0.5.1 +Version: 0.5.2 Summary: Simple VTXXX-compatible terminal emulator. Home-page: https://github.com/selectel/pyte Author: Sergei Lebedev @@ -17,7 +17,7 @@ | |_) || |_| || |_| __/ | .__/ \__, | \__|\___| | | __/ | - |_| |___/ 0.5.1 + |_| |___/ 0.5.2 What is ``pyte``? @@ -68,7 +68,7 @@ Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent -Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/README new/pyte-0.5.2/README --- old/pyte-0.5.1/README 2016-01-10 20:45:14.000000000 +0100 +++ new/pyte-0.5.2/README 2016-03-14 20:49:43.000000000 +0100 @@ -9,7 +9,7 @@ | |_) || |_| || |_| __/ | .__/ \__, | \__|\___| | | __/ | - |_| |___/ 0.5.1 + |_| |___/ 0.5.2 What is ``pyte``? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/docs/conf.py new/pyte-0.5.2/docs/conf.py --- old/pyte-0.5.1/docs/conf.py 2016-01-10 20:45:00.000000000 +0100 +++ new/pyte-0.5.2/docs/conf.py 2016-03-14 20:49:12.000000000 +0100 @@ -52,9 +52,9 @@ # built documents. # # The short X.Y version. -version = '0.5.1' +version = '0.5.2' # The full version, including alpha/beta/rc tags. -release = '0.5.1' +release = '0.5.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/docs/index.rst new/pyte-0.5.2/docs/index.rst --- old/pyte-0.5.1/docs/index.rst 2016-01-10 17:43:45.000000000 +0100 +++ new/pyte-0.5.2/docs/index.rst 2016-03-14 12:23:17.000000000 +0100 @@ -20,7 +20,7 @@ Head over to our brief :ref:`tutorial` or, if you're feeling brave, dive right into the :ref:`api`; ``pyte`` also has a couple of examples in the -`examples <https://github.com/selectel/examples>`_ directory. +`examples <https://github.com/selectel/pyte/tree/master/examples>`_ directory. .. toctree:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/docs/tutorial.rst new/pyte-0.5.2/docs/tutorial.rst --- old/pyte-0.5.1/docs/tutorial.rst 2016-01-10 17:27:24.000000000 +0100 +++ new/pyte-0.5.2/docs/tutorial.rst 2016-03-14 12:23:17.000000000 +0100 @@ -14,7 +14,7 @@ In general, if you just want to know what's being displayed on screen you can do something like the following: - >>> fromm __future__ import unicode_literals + >>> from __future__ import unicode_literals >>> import pyte >>> screen = pyte.Screen(80, 24) >>> stream = pyte.Stream() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/examples/inception.py new/pyte-0.5.2/examples/inception.py --- old/pyte-0.5.1/examples/inception.py 2016-01-10 04:12:20.000000000 +0100 +++ new/pyte-0.5.2/examples/inception.py 2016-03-14 12:23:17.000000000 +0100 @@ -25,7 +25,7 @@ def print_screen(screen, text): - print(pyte.ctrl.ESC + pyte.esc.RIS) + print(pyte.control.ESC + pyte.escape.RIS) for idx, line in enumerate(screen.display, 1): print("{0:2d} {1} ΒΆ".format(idx, line)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/pyte/screens.py new/pyte-0.5.2/pyte/screens.py --- old/pyte-0.5.1/pyte/screens.py 2016-01-10 11:56:38.000000000 +0100 +++ new/pyte-0.5.2/pyte/screens.py 2016-03-14 12:23:17.000000000 +0100 @@ -864,14 +864,15 @@ self.cursor.attrs = self.cursor.attrs._replace(**replace) - def report_device_attributes(self): + def report_device_attributes(self, mode=0, **kwargs): """Reports terminal identity. .. versionadded:: 0.5.0 """ # We only implement "primary" DA which is the only DA request # VT102 understood, see ``VT102ID`` in ``linux/drivers/tty/vt.c``. - self.write_process_input(ctrl.CSI + "?6c") + if mode == 0: + self.write_process_input(ctrl.CSI + "?6c") def report_device_status(self, mode): """Reports terminal status or cursor position. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/pyte/streams.py new/pyte-0.5.2/pyte/streams.py --- old/pyte-0.5.1/pyte/streams.py 2016-01-10 17:20:49.000000000 +0100 +++ new/pyte-0.5.2/pyte/streams.py 2016-03-14 12:23:17.000000000 +0100 @@ -148,7 +148,7 @@ Use :meth:`feed` instead. """ warnings.warn(".consume is deprecated and will be removed in " - "pyte 0.5.1. Please use .feed instead.", + "pyte 0.5.2. Please use .feed instead.", category=DeprecationWarning) return self.feed(char) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/pyte.egg-info/PKG-INFO new/pyte-0.5.2/pyte.egg-info/PKG-INFO --- old/pyte-0.5.1/pyte.egg-info/PKG-INFO 2016-01-10 20:45:41.000000000 +0100 +++ new/pyte-0.5.2/pyte.egg-info/PKG-INFO 2016-03-14 20:53:20.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyte -Version: 0.5.1 +Version: 0.5.2 Summary: Simple VTXXX-compatible terminal emulator. Home-page: https://github.com/selectel/pyte Author: Sergei Lebedev @@ -17,7 +17,7 @@ | |_) || |_| || |_| __/ | .__/ \__, | \__|\___| | | __/ | - |_| |___/ 0.5.1 + |_| |___/ 0.5.2 What is ``pyte``? @@ -68,7 +68,7 @@ Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent -Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/pyte.egg-info/SOURCES.txt new/pyte-0.5.2/pyte.egg-info/SOURCES.txt --- old/pyte-0.5.1/pyte.egg-info/SOURCES.txt 2016-01-10 20:45:41.000000000 +0100 +++ new/pyte-0.5.2/pyte.egg-info/SOURCES.txt 2016-03-14 20:53:20.000000000 +0100 @@ -3,6 +3,7 @@ LICENSE MANIFEST.in README +setup.cfg setup.py docs/api.rst docs/changelog.rst @@ -29,7 +30,6 @@ pyte.egg-info/requires.txt pyte.egg-info/top_level.txt tests/__init__.py -tests/test_benchmarks.py tests/test_diff.py tests/test_history.py tests/test_screen.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/setup.cfg new/pyte-0.5.2/setup.cfg --- old/pyte-0.5.1/setup.cfg 2016-01-10 20:45:41.000000000 +0100 +++ new/pyte-0.5.2/setup.cfg 2016-03-14 20:53:20.000000000 +0100 @@ -1,5 +1,8 @@ +[aliases] +test = pytest + [egg_info] -tag_build = -tag_date = 0 tag_svn_revision = 0 +tag_date = 0 +tag_build = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/setup.py new/pyte-0.5.2/setup.py --- old/pyte-0.5.1/setup.py 2016-01-10 20:44:33.000000000 +0100 +++ new/pyte-0.5.2/setup.py 2016-03-14 20:49:24.000000000 +0100 @@ -2,10 +2,8 @@ # -*- coding: utf-8 -*- import os -import sys from setuptools import setup -from setuptools.command.test import test as TestCommand here = os.path.abspath(os.path.dirname(__file__)) @@ -23,7 +21,7 @@ "Environment :: Console", "Intended Audience :: Developers", "Operating System :: OS Independent", - "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", + "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", @@ -32,26 +30,11 @@ ] -class PyTest(TestCommand): - """Unfortunately :mod:`setuptools` support only :mod:`unittest` - based tests, thus, we have to overider build-in ``test`` command - to run :mod:`pytest`. - """ - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - - def run_tests(self): - import pytest - sys.exit(pytest.main(self.test_args + ["./tests"])) - - setup(name="pyte", - version="0.5.1", + version="0.5.2", packages=["pyte"], install_requires=["wcwidth"], - cmdclass={"test": PyTest}, + setup_requires=["pytest-runner"], tests_require=["pytest"], platforms=["any"], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/tests/test_benchmarks.py new/pyte-0.5.2/tests/test_benchmarks.py --- old/pyte-0.5.1/tests/test_benchmarks.py 2016-01-10 11:48:32.000000000 +0100 +++ new/pyte-0.5.2/tests/test_benchmarks.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,815 +0,0 @@ -import subprocess -import sys -import time - -import pytest - -from pyte import control as ctrl, escape as esc, Stream -from pyte.screens import * - - -class VanillaScreen(object): - """ - A screen is an in-memory matrix of characters that represents the - screen display of the terminal. It can be instantiated on it's own - and given explicit commands, or it can be attached to a stream and - will respond to events. - - .. attribute:: buffer - - A ``lines x columns`` :class:`~pyte.screens.Char` matrix. - - .. attribute:: cursor - - Reference to the :class:`~pyte.screens.Cursor` object, holding - cursor position and attributes. - - .. attribute:: margins - - Top and bottom screen margins, defining the scrolling region; - the actual values are top and bottom line. - - .. attribute:: charset - - Current charset number; can be either ``0`` or ``1`` for `G0` - and `G1` respectively, note that `G0` is activated by default. - - .. note:: - - According to ``ECMA-48`` standard, **lines and columnns are - 1-indexed**, so, for instance ``ESC [ 10;10 f`` really means - -- move cursor to position (9, 9) in the display matrix. - - .. versionchanged:: 0.4.7 - .. warning:: - - :data:`~pyte.modes.LNM` is reset by default, to match VT220 - specification. - - .. versionchanged:: 0.4.8 - .. warning:: - - If `DECAWM` mode is set than a cursor will be wrapped to the - **beginning** of the next line, which is the behaviour described - in ``man console_codes``. - - .. seealso:: - - `Standard ECMA-48, Section 6.1.1 \ - <http://www.ecma-international.org/publications/standards/Ecma-048.htm>`_ - for a description of the presentational component, implemented - by ``Screen``. - """ - #: A plain empty character with default foreground and background - #: colors. - default_char = Char(data=" ", fg="default", bg="default") - - #: An inifinite sequence of default characters, used for populating - #: new lines and columns. - default_line = repeat(default_char) - - def __init__(self, columns, lines): - self.savepoints = [] - self.columns = columns - self.lines = lines - self.buffer = [] - self.reset() - - def __repr__(self): - return ("{0}({1}, {2})".format(self.__class__.__name__, - self.columns, self.lines)) - - def __before__(self, command): - """Hook, called **before** a command is dispatched to the - :class:`Screen` instance. - - :param str command: command name, for example ``"LINEFEED"``. - """ - - def __after__(self, command): - """Hook, called **after** a command is dispatched to the - :class:`Screen` instance. - - :param str command: command name, for example ``"LINEFEED"``. - """ - - @property - def display(self): - """Returns a :func:`list` of screen lines as unicode strings.""" - return ["".join(map(operator.attrgetter("data"), line)) - for line in self.buffer] - - def reset(self): - """Resets the terminal to its initial state. - - * Scroll margins are reset to screen boundaries. - * Cursor is moved to home location -- ``(0, 0)`` and its - attributes are set to defaults (see :attr:`default_char`). - * Screen is cleared -- each character is reset to - :attr:`default_char`. - * Tabstops are reset to "every eight columns". - - .. note:: - - Neither VT220 nor VT102 manuals mentioned that terminal modes - and tabstops should be reset as well, thanks to - :manpage:`xterm` -- we now know that. - """ - self.buffer[:] = (take(self.columns, self.default_line) - for _ in range(self.lines)) - self.mode = set([mo.DECAWM, mo.DECTCEM]) - self.margins = Margins(0, self.lines - 1) - - # According to VT220 manual and ``linux/drivers/tty/vt.c`` - # the default G0 charset is latin-1, but for reasons unknown - # latin-1 breaks ascii-graphics; so G0 defaults to cp437. - self.charset = 0 - self.g0_charset = cs.IBMPC_MAP - self.g1_charset = cs.VT100_MAP - - # From ``man terminfo`` -- "... hardware tabs are initially - # set every `n` spaces when the terminal is powered up. Since - # we aim to support VT102 / VT220 and linux -- we use n = 8. - self.tabstops = set(range(7, self.columns, 8)) - - self.cursor = Cursor(0, 0) - self.cursor_position() - - def resize(self, lines=None, columns=None): - """Resize the screen to the given dimensions. - - If the requested screen size has more lines than the existing - screen, lines will be added at the bottom. If the requested - size has less lines than the existing screen lines will be - clipped at the top of the screen. Similarly, if the existing - screen has less columns than the requested screen, columns will - be added at the right, and if it has more -- columns will be - clipped at the right. - - .. note:: According to `xterm`, we should also reset origin - mode and screen margins, see ``xterm/screen.c:1761``. - - :param int lines: number of lines in the new screen. - :param int columns: number of columns in the new screen. - """ - lines = lines or self.lines - columns = columns or self.columns - - # First resize the lines: - diff = self.lines - lines - - # a) if the current display size is less than the requested - # size, add lines to the bottom. - if diff < 0: - self.buffer.extend(take(self.columns, self.default_line) - for _ in range(diff, 0)) - # b) if the current display size is greater than requested - # size, take lines off the top. - elif diff > 0: - self.buffer[:diff] = () - - # Then resize the columns: - diff = self.columns - columns - - # a) if the current display size is less than the requested - # size, expand each line to the new size. - if diff < 0: - for y in range(lines): - self.buffer[y].extend(take(abs(diff), self.default_line)) - # b) if the current display size is greater than requested - # size, trim each line from the right to the new size. - elif diff > 0: - for line in self.buffer: - del line[columns:] - - self.lines, self.columns = lines, columns - self.margins = Margins(0, self.lines - 1) - self.reset_mode(mo.DECOM) - - def set_margins(self, top=None, bottom=None): - """Selects top and bottom margins for the scrolling region. - - Margins determine which screen lines move during scrolling - (see :meth:`index` and :meth:`reverse_index`). Characters added - outside the scrolling region do not cause the screen to scroll. - - :param int top: the smallest line number that is scrolled. - :param int bottom: the biggest line number that is scrolled. - """ - if top is None or bottom is None: - return - - # Arguments are 1-based, while :attr:`margins` are zero based -- - # so we have to decrement them by one. We also make sure that - # both of them is bounded by [0, lines - 1]. - top = max(0, min(top - 1, self.lines - 1)) - bottom = max(0, min(bottom - 1, self.lines - 1)) - - # Even though VT102 and VT220 require DECSTBM to ignore regions - # of width less than 2, some programs (like aptitude for example) - # rely on it. Practicality beats purity. - if bottom - top >= 1: - self.margins = Margins(top, bottom) - - # The cursor moves to the home position when the top and - # bottom margins of the scrolling region (DECSTBM) changes. - self.cursor_position() - - def set_charset(self, code, mode): - """Set active ``G0`` or ``G1`` charset. - - :param str code: character set code, should be a character - from ``"B0UK"`` -- otherwise ignored. - :param str mode: if ``"("`` ``G0`` charset is set, if - ``")"`` -- we operate on ``G1``. - - .. warning:: User-defined charsets are currently not supported. - """ - if code in cs.MAPS: - setattr(self, {"(": "g0_charset", ")": "g1_charset"}[mode], - cs.MAPS[code]) - - def set_mode(self, *modes, **kwargs): - """Sets (enables) a given list of modes. - - :param list modes: modes to set, where each mode is a constant - from :mod:`pyte.modes`. - """ - # Private mode codes are shifted, to be distingiushed from non - # private ones. - if kwargs.get("private"): - modes = [mode << 5 for mode in modes] - - self.mode.update(modes) - - # When DECOLM mode is set, the screen is erased and the cursor - # moves to the home position. - if mo.DECCOLM in modes: - self.resize(columns=132) - self.erase_in_display(2) - self.cursor_position() - - # According to `vttest`, DECOM should also home the cursor, see - # vttest/main.c:303. - if mo.DECOM in modes: - self.cursor_position() - - # Mark all displayed characters as reverse. - if mo.DECSCNM in modes: - self.buffer[:] = ([char._replace(reverse=True) for char in line] - for line in self.buffer) - self.select_graphic_rendition(g._SGR["+reverse"]) - - # Make the cursor visible. - if mo.DECTCEM in modes: - self.cursor.hidden = False - - def reset_mode(self, *modes, **kwargs): - """Resets (disables) a given list of modes. - - :param list modes: modes to reset -- hopefully, each mode is a - constant from :mod:`pyte.modes`. - """ - # Private mode codes are shifted, to be distingiushed from non - # private ones. - if kwargs.get("private"): - modes = [mode << 5 for mode in modes] - - self.mode.difference_update(modes) - - # Lines below follow the logic in :meth:`set_mode`. - if mo.DECCOLM in modes: - self.resize(columns=80) - self.erase_in_display(2) - self.cursor_position() - - if mo.DECOM in modes: - self.cursor_position() - - if mo.DECSCNM in modes: - self.buffer[:] = ([char._replace(reverse=False) for char in line] - for line in self.buffer) - self.select_graphic_rendition(g._SGR["-reverse"]) - - # Hide the cursor. - if mo.DECTCEM in modes: - self.cursor.hidden = True - - def shift_in(self): - """Activates ``G0`` character set.""" - self.charset = 0 - - def shift_out(self): - """Activates ``G1`` character set.""" - self.charset = 1 - - def draw(self, char): - """Display a character at the current cursor position and advance - the cursor if :data:`~pyte.modes.DECAWM` is set. - - :param str char: a character to display. - - .. versionchanged:: 0.5.0 - - Character width is taken into account. Specifically, zero-width - and unprintable characters do not affect screen state. Full-width - characters are rendered into two consecutive character containers. - """ - # Translating a given character. - if self.charset: - char = char.translate(self.g1_charset) - else: - char = char.translate(self.g0_charset) - - char_width = wcwidth(char) - if char_width <= 0: - # Unprintable character or doesn't advance the cursor. - return - - # If this was the last column in a line and auto wrap mode is - # enabled, move the cursor to the beginning of the next line, - # otherwise replace characters already displayed with newly - # entered. - if self.cursor.x == self.columns: - if mo.DECAWM in self.mode: - self.carriage_return() - self.linefeed() - else: - self.cursor.x -= char_width - - # If Insert mode is set, new characters move old characters to - # the right, otherwise terminal is in Replace mode and new - # characters replace old characters at cursor position. - if mo.IRM in self.mode: - self.insert_characters(char_width) - - line = self.buffer[self.cursor.y] - line[self.cursor.x] = self.cursor.attrs._replace(data=char) - if char_width > 1: - # Add a stub *after* a two-cell characters. See issue #9 - # on GitHub. - line[self.cursor.x + 1] = self.cursor.attrs._replace(data=" ") - - # .. note:: We can't use :meth:`cursor_forward()`, because that - # way, we'll never know when to linefeed. - self.cursor.x += char_width - - def carriage_return(self): - """Move the cursor to the beginning of the current line.""" - self.cursor.x = 0 - - def index(self): - """Move the cursor down one line in the same column. If the - cursor is at the last line, create a new line at the bottom. - """ - top, bottom = self.margins - - if self.cursor.y == bottom: - self.buffer.pop(top) - self.buffer.insert(bottom, take(self.columns, self.default_line)) - else: - self.cursor_down() - - def reverse_index(self): - """Move the cursor up one line in the same column. If the cursor - is at the first line, create a new line at the top. - """ - top, bottom = self.margins - - if self.cursor.y == top: - self.buffer.pop(bottom) - self.buffer.insert(top, take(self.columns, self.default_line)) - else: - self.cursor_up() - - def linefeed(self): - """Performs an index and, if :data:`~pyte.modes.LNM` is set, a - carriage return. - """ - self.index() - - if mo.LNM in self.mode: - self.carriage_return() - - self.ensure_bounds() - - def tab(self): - """Move to the next tab space, or the end of the screen if there - aren't anymore left. - """ - for stop in sorted(self.tabstops): - if self.cursor.x < stop: - column = stop - break - else: - column = self.columns - 1 - - self.cursor.x = column - - def backspace(self): - """Move cursor to the left one or keep it in it's position if - it's at the beginning of the line already. - """ - self.cursor_back() - - def save_cursor(self): - """Push the current cursor position onto the stack.""" - self.savepoints.append(Savepoint(copy.copy(self.cursor), - self.g0_charset, - self.g1_charset, - self.charset, - mo.DECOM in self.mode, - mo.DECAWM in self.mode)) - - def restore_cursor(self): - """Set the current cursor position to whatever cursor is on top - of the stack. - """ - if self.savepoints: - savepoint = self.savepoints.pop() - - self.g0_charset = savepoint.g0_charset - self.g1_charset = savepoint.g1_charset - self.charset = savepoint.charset - - if savepoint.origin: - self.set_mode(mo.DECOM) - if savepoint.wrap: - self.set_mode(mo.DECAWM) - - self.cursor = savepoint.cursor - self.ensure_bounds(use_margins=True) - else: - # If nothing was saved, the cursor moves to home position; - # origin mode is reset. :todo: DECAWM? - self.reset_mode(mo.DECOM) - self.cursor_position() - - def insert_lines(self, count=None): - """Inserts the indicated # of lines at line with cursor. Lines - displayed **at** and below the cursor move down. Lines moved - past the bottom margin are lost. - - :param count: number of lines to delete. - """ - count = count or 1 - top, bottom = self.margins - - # If cursor is outside scrolling margins it -- do nothin'. - if top <= self.cursor.y <= bottom: - # v +1, because range() is exclusive. - for line in range(self.cursor.y, - min(bottom + 1, self.cursor.y + count)): - self.buffer.pop(bottom) - self.buffer.insert(line, take(self.columns, self.default_line)) - - self.carriage_return() - - def delete_lines(self, count=None): - """Deletes the indicated # of lines, starting at line with - cursor. As lines are deleted, lines displayed below cursor - move up. Lines added to bottom of screen have spaces with same - character attributes as last line moved up. - - :param int count: number of lines to delete. - """ - count = count or 1 - top, bottom = self.margins - - # If cursor is outside scrolling margins it -- do nothin'. - if top <= self.cursor.y <= bottom: - # v -- +1 to include the bottom margin. - for _ in range(min(bottom - self.cursor.y + 1, count)): - self.buffer.pop(self.cursor.y) - self.buffer.insert(bottom, list( - repeat(self.cursor.attrs, self.columns))) - - self.carriage_return() - - def insert_characters(self, count=None): - """Inserts the indicated # of blank characters at the cursor - position. The cursor does not move and remains at the beginning - of the inserted blank characters. Data on the line is shifted - forward. - - :param int count: number of characters to insert. - """ - count = count or 1 - - for _ in range(min(self.columns - self.cursor.y, count)): - self.buffer[self.cursor.y].insert(self.cursor.x, self.cursor.attrs) - self.buffer[self.cursor.y].pop() - - def delete_characters(self, count=None): - """Deletes the indicated # of characters, starting with the - character at cursor position. When a character is deleted, all - characters to the right of cursor move left. Character attributes - move with the characters. - - :param int count: number of characters to delete. - """ - count = count or 1 - - for _ in range(min(self.columns - self.cursor.x, count)): - self.buffer[self.cursor.y].pop(self.cursor.x) - self.buffer[self.cursor.y].append(self.cursor.attrs) - - def erase_characters(self, count=None): - """Erases the indicated # of characters, starting with the - character at cursor position. Character attributes are set - cursor attributes. The cursor remains in the same position. - - :param int count: number of characters to erase. - - .. warning:: - - Even though *ALL* of the VTXXX manuals state that character - attributes **should be reset to defaults**, ``libvte``, - ``xterm`` and ``ROTE`` completely ignore this. Same applies - too all ``erase_*()`` and ``delete_*()`` methods. - """ - count = count or 1 - - for column in range(self.cursor.x, - min(self.cursor.x + count, self.columns)): - self.buffer[self.cursor.y][column] = self.cursor.attrs - - def erase_in_line(self, type_of=0, private=False): - """Erases a line in a specific way. - - :param int type_of: defines the way the line should be erased in: - - * ``0`` -- Erases from cursor to end of line, including cursor - position. - * ``1`` -- Erases from beginning of line to cursor, - including cursor position. - * ``2`` -- Erases complete line. - :param bool private: when ``True`` character attributes are left - unchanged **not implemented**. - """ - interval = ( - # a) erase from the cursor to the end of line, including - # the cursor, - range(self.cursor.x, self.columns), - # b) erase from the beginning of the line to the cursor, - # including it, - range(0, self.cursor.x + 1), - # c) erase the entire line. - range(0, self.columns) - )[type_of] - - for column in interval: - self.buffer[self.cursor.y][column] = self.cursor.attrs - - def erase_in_display(self, type_of=0, private=False): - """Erases display in a specific way. - - :param int type_of: defines the way the line should be erased in: - - * ``0`` -- Erases from cursor to end of screen, including - cursor position. - * ``1`` -- Erases from beginning of screen to cursor, - including cursor position. - * ``2`` -- Erases complete display. All lines are erased - and changed to single-width. Cursor does not move. - :param bool private: when ``True`` character attributes are left - unchanged **not implemented**. - """ - interval = ( - # a) erase from cursor to the end of the display, including - # the cursor, - range(self.cursor.y + 1, self.lines), - # b) erase from the beginning of the display to the cursor, - # including it, - range(0, self.cursor.y), - # c) erase the whole display. - range(0, self.lines) - )[type_of] - - for line in interval: - self.buffer[line][:] = \ - (self.cursor.attrs for _ in range(self.columns)) - - # In case of 0 or 1 we have to erase the line with the cursor. - if type_of in [0, 1]: - self.erase_in_line(type_of) - - def set_tab_stop(self): - """Sest a horizontal tab stop at cursor position.""" - self.tabstops.add(self.cursor.x) - - def clear_tab_stop(self, type_of=None): - """Clears a horizontal tab stop in a specific way, depending - on the ``type_of`` value: - - * ``0`` or nothing -- Clears a horizontal tab stop at cursor - position. - * ``3`` -- Clears all horizontal tab stops. - """ - if not type_of: - # Clears a horizontal tab stop at cursor position, if it's - # present, or silently fails if otherwise. - self.tabstops.discard(self.cursor.x) - elif type_of == 3: - self.tabstops = set() # Clears all horizontal tab stops. - - def ensure_bounds(self, use_margins=None): - """Ensure that current cursor position is within screen bounds. - - :param bool use_margins: when ``True`` or when - :data:`~pyte.modes.DECOM` is set, - cursor is bounded by top and and bottom - margins, instead of ``[0; lines - 1]``. - """ - if use_margins or mo.DECOM in self.mode: - top, bottom = self.margins - else: - top, bottom = 0, self.lines - 1 - - self.cursor.x = min(max(0, self.cursor.x), self.columns - 1) - self.cursor.y = min(max(top, self.cursor.y), bottom) - - def cursor_up(self, count=None): - """Moves cursor up the indicated # of lines in same column. - Cursor stops at top margin. - - :param int count: number of lines to skip. - """ - self.cursor.y -= count or 1 - self.ensure_bounds(use_margins=True) - - def cursor_up1(self, count=None): - """Moves cursor up the indicated # of lines to column 1. Cursor - stops at bottom margin. - - :param int count: number of lines to skip. - """ - self.cursor_up(count) - self.carriage_return() - - def cursor_down(self, count=None): - """Moves cursor down the indicated # of lines in same column. - Cursor stops at bottom margin. - - :param int count: number of lines to skip. - """ - self.cursor.y += count or 1 - self.ensure_bounds(use_margins=True) - - def cursor_down1(self, count=None): - """Moves cursor down the indicated # of lines to column 1. - Cursor stops at bottom margin. - - :param int count: number of lines to skip. - """ - self.cursor_down(count) - self.carriage_return() - - def cursor_back(self, count=None): - """Moves cursor left the indicated # of columns. Cursor stops - at left margin. - - :param int count: number of columns to skip. - """ - self.cursor.x -= count or 1 - self.ensure_bounds() - - def cursor_forward(self, count=None): - """Moves cursor right the indicated # of columns. Cursor stops - at right margin. - - :param int count: number of columns to skip. - """ - self.cursor.x += count or 1 - self.ensure_bounds() - - def cursor_position(self, line=None, column=None): - """Set the cursor to a specific `line` and `column`. - - Cursor is allowed to move out of the scrolling region only when - :data:`~pyte.modes.DECOM` is reset, otherwise -- the position - doesn't change. - - :param int line: line number to move the cursor to. - :param int column: column number to move the cursor to. - """ - column = (column or 1) - 1 - line = (line or 1) - 1 - - # If origin mode (DECOM) is set, line number are relative to - # the top scrolling margin. - if mo.DECOM in self.mode: - line += self.margins.top - - # Cursor is not allowed to move out of the scrolling region. - if not self.margins.top <= line <= self.margins.bottom: - return - - self.cursor.x, self.cursor.y = column, line - self.ensure_bounds() - - def cursor_to_column(self, column=None): - """Moves cursor to a specific column in the current line. - - :param int column: column number to move the cursor to. - """ - self.cursor.x = (column or 1) - 1 - self.ensure_bounds() - - def cursor_to_line(self, line=None): - """Moves cursor to a specific line in the current column. - - :param int line: line number to move the cursor to. - """ - self.cursor.y = (line or 1) - 1 - - # If origin mode (DECOM) is set, line number are relative to - # the top scrolling margin. - if mo.DECOM in self.mode: - self.cursor.y += self.margins.top - - # FIXME: should we also restrict the cursor to the scrolling - # region? - - self.ensure_bounds() - - def bell(self, *args): - """Bell stub -- the actual implementation should probably be - provided by the end-user. - """ - - def alignment_display(self): - """Fills screen with uppercase E's for screen focus and alignment.""" - for line in self.buffer: - for column, char in enumerate(line): - line[column] = char._replace(data="E") - - def select_graphic_rendition(self, *attrs): - """Set display attributes. - - :param list attrs: a list of display attributes to set. - """ - replace = {} - - for attr in attrs or [0]: - if attr in g.FG: - replace["fg"] = g.FG[attr] - elif attr in g.BG: - replace["bg"] = g.BG[attr] - elif attr in g.TEXT: - attr = g.TEXT[attr] - replace[attr[1:]] = attr.startswith("+") - elif not attr: - replace = self.default_char._asdict() - - self.cursor.attrs = self.cursor.attrs._replace(**replace) - - def report_device_attributes(self): - """Reports terminal identity. - - .. versionadded:: 0.5.0 - """ - # We only implement "primary" DA which is the only DA request - # VT102 understood, see ``VT102ID`` in ``linux/drivers/tty/vt.c``. - self.write_process_input(ctrl.CSI + "?6c") - - def report_device_status(self, mode): - """Reports terminal status or cursor position. - - :param int mode: if 5 -- terminal status, 6 -- cursor position, - otherwise a noop. - - .. versionadded:: 0.5.0 - """ - if mode == 5: # Request for terminal status. - self.write_process_input(ctrl.CSI + "0n") - elif mode == 6: # Request for cursor position. - x = self.cursor.x + 1 - y = self.cursor.y + 1 - - # "Origin mode (DECOM) selects line numbering." - if mo.DECOM in self.mode: - y -= self.margins.top - self.write_process_input("{0}{1};{2}R".format(ctrl.CSI, y, x)) - - def write_process_input(self, data): - """Writes data to the process running inside the terminal. - - By default is a noop. - - :param str data: data to write to the process ``stdin``. - - .. versionadded:: 0.5.0 - """ - - - - [email protected]("screen_cls", [Screen, VanillaScreen]) -def test_stream_performance(benchmark, screen_cls): - def inner(contents): - s = Stream() - s.attach(screen_cls(80, 24)) - s.feed(contents) - - benchmark(inner, open("/tmp/mc").read()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyte-0.5.1/tests/test_screen.py new/pyte-0.5.2/tests/test_screen.py --- old/pyte-0.5.1/tests/test_screen.py 2016-01-10 01:01:14.000000000 +0100 +++ new/pyte-0.5.2/tests/test_screen.py 2016-03-14 12:23:17.000000000 +0100 @@ -1220,10 +1220,29 @@ acc = [] screen.write_process_input = acc.append + + # a) noop + screen.report_device_attributes(42) + assert not acc + + # b) OK case screen.report_device_attributes() assert acc.pop() == ctrl.CSI + "?6c" +def test_private_report_device_attributes(): + # Some console apps (e.g. ADOM) might add ``?`` to the DA request, + # even though the VT102/VT220 spec does not allow this. + screen = Screen(10, 10) + stream = Stream() + stream.attach(screen) + + acc = [] + screen.write_process_input = acc.append + stream.feed(ctrl.CSI + "?0c") + assert acc.pop() == ctrl.CSI + "?6c" + + def test_report_device_status(): screen = Screen(10, 10)
