diff options
| author | robot-piglet <[email protected]> | 2026-02-09 14:18:13 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2026-02-09 14:37:49 +0300 |
| commit | ec4181e4ae8efc801e773ea358a493722d666231 (patch) | |
| tree | 56620f4966dfdfcb74e750a6fd875180d325d4f8 /contrib/python/wcwidth/py3 | |
| parent | 63535330a604fb3b8980f33ae6abbd046e4bce93 (diff) | |
Intermediate changes
commit_hash:0d521246940b8136d685e6a7302a677e00aea754
Diffstat (limited to 'contrib/python/wcwidth/py3')
| -rw-r--r-- | contrib/python/wcwidth/py3/.dist-info/METADATA | 15 | ||||
| -rw-r--r-- | contrib/python/wcwidth/py3/tests/test_justify.py | 41 | ||||
| -rw-r--r-- | contrib/python/wcwidth/py3/wcwidth/__init__.py | 2 | ||||
| -rw-r--r-- | contrib/python/wcwidth/py3/wcwidth/escape_sequences.py | 4 | ||||
| -rw-r--r-- | contrib/python/wcwidth/py3/wcwidth/grapheme.py | 12 | ||||
| -rw-r--r-- | contrib/python/wcwidth/py3/wcwidth/textwrap.py | 4 | ||||
| -rw-r--r-- | contrib/python/wcwidth/py3/wcwidth/wcwidth.py | 57 | ||||
| -rw-r--r-- | contrib/python/wcwidth/py3/ya.make | 2 |
8 files changed, 78 insertions, 59 deletions
diff --git a/contrib/python/wcwidth/py3/.dist-info/METADATA b/contrib/python/wcwidth/py3/.dist-info/METADATA index 5bdc95adbae..de002938d9d 100644 --- a/contrib/python/wcwidth/py3/.dist-info/METADATA +++ b/contrib/python/wcwidth/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: wcwidth -Version: 0.3.3 +Version: 0.3.5 Summary: Measures the displayed width of unicode strings in a terminal Project-URL: Homepage, https://github.com/jquast/wcwidth Author-email: Jeff Quast <[email protected]> @@ -139,7 +139,7 @@ See `Specification <Specification_from_pypi_>`_ of character measurements. Note width() ------- -Measures width of a string, with improved handling of ``control_codes`` +Use function `width()`_ to measure a string with improved handling of ``control_codes``. .. code-block:: python @@ -472,6 +472,13 @@ languages. History ======= +0.3.5 *2026-01-24* + * **Bugfix** packaging of 0.3.4 contains a failing test. + +0.3.4 *2026-01-24* + * **Bugfix** `center()`_ should match the eccentric `parity padding`_ + of `str.center()`_. `PR #188`_. + 0.3.3 *2026-01-24* * **Performance** improvement in `width()`_. `PR #185`_. * **Bugfix** missing ``py.typed``, ``Typing :: Typed``. `PR #184`_. @@ -483,6 +490,7 @@ History * **Performance** improvement up to 30% in `width()_`. `PR #181`_. 0.3.0 *2026-01-21* + * **Drop Support** for Python 3.6 and 3.7. `PR #156`_. * **New** Function `iter_graphemes()`_. `PR #165`_. * **New** Functions `width()`_ and `iter_sequences()`_. `PR #166`_. * **New** Functions `ljust()`_, `rjust()`_, `center()`_. `PR #168`_. @@ -625,6 +633,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c:: .. _`PR #117`: https://github.com/jquast/wcwidth/pull/117 .. _`PR #146`: https://github.com/jquast/wcwidth/pull/146 .. _`PR #149`: https://github.com/jquast/wcwidth/pull/149 +.. _`PR #156`: https://github.com/jquast/wcwidth/pull/156 .. _`PR #165`: https://github.com/jquast/wcwidth/pull/165 .. _`PR #166`: https://github.com/jquast/wcwidth/pull/166 .. _`PR #168`: https://github.com/jquast/wcwidth/pull/168 @@ -638,6 +647,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c:: .. _`PR #183`: https://github.com/jquast/wcwidth/pull/183 .. _`PR #184`: https://github.com/jquast/wcwidth/pull/184 .. _`PR #185`: https://github.com/jquast/wcwidth/pull/185 +.. _`PR #188`: https://github.com/jquast/wcwidth/pull/188 .. _`Issue #101`: https://github.com/jquast/wcwidth/issues/101 .. _`jquast/blessed`: https://github.com/jquast/blessed .. _`selectel/pyte`: https://github.com/selectel/pyte @@ -689,6 +699,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c:: .. _`iter_sequences()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_sequences .. _`Unicode Standard Annex #29`: https://www.unicode.org/reports/tr29/ .. _`Terminal.detect_ambiguous_width()`: https://blessed.readthedocs.io/en/latest/api/terminal.html#blessed.terminal.Terminal.detect_ambiguous_width +.. _`parity padding`: https://jazcap53.github.io/pythons-eccentric-strcenter.html .. |pypi_downloads| image:: https://img.shields.io/pypi/dm/wcwidth.svg?logo=pypi :alt: Downloads :target: https://pypi.org/project/wcwidth/ diff --git a/contrib/python/wcwidth/py3/tests/test_justify.py b/contrib/python/wcwidth/py3/tests/test_justify.py index 55864bb23a5..71dec6199b6 100644 --- a/contrib/python/wcwidth/py3/tests/test_justify.py +++ b/contrib/python/wcwidth/py3/tests/test_justify.py @@ -10,13 +10,15 @@ EMOJI_FAMILY = '\U0001F468\u200D\U0001F469\u200D\U0001F467' def test_ljust(): - assert ljust('hi', 5) == 'hi ' - assert ljust('', 5) == ' ' - assert ljust('hello', 3) == 'hello' - assert ljust('hello', 5) == 'hello' + # our ljust() matches standard python ljust() for ascii + assert ljust('hi', 5) == 'hi ' == str.ljust('hi', 5) + assert ljust('', 5) == ' ' == str.ljust('', 5) + assert ljust('hello', 3) == 'hello' == str.ljust('hello', 3) + assert ljust('hello', 5) == 'hello' == str.ljust('hello', 5) + assert ljust('hi', 5, fillchar='-') == 'hi---' == str.ljust('hi', 5, '-') + # advanced capabilities assert ljust('\x1b[31mhi\x1b[0m', 5) == '\x1b[31mhi\x1b[0m ' assert ljust('\u4e2d', 4) == '\u4e2d ' - assert ljust('hi', 5, fillchar='-') == 'hi---' assert ljust('hi', 5, fillchar='\u00b7') == 'hi\u00b7\u00b7\u00b7' assert ljust(CJK_WORD, 8) == CJK_WORD + ' ' assert width(ljust(CJK_WORD, 8)) == 8 @@ -27,13 +29,15 @@ def test_ljust(): def test_rjust(): - assert rjust('hi', 5) == ' hi' - assert rjust('', 5) == ' ' - assert rjust('hello', 3) == 'hello' - assert rjust('hello', 5) == 'hello' + # our rjust() matches standard python rjust() for ascii + assert rjust('hi', 5) == ' hi' == str.rjust('hi', 5) + assert rjust('', 5) == ' ' == str.rjust('', 5) + assert rjust('hello', 3) == 'hello' == str.rjust('hello', 3) + assert rjust('hello', 5) == 'hello' == str.rjust('hello', 5) + assert rjust('hi', 5, fillchar='-') == '---hi' == str.rjust('hi', 5, '-') + # advanced capabilities assert rjust('\x1b[31mhi\x1b[0m', 5) == ' \x1b[31mhi\x1b[0m' assert rjust('\u4e2d', 4) == ' \u4e2d' - assert rjust('hi', 5, fillchar='-') == '---hi' assert rjust('hi', 5, fillchar='\u00b7') == '\u00b7\u00b7\u00b7hi' assert rjust(CJK_WORD, 8) == ' ' + CJK_WORD assert width(rjust(CAFE_COMBINING, 8)) == 8 @@ -41,16 +45,19 @@ def test_rjust(): def test_center(): - assert center('hi', 6) == ' hi ' - assert center('hi', 5) == ' hi ' - assert center('', 4) == ' ' - assert center('hello', 3) == 'hello' - assert center('hello', 5) == 'hello' + # our center() matches standard python center() for ascii + assert center('hi', 6) == ' hi ' == str.center('hi', 6) + assert center('hi', 5) == ' hi ' == str.center('hi', 5) + assert center('ab', 7) == ' ab ' == str.center('ab', 7) + assert center('', 4) == ' ' == str.center('', 4) + assert center('hello', 3) == 'hello' == str.center('hello', 3) + assert center('hello', 5) == 'hello' == str.center('hello', 5) + assert center('hi', 6, fillchar='-') == '--hi--' == str.center('hi', 6, '-') + assert center('x', 4) == ' x ' == str.center('x', 4) + # advanced capabilities assert center('\x1b[31mhi\x1b[0m', 6) == ' \x1b[31mhi\x1b[0m ' assert center('\u4e2d', 6) == ' \u4e2d ' - assert center('hi', 6, fillchar='-') == '--hi--' assert center('hi', 6, fillchar='\u00b7') == '\u00b7\u00b7hi\u00b7\u00b7' - assert center('x', 4) == ' x ' assert width(center(CJK_WORD, 8)) == 8 assert width(center(CAFE_COMBINING, 8)) == 8 assert width(center(EMOJI_FAMILY, 6)) == 6 diff --git a/contrib/python/wcwidth/py3/wcwidth/__init__.py b/contrib/python/wcwidth/py3/wcwidth/__init__.py index a2349ffdb93..ed29279dcb8 100644 --- a/contrib/python/wcwidth/py3/wcwidth/__init__.py +++ b/contrib/python/wcwidth/py3/wcwidth/__init__.py @@ -38,4 +38,4 @@ __all__ = ('wcwidth', 'wcswidth', 'width', 'iter_sequences', 'iter_graphemes', # We also used pkg_resources to load unicode version tables from version.json, # generated by bin/update-tables.py, but some environments are unable to # import pkg_resources for one reason or another, yikes! -__version__ = '0.3.3' +__version__ = '0.3.5' diff --git a/contrib/python/wcwidth/py3/wcwidth/escape_sequences.py b/contrib/python/wcwidth/py3/wcwidth/escape_sequences.py index ec51bd3b5bb..d4ac6cc36db 100644 --- a/contrib/python/wcwidth/py3/wcwidth/escape_sequences.py +++ b/contrib/python/wcwidth/py3/wcwidth/escape_sequences.py @@ -2,8 +2,8 @@ r""" Terminal escape sequence patterns. This module provides regex patterns for matching terminal escape sequences. All patterns match -sequences that begin with ESC (\\x1b). Before calling re.match with these patterns, callers should -first check that the character at the current position is ESC for optimal performance. +sequences that begin with ESC (``\x1b``). Before calling re.match with these patterns, callers +should first check that the character at the current position is ESC for optimal performance. """ # std imports import re diff --git a/contrib/python/wcwidth/py3/wcwidth/grapheme.py b/contrib/python/wcwidth/py3/wcwidth/grapheme.py index ba419f4d03f..1a83668b066 100644 --- a/contrib/python/wcwidth/py3/wcwidth/grapheme.py +++ b/contrib/python/wcwidth/py3/wcwidth/grapheme.py @@ -257,12 +257,12 @@ def iter_graphemes( Example:: - >>> list(iter_graphemes('cafe\\u0301')) - ['c', 'a', 'f', 'e\\u0301'] - >>> list(iter_graphemes('\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F467')) - ['o', 'k', '\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F467'] - >>> list(iter_graphemes('\\U0001F1FA\\U0001F1F8')) - ['o', 'k', '\\U0001F1FA\\U0001F1F8'] + >>> list(iter_graphemes('cafe\u0301')) + ['c', 'a', 'f', 'e\u0301'] + >>> list(iter_graphemes('\U0001F468\u200D\U0001F469\u200D\U0001F467')) + ['o', 'k', '\U0001F468\u200D\U0001F469\u200D\U0001F467'] + >>> list(iter_graphemes('\U0001F1FA\U0001F1F8')) + ['o', 'k', '\U0001F1FA\U0001F1F8'] .. versionadded:: 0.3.0 """ diff --git a/contrib/python/wcwidth/py3/wcwidth/textwrap.py b/contrib/python/wcwidth/py3/wcwidth/textwrap.py index 40d3b619065..8b91d6ff9ce 100644 --- a/contrib/python/wcwidth/py3/wcwidth/textwrap.py +++ b/contrib/python/wcwidth/py3/wcwidth/textwrap.py @@ -353,10 +353,10 @@ def wrap(text: str, width: int = 70, *, whitespace and collapsed. To preserve paragraph breaks, wrap each paragraph separately:: - >>> text = 'First line.\\nSecond line.' + >>> text = 'First line.\nSecond line.' >>> wrap(text, 40) # newline collapsed to space ['First line. Second line.'] - >>> [line for para in text.split('\\n') + >>> [line for para in text.split('\n') ... for line in (wrap(para, 40) if para else [''])] ['First line.', 'Second line.'] diff --git a/contrib/python/wcwidth/py3/wcwidth/wcwidth.py b/contrib/python/wcwidth/py3/wcwidth/wcwidth.py index ba4a09a5057..556d1d49a85 100644 --- a/contrib/python/wcwidth/py3/wcwidth/wcwidth.py +++ b/contrib/python/wcwidth/py3/wcwidth/wcwidth.py @@ -398,10 +398,10 @@ def iter_sequences(text: str) -> Iterator[tuple[str, bool]]: >>> list(iter_sequences('hello')) [('hello', False)] - >>> list(iter_sequences('\\x1b[31mred')) - [('\\x1b[31m', True), ('red', False)] - >>> list(iter_sequences('\\x1b[1m\\x1b[31m')) - [('\\x1b[1m', True), ('\\x1b[31m', True)] + >>> list(iter_sequences('\x1b[31mred')) + [('\x1b[31m', True), ('red', False)] + >>> list(iter_sequences('\x1b[1m\x1b[31m')) + [('\x1b[1m', True), ('\x1b[31m', True)] """ idx = 0 text_len = len(text) @@ -461,16 +461,16 @@ def width( :param text: String to measure. :param control_codes: How to handle control characters and sequences: - - ``'parse'`` (default): Track horizontal cursor movement from BS ``\\b``, CR ``\\r``, TAB - ``\\t``, and cursor left and right movement sequences. Vertical movement (LF, VT, FF) and + - ``'parse'`` (default): Track horizontal cursor movement from BS ``\b``, CR ``\r``, TAB + ``\t``, and cursor left and right movement sequences. Vertical movement (LF, VT, FF) and indeterminate sequences are zero-width. Never raises. - ``'strict'``: Like parse, but raises :exc:`ValueError` on control characters with indeterminate results of the screen or cursor, like clear or vertical movement. Generally, these should be handled with a virtual terminal emulator (like 'pyte'). - ``'ignore'``: All C0 and C1 control characters and escape sequences are measured as width 0. This is the fastest measurement for text already filtered or known not to contain - any kinds of control codes or sequences. TAB ``\\t`` is zero-width; for tab expansion, - pre-process: ``text.replace('\\t', ' ' * 8)``. + any kinds of control codes or sequences. TAB ``\t`` is zero-width; for tab expansion, + pre-process: ``text.replace('\t', ' ' * 8)``. :param tabsize: Tab stop width for ``'parse'`` and ``'strict'`` modes. Default is 8. Must be positive. Has no effect when ``control_codes='ignore'``. @@ -492,17 +492,17 @@ def width( 5 >>> width('コンニチハ') 10 - >>> width('\\x1b[31mred\\x1b[0m') + >>> width('\x1b[31mred\x1b[0m') 3 - >>> width('\\x1b[31mred\\x1b[0m', control_codes='ignore') # same result (ignored) + >>> width('\x1b[31mred\x1b[0m', control_codes='ignore') # same result (ignored) 3 - >>> width('123\\b4') # backspace overwrites previous cell (outputs '124') + >>> width('123\b4') # backspace overwrites previous cell (outputs '124') 3 - >>> width('abc\\t') # tab caused cursor to move to column 8 + >>> width('abc\t') # tab caused cursor to move to column 8 8 - >>> width('1\\x1b[10C') # '1' + cursor right 10, cursor ends on column 11 + >>> width('1\x1b[10C') # '1' + cursor right 10, cursor ends on column 11 11 - >>> width('1\\x1b[10C', control_codes='ignore') # faster but wrong in this case + >>> width('1\x1b[10C', control_codes='ignore') # faster but wrong in this case 1 """ # pylint: disable=too-complex,too-many-branches,too-many-statements,too-many-locals @@ -647,9 +647,9 @@ def ljust( >>> wcwidth.ljust('hi', 5) 'hi ' - >>> wcwidth.ljust('\\x1b[31mhi\\x1b[0m', 5) - '\\x1b[31mhi\\x1b[0m ' - >>> wcwidth.ljust('\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F467', 6) + >>> wcwidth.ljust('\x1b[31mhi\x1b[0m', 5) + '\x1b[31mhi\x1b[0m ' + >>> wcwidth.ljust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6) '👨👩👧 ' """ if text.isascii() and text.isprintable(): @@ -688,9 +688,9 @@ def rjust( >>> wcwidth.rjust('hi', 5) ' hi' - >>> wcwidth.rjust('\\x1b[31mhi\\x1b[0m', 5) - ' \\x1b[31mhi\\x1b[0m' - >>> wcwidth.rjust('\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F467', 6) + >>> wcwidth.rjust('\x1b[31mhi\x1b[0m', 5) + ' \x1b[31mhi\x1b[0m' + >>> wcwidth.rjust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6) ' 👨👩👧' """ if text.isascii() and text.isprintable(): @@ -732,9 +732,9 @@ def center( >>> wcwidth.center('hi', 6) ' hi ' - >>> wcwidth.center('\\x1b[31mhi\\x1b[0m', 6) - ' \\x1b[31mhi\\x1b[0m ' - >>> wcwidth.center('\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F467', 6) + >>> wcwidth.center('\x1b[31mhi\x1b[0m', 6) + ' \x1b[31mhi\x1b[0m ' + >>> wcwidth.center('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6) ' 👨👩👧 ' """ if text.isascii() and text.isprintable(): @@ -742,7 +742,8 @@ def center( else: text_width = width(text, control_codes=control_codes, ambiguous_width=ambiguous_width) total_padding = max(0, dest_width - text_width) - left_pad = total_padding // 2 + # matching https://jazcap53.github.io/pythons-eccentric-strcenter.html + left_pad = total_padding // 2 + (total_padding & dest_width & 1) right_pad = total_padding - left_pad return fillchar * left_pad + text + fillchar * right_pad @@ -760,11 +761,11 @@ def strip_sequences(text: str) -> str: Example:: - >>> strip_sequences('\\x1b[31mred\\x1b[0m') + >>> strip_sequences('\x1b[31mred\x1b[0m') 'red' >>> strip_sequences('hello') 'hello' - >>> strip_sequences('\\x1b[1m\\x1b[31mbold red\\x1b[0m text') + >>> strip_sequences('\x1b[1m\x1b[31mbold red\x1b[0m text') 'bold red text' """ return ZERO_WIDTH_PATTERN.sub('', text) @@ -787,7 +788,7 @@ def clip( they have zero display width. If a wide character (width 2) would be split at either boundary, it is replaced with ``fillchar``. - TAB characters (``\\t``) are expanded to spaces up to the next tab stop, + TAB characters (``\t``) are expanded to spaces up to the next tab stop, controlled by the ``tabsize`` parameter. Other cursor movement characters (backspace, carriage return) and cursor @@ -814,7 +815,7 @@ def clip( 'hello' >>> clip('中文字', 0, 3) # Wide char split at column 3 '中 ' - >>> clip('a\\tb', 0, 10) # Tab expanded to spaces + >>> clip('a\tb', 0, 10) # Tab expanded to spaces 'a b' """ # pylint: disable=too-complex,too-many-locals,too-many-branches diff --git a/contrib/python/wcwidth/py3/ya.make b/contrib/python/wcwidth/py3/ya.make index bb124edb88b..36c1c8b8ee2 100644 --- a/contrib/python/wcwidth/py3/ya.make +++ b/contrib/python/wcwidth/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(0.3.3) +VERSION(0.3.5) LICENSE(MIT) |
