mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-131507: Clean up tests and type checking for _pyrepl
(#131509)
This commit is contained in:
parent
d3f6063af1
commit
5d8e981c84
14 changed files with 234 additions and 135 deletions
|
@ -456,7 +456,7 @@ class invalid_command(Command):
|
|||
class show_history(Command):
|
||||
def do(self) -> None:
|
||||
from .pager import get_pager
|
||||
from site import gethistoryfile # type: ignore[attr-defined]
|
||||
from site import gethistoryfile
|
||||
|
||||
history = os.linesep.join(self.reader.history[:])
|
||||
self.reader.console.restore()
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import _colorize # type: ignore[import-not-found]
|
||||
import _colorize
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
import ast
|
||||
|
@ -162,7 +162,7 @@ class InteractiveColoredConsole(code.InteractiveConsole):
|
|||
*,
|
||||
local_exit: bool = False,
|
||||
) -> None:
|
||||
super().__init__(locals=locals, filename=filename, local_exit=local_exit) # type: ignore[call-arg]
|
||||
super().__init__(locals=locals, filename=filename, local_exit=local_exit)
|
||||
self.can_colorize = _colorize.can_colorize()
|
||||
|
||||
def showsyntaxerror(self, filename=None, **kwargs):
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
[mypy]
|
||||
files = Lib/_pyrepl
|
||||
mypy_path = $MYPY_CONFIG_FILE_DIR/../../Misc/mypy
|
||||
explicit_package_bases = True
|
||||
python_version = 3.12
|
||||
python_version = 3.13
|
||||
platform = linux
|
||||
pretty = True
|
||||
|
||||
|
@ -22,3 +23,7 @@ check_untyped_defs = False
|
|||
# Various internal modules that typeshed deliberately doesn't have stubs for:
|
||||
[mypy-_abc.*,_opcode.*,_overlapped.*,_testcapi.*,_testinternalcapi.*,test.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
# Other untyped parts of the stdlib
|
||||
[mypy-idlelib.*]
|
||||
ignore_missing_imports = True
|
||||
|
|
|
@ -26,11 +26,11 @@ import sys
|
|||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass, field, fields
|
||||
import unicodedata
|
||||
from _colorize import can_colorize, ANSIColors # type: ignore[import-not-found]
|
||||
from _colorize import can_colorize, ANSIColors
|
||||
|
||||
|
||||
from . import commands, console, input
|
||||
from .utils import ANSI_ESCAPE_SEQUENCE, wlen, str_width
|
||||
from .utils import wlen, unbracket, str_width
|
||||
from .trace import trace
|
||||
|
||||
|
||||
|
@ -421,42 +421,15 @@ class Reader:
|
|||
|
||||
@staticmethod
|
||||
def process_prompt(prompt: str) -> tuple[str, int]:
|
||||
"""Process the prompt.
|
||||
r"""Return a tuple with the prompt string and its visible length.
|
||||
|
||||
This means calculate the length of the prompt. The character \x01
|
||||
and \x02 are used to bracket ANSI control sequences and need to be
|
||||
excluded from the length calculation. So also a copy of the prompt
|
||||
is returned with these control characters removed."""
|
||||
|
||||
# The logic below also ignores the length of common escape
|
||||
# sequences if they were not explicitly within \x01...\x02.
|
||||
# They are CSI (or ANSI) sequences ( ESC [ ... LETTER )
|
||||
|
||||
# wlen from utils already excludes ANSI_ESCAPE_SEQUENCE chars,
|
||||
# which breaks the logic below so we redefine it here.
|
||||
def wlen(s: str) -> int:
|
||||
return sum(str_width(i) for i in s)
|
||||
|
||||
out_prompt = ""
|
||||
l = wlen(prompt)
|
||||
pos = 0
|
||||
while True:
|
||||
s = prompt.find("\x01", pos)
|
||||
if s == -1:
|
||||
break
|
||||
e = prompt.find("\x02", s)
|
||||
if e == -1:
|
||||
break
|
||||
# Found start and end brackets, subtract from string length
|
||||
l = l - (e - s + 1)
|
||||
keep = prompt[pos:s]
|
||||
l -= sum(map(wlen, ANSI_ESCAPE_SEQUENCE.findall(keep)))
|
||||
out_prompt += keep + prompt[s + 1 : e]
|
||||
pos = e + 1
|
||||
keep = prompt[pos:]
|
||||
l -= sum(map(wlen, ANSI_ESCAPE_SEQUENCE.findall(keep)))
|
||||
out_prompt += keep
|
||||
return out_prompt, l
|
||||
The prompt string has the zero-width brackets recognized by shells
|
||||
(\x01 and \x02) removed. The length ignores anything between those
|
||||
brackets as well as any ANSI escape sequences.
|
||||
"""
|
||||
out_prompt = unbracket(prompt, including_content=False)
|
||||
visible_prompt = unbracket(prompt, including_content=True)
|
||||
return out_prompt, wlen(visible_prompt)
|
||||
|
||||
def bow(self, p: int | None = None) -> int:
|
||||
"""Return the 0-based index of the word break preceding p most
|
||||
|
|
|
@ -32,7 +32,7 @@ import warnings
|
|||
from dataclasses import dataclass, field
|
||||
|
||||
import os
|
||||
from site import gethistoryfile # type: ignore[attr-defined]
|
||||
from site import gethistoryfile
|
||||
import sys
|
||||
from rlcompleter import Completer as RLCompleter
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ import unicodedata
|
|||
import functools
|
||||
|
||||
ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]")
|
||||
ZERO_WIDTH_BRACKET = re.compile(r"\x01.*?\x02")
|
||||
ZERO_WIDTH_TRANS = str.maketrans({"\x01": "", "\x02": ""})
|
||||
|
||||
|
||||
@functools.cache
|
||||
|
@ -10,16 +12,27 @@ def str_width(c: str) -> int:
|
|||
if ord(c) < 128:
|
||||
return 1
|
||||
w = unicodedata.east_asian_width(c)
|
||||
if w in ('N', 'Na', 'H', 'A'):
|
||||
if w in ("N", "Na", "H", "A"):
|
||||
return 1
|
||||
return 2
|
||||
|
||||
|
||||
def wlen(s: str) -> int:
|
||||
if len(s) == 1 and s != '\x1a':
|
||||
if len(s) == 1 and s != "\x1a":
|
||||
return str_width(s)
|
||||
length = sum(str_width(i) for i in s)
|
||||
# remove lengths of any escape sequences
|
||||
sequence = ANSI_ESCAPE_SEQUENCE.findall(s)
|
||||
ctrl_z_cnt = s.count('\x1a')
|
||||
ctrl_z_cnt = s.count("\x1a")
|
||||
return length - sum(len(i) for i in sequence) + ctrl_z_cnt
|
||||
|
||||
|
||||
def unbracket(s: str, including_content: bool = False) -> str:
|
||||
r"""Return `s` with \001 and \002 characters removed.
|
||||
|
||||
If `including_content` is True, content between \001 and \002 is also
|
||||
stripped.
|
||||
"""
|
||||
if including_content:
|
||||
return ZERO_WIDTH_BRACKET.sub("", s)
|
||||
return s.translate(ZERO_WIDTH_TRANS)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue