summaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2026-02-09 14:18:13 +0300
committerrobot-piglet <[email protected]>2026-02-09 14:37:49 +0300
commitec4181e4ae8efc801e773ea358a493722d666231 (patch)
tree56620f4966dfdfcb74e750a6fd875180d325d4f8 /contrib/python
parent63535330a604fb3b8980f33ae6abbd046e4bce93 (diff)
Intermediate changes
commit_hash:0d521246940b8136d685e6a7302a677e00aea754
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/wcwidth/py3/.dist-info/METADATA15
-rw-r--r--contrib/python/wcwidth/py3/tests/test_justify.py41
-rw-r--r--contrib/python/wcwidth/py3/wcwidth/__init__.py2
-rw-r--r--contrib/python/wcwidth/py3/wcwidth/escape_sequences.py4
-rw-r--r--contrib/python/wcwidth/py3/wcwidth/grapheme.py12
-rw-r--r--contrib/python/wcwidth/py3/wcwidth/textwrap.py4
-rw-r--r--contrib/python/wcwidth/py3/wcwidth/wcwidth.py57
-rw-r--r--contrib/python/wcwidth/py3/ya.make2
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)