Skip to content

Commit

Permalink
Bugfix for term.split_seqs('term.right(3)') #197
Browse files Browse the repository at this point in the history
* Bugfix for term.split_seqs('term.right(3)')

In version 1.18.0 and earlier,

>> term.split_seqs(term.move_right(333) + 'xyz', maxsplit=1)
['\x1b[333C', '333', 'xyz']

This is a bug, it duplicates the matched parameter, this is
now corrected:

['\x1b[3C', 'xyz']

Previously, we documented "same arguments as "re.split", so
we must also implement maxsplit and flags.

Also,
- fix flake8 linting of tests by moving fixtures to conftest.py,
  fixes "unused" or "re-definition from import" errors.
- version stamp blessed/__init__.py like a codegen step i guess
- remove run_codecov.py, its been fixed upstream
  codecov/codecov-python#158 (comment)
  • Loading branch information
jquast authored Jun 10, 2021
1 parent b6025ec commit 2d75fdc
Show file tree
Hide file tree
Showing 17 changed files with 159 additions and 115 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ matrix:
env: TOXENV=py37,codecov TEST_QUICK=1 COVERAGE_ID=travis-ci
- python: 3.8
env: TOXENV=py38,codecov COVERAGE_ID=travis-ci TEST_RAW=yes
- python: 3.9-dev
- python: 3.9
env: TOXENV=py39,codecov TEST_QUICK=1 COVERAGE_ID=travis-ci TOXPYTHON=3.9
- python: 3.10-dev
env: TOXENV=py310,codecov TEST_QUICK=1 COVERAGE_ID=travis-ci TOXPYTHON=3.10
Expand All @@ -38,7 +38,6 @@ matrix:
env: PATH=/c/Python38:/c/Python38/Scripts:$PATH TOXENV=py38,codecov COVERAGE_ID=travis-ci TEST_KEYBOARD=no

allow_failures:
- python: 3.9-dev
- python: 3.10-dev

install:
Expand Down
2 changes: 1 addition & 1 deletion blessed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@
'support due to http://bugs.python.org/issue10570.')

__all__ = ('Terminal',)
__version__ = '1.18.0'
__version__ = "1.18.1"
1 change: 0 additions & 1 deletion blessed/_capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import re
from collections import OrderedDict


__all__ = (
'CAPABILITY_DATABASE',
'CAPABILITIES_RAW_MIXIN',
Expand Down
19 changes: 16 additions & 3 deletions blessed/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1100,20 +1100,33 @@ def strip_seqs(self, text):
"""
return Sequence(text, self).strip_seqs()

def split_seqs(self, text, **kwds):
def split_seqs(self, text, maxsplit=0):
r"""
Return ``text`` split by individual character elements and sequences.
:arg str text: String containing sequences
:arg kwds: remaining keyword arguments for :func:`re.split`.
:arg int maxsplit: When maxsplit is nonzero, at most maxsplit splits
occur, and the remainder of the string is returned as the final element
of the list (same meaning is argument for :func:`re.split`).
:rtype: list[str]
:returns: List of sequences and individual characters
>>> term.split_seqs(term.underline(u'xyz'))
['\x1b[4m', 'x', 'y', 'z', '\x1b(B', '\x1b[m']
>>> term.split_seqs(term.underline(u'xyz'), 1)
['\x1b[4m', r'xyz\x1b(B\x1b[m']
"""
pattern = self._caps_unnamed_any
return list(filter(None, re.split(pattern, text, **kwds)))
result = []
for idx, match in enumerate(re.finditer(pattern, text)):
result.append(match.group())
if maxsplit and idx == maxsplit:
remaining = text[match.end():]
if remaining:
result[-1] += remaining
break
return result

def wrap(self, text, width=None, **kwargs):
"""
Expand Down
2 changes: 1 addition & 1 deletion blessed/terminal.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class Terminal:
def rstrip(self, text: str, chars: Optional[str] = ...) -> str: ...
def lstrip(self, text: str, chars: Optional[str] = ...) -> str: ...
def strip_seqs(self, text: str) -> str: ...
def split_seqs(self, text: str, **kwds: Any) -> List[str]: ...
def split_seqs(self, text: str, maxsplit: int) -> List[str]: ...
def wrap(
self, text: str, width: Optional[int] = ..., **kwargs: Any
) -> List[str]: ...
Expand Down
2 changes: 2 additions & 0 deletions docs/history.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Version History
===============
1.18
* bugfix: :meth:`~Terminal.split_seqs` for some sequences
like ``term.move_left(3)``, :ghissue:`197`.
* introduced: type annotations, :ghissue:`192` by :ghuser:`dlax`.
* bugfix: do not fail when ``sys.stdin`` is unset, :ghissue:`195` by
:ghuser:`Olen`
Expand Down
47 changes: 0 additions & 47 deletions run_codecov.py

This file was deleted.

49 changes: 1 addition & 48 deletions tests/accessories.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
"""Accessories for automated py.test runner."""
# standard imports
from __future__ import print_function, with_statement

# std imports
Expand All @@ -11,11 +10,9 @@
import functools
import traceback
import contextlib
import subprocess

# 3rd party
import six
import pytest

# local
from blessed import Terminal
Expand All @@ -40,31 +37,6 @@
TestTerminal = functools.partial(Terminal, kind=test_kind) # type: Callable[..., Terminal]
SEND_SEMAPHORE = SEMAPHORE = b'SEMAPHORE\n'
RECV_SEMAPHORE = b'SEMAPHORE\r\n'
many_lines_params = [40, 80]
# we must test a '1' column for conditional in _handle_long_word
many_columns_params = [1, 10]

if os.environ.get('TEST_QUICK'):
many_lines_params = [80, ]
many_columns_params = [25, ]

all_terms_params = 'xterm screen ansi vt220 rxvt cons25 linux'.split()

if os.environ.get('TEST_FULL'):
try:
all_terms_params = [
# use all values of the first column of data in output of 'toe -a'
_term.split(None, 1)[0] for _term in
subprocess.Popen(('toe', '-a'),
stdout=subprocess.PIPE,
close_fds=True)
.communicate()[0].splitlines()]
except OSError:
pass
elif platform.system() == 'Windows':
all_terms_params = ['vtwin10', ]
elif os.environ.get('TEST_QUICK'):
all_terms_params = 'xterm screen ansi linux'.split()


def init_subproc_coverage(run_note):
Expand Down Expand Up @@ -164,8 +136,7 @@ def __call__(self, *args, **kwargs):
assert os.WEXITSTATUS(status) == 0


def read_until_semaphore(fd, semaphore=RECV_SEMAPHORE,
encoding='utf8', timeout=10):
def read_until_semaphore(fd, semaphore=RECV_SEMAPHORE, encoding='utf8'):
"""
Read file descriptor ``fd`` until ``semaphore`` is found.
Expand Down Expand Up @@ -254,21 +225,3 @@ def unicode_parm(cap, *parms):
if val:
return val.decode('latin1')
return u''


@pytest.fixture(params=all_terms_params)
def all_terms(request):
"""Common kind values for all kinds of terminals."""
return request.param


@pytest.fixture(params=many_lines_params)
def many_lines(request):
"""Various number of lines for screen height."""
return request.param


@pytest.fixture(params=many_columns_params)
def many_columns(request):
"""Various number of columns for screen width."""
return request.param
51 changes: 51 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# std imports
import os
import platform
import subprocess

# 3rd party
import pytest

all_terms_params = 'xterm screen ansi vt220 rxvt cons25 linux'.split()
many_lines_params = [40, 80]
# we must test a '1' column for conditional in _handle_long_word
many_columns_params = [1, 10]

if os.environ.get('TEST_FULL'):
try:
all_terms_params = [
# use all values of the first column of data in output of 'toe -a'
_term.split(None, 1)[0] for _term in
subprocess.Popen(('toe', '-a'),
stdout=subprocess.PIPE,
close_fds=True)
.communicate()[0].splitlines()]
except OSError:
pass
elif platform.system() == 'Windows':
all_terms_params = ['vtwin10', ]
elif os.environ.get('TEST_QUICK'):
all_terms_params = 'xterm screen ansi linux'.split()


if os.environ.get('TEST_QUICK'):
many_lines_params = [80, ]
many_columns_params = [25, ]


@pytest.fixture(params=all_terms_params)
def all_terms(request):
"""Common kind values for all kinds of terminals."""
return request.param


@pytest.fixture(params=many_lines_params)
def many_lines(request):
"""Various number of lines for screen height."""
return request.param


@pytest.fixture(params=many_columns_params)
def many_columns(request):
"""Various number of columns for screen width."""
return request.param
2 changes: 1 addition & 1 deletion tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from six.moves import reload_module

# local
from .accessories import TestTerminal, all_terms, unicode_cap, as_subprocess
from .accessories import TestTerminal, unicode_cap, as_subprocess


def test_export_only_Terminal():
Expand Down
2 changes: 1 addition & 1 deletion tests/test_keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import pytest

# local
from .accessories import TestTerminal, all_terms, as_subprocess
from .accessories import TestTerminal, as_subprocess

if platform.system() != 'Windows':
import curses
Expand Down
4 changes: 2 additions & 2 deletions tests/test_length_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
import six
import pytest

from .accessories import ( # isort:skip
TestTerminal, as_subprocess, all_terms, many_lines, many_columns)
# local
from .accessories import TestTerminal, as_subprocess

if platform.system() != 'Windows':
import fcntl
Expand Down
52 changes: 50 additions & 2 deletions tests/test_sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest

# local
from .accessories import TestTerminal, all_terms, unicode_cap, unicode_parm, as_subprocess
from .accessories import TestTerminal, unicode_cap, unicode_parm, as_subprocess


@pytest.mark.skipif(platform.system() == 'Windows', reason="requires real tty")
Expand Down Expand Up @@ -543,9 +543,57 @@ def child(kind):
result = list(term.split_seqs(given_text))
assert result == expected

child(all_terms)


def test_split_seqs_maxsplit1(all_terms):
"""Test Terminal.split_seqs with maxsplit=1."""
@as_subprocess
def child(kind):
from blessed import Terminal
term = Terminal(kind)

if term.bold:
given_text = term.bold + 'bbq'
expected = [term.bold, 'b', 'b', 'q']
expected = [term.bold, 'bbq']
result = list(term.split_seqs(given_text, 1))
assert result == expected

child(all_terms)


def test_split_seqs_term_right(all_terms):
"""Test Terminal.split_seqs with parameterized sequence"""
@as_subprocess
def child(kind):
from blessed import Terminal
term = Terminal(kind)

if term.move_up:
given_text = 'XY' + term.move_right + 'VK'
expected = ['X', 'Y', term.move_right, 'V', 'K']
result = list(term.split_seqs(given_text))
assert result == expected

child(all_terms)


def test_split_seqs_maxsplit3_and_term_right(all_terms):
"""Test Terminal.split_seqs with parameterized sequence."""
@as_subprocess
def child(kind):
from blessed import Terminal
term = Terminal(kind)

if term.move_right(32):
given_text = 'PQ' + term.move_right(32) + 'RS'
expected = ['P', 'Q', term.move_right(32), 'RS']
result = list(term.split_seqs(given_text, 3))
assert result == expected

if term.move_up(45):
given_text = 'XY' + term.move_up(45) + 'VK'
expected = ['X', 'Y', term.move_up(45), 'V', 'K']
result = list(term.split_seqs(given_text))
assert result == expected

Expand Down
2 changes: 1 addition & 1 deletion tests/test_wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pytest

# local
from .accessories import TestTerminal, many_columns, as_subprocess
from .accessories import TestTerminal, as_subprocess

TEXTWRAP_KEYWORD_COMBINATIONS = [
dict(break_long_words=False,
Expand Down
Loading

0 comments on commit 2d75fdc

Please sign in to comment.