Skip to content

Commit

Permalink
Merge branch 'main' into pythongh-125413-info
Browse files Browse the repository at this point in the history
  • Loading branch information
barneygale authored Jan 21, 2025
2 parents 60b3ac4 + 29caec6 commit 7658dc8
Show file tree
Hide file tree
Showing 19 changed files with 166 additions and 84 deletions.
10 changes: 2 additions & 8 deletions Doc/library/__main__.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,7 @@ Here is an example module that consumes the ``__main__`` namespace::
if not did_user_define_their_name():
raise ValueError('Define the variable `my_name`!')

if '__file__' in dir(__main__):
print(__main__.my_name, "found in file", __main__.__file__)
else:
print(__main__.my_name)
print(__main__.my_name)

Example usage of this module could be as follows::

Expand Down Expand Up @@ -330,7 +327,7 @@ status code 0, indicating success:
.. code-block:: shell-session
$ python start.py
Dinsdale found in file /path/to/start.py
Dinsdale
Note that importing ``__main__`` doesn't cause any issues with unintentionally
running top-level code meant for script use which is put in the
Expand Down Expand Up @@ -361,8 +358,5 @@ defined in the REPL becomes part of the ``__main__`` scope::
>>> namely.print_user_name()
Jabberwocky

Note that in this case the ``__main__`` scope doesn't contain a ``__file__``
attribute as it's interactive.

The ``__main__`` scope is used in the implementation of :mod:`pdb` and
:mod:`rlcompleter`.
6 changes: 4 additions & 2 deletions Doc/reference/compound_stmts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1217,8 +1217,10 @@ A function definition defines a user-defined function object (see section
: | `parameter_list_no_posonly`
parameter_list_no_posonly: `defparameter` ("," `defparameter`)* ["," [`parameter_list_starargs`]]
: | `parameter_list_starargs`
parameter_list_starargs: "*" [`star_parameter`] ("," `defparameter`)* ["," ["**" `parameter` [","]]]
: | "**" `parameter` [","]
parameter_list_starargs: "*" [`star_parameter`] ("," `defparameter`)* ["," [`parameter_star_kwargs`]]
: "*" ("," `defparameter`)+ ["," [`parameter_star_kwargs`]]
: | `parameter_star_kwargs`
parameter_star_kwargs: "**" `parameter` [","]
parameter: `identifier` [":" `expression`]
star_parameter: `identifier` [":" ["*"] `expression`]
defparameter: `parameter` ["=" `expression`]
Expand Down
2 changes: 1 addition & 1 deletion Doc/using/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@ conflict.

.. envvar:: PYTHON_BASIC_REPL

If this variable is set to ``1``, the interpreter will not attempt to
If this variable is set to any value, the interpreter will not attempt to
load the Python-based :term:`REPL` that requires :mod:`curses` and
:mod:`readline`, and will instead use the traditional parser-based
:term:`REPL`.
Expand Down
18 changes: 12 additions & 6 deletions Lib/_pyrepl/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def do(self) -> None:
x, y = r.pos2xy()
new_y = y + 1

if new_y > r.max_row():
if r.eol() == len(b):
if r.historyi < len(r.history):
r.select_item(r.historyi + 1)
r.pos = r.eol(0)
Expand All @@ -309,7 +309,7 @@ def do(self) -> None:
class left(MotionCommand):
def do(self) -> None:
r = self.reader
for i in range(r.get_arg()):
for _ in range(r.get_arg()):
p = r.pos - 1
if p >= 0:
r.pos = p
Expand All @@ -321,7 +321,7 @@ class right(MotionCommand):
def do(self) -> None:
r = self.reader
b = r.buffer
for i in range(r.get_arg()):
for _ in range(r.get_arg()):
p = r.pos + 1
if p <= len(b):
r.pos = p
Expand Down Expand Up @@ -459,9 +459,15 @@ def do(self) -> None:
from site import gethistoryfile # type: ignore[attr-defined]

history = os.linesep.join(self.reader.history[:])
with self.reader.suspend():
pager = get_pager()
pager(history, gethistoryfile())
self.reader.console.restore()
pager = get_pager()
pager(history, gethistoryfile())
self.reader.console.prepare()

# We need to copy over the state so that it's consistent between
# console and reader, and console does not overwrite/append stuff
self.reader.console.screen = self.reader.screen.copy()
self.reader.console.posxy = self.reader.cxy


class paste_mode(Command):
Expand Down
11 changes: 8 additions & 3 deletions Lib/_pyrepl/completing_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,15 @@ def after_command(self, cmd: Command) -> None:
def calc_screen(self) -> list[str]:
screen = super().calc_screen()
if self.cmpltn_menu_visible:
ly = self.lxy[1]
# We display the completions menu below the current prompt
ly = self.lxy[1] + 1
screen[ly:ly] = self.cmpltn_menu
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu)
self.cxy = self.cxy[0], self.cxy[1] + len(self.cmpltn_menu)
# If we're not in the middle of multiline edit, don't append to screeninfo
# since that screws up the position calculation in pos2xy function.
# This is a hack to prevent the cursor jumping
# into the completions menu when pressing left or down arrow.
if self.pos != len(self.buffer):
self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu)
return screen

def finish(self) -> None:
Expand Down
1 change: 1 addition & 0 deletions Lib/_pyrepl/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Event:

@dataclass
class Console(ABC):
posxy: tuple[int, int]
screen: list[str] = field(default_factory=list)
height: int = 25
width: int = 80
Expand Down
18 changes: 11 additions & 7 deletions Lib/_pyrepl/historical_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,17 @@ def get_item(self, i: int) -> str:

@contextmanager
def suspend(self) -> SimpleContextManager:
with super().suspend():
try:
old_history = self.history[:]
del self.history[:]
yield
finally:
self.history[:] = old_history
with super().suspend(), self.suspend_history():
yield

@contextmanager
def suspend_history(self) -> SimpleContextManager:
try:
old_history = self.history[:]
del self.history[:]
yield
finally:
self.history[:] = old_history

def prepare(self) -> None:
super().prepare()
Expand Down
16 changes: 4 additions & 12 deletions Lib/_pyrepl/simple_interact.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _clear_screen():
"exit": _sitebuiltins.Quitter('exit', ''),
"quit": _sitebuiltins.Quitter('quit' ,''),
"copyright": _sitebuiltins._Printer('copyright', sys.copyright),
"help": "help",
"help": _sitebuiltins._Helper(),
"clear": _clear_screen,
"\x1a": _sitebuiltins.Quitter('\x1a', ''),
}
Expand Down Expand Up @@ -124,18 +124,10 @@ def maybe_run_command(statement: str) -> bool:
reader.history.pop() # skip internal commands in history
command = REPL_COMMANDS[statement]
if callable(command):
command()
# Make sure that history does not change because of commands
with reader.suspend_history():
command()
return True

if isinstance(command, str):
# Internal readline commands require a prepared reader like
# inside multiline_input.
reader.prepare()
reader.refresh()
reader.do_cmd((command, [statement]))
reader.restore()
return True

return False

while True:
Expand Down
48 changes: 26 additions & 22 deletions Lib/_pyrepl/unix_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def refresh(self, screen, c_xy):
self.__hide_cursor()
self.__move(0, len(self.screen) - 1)
self.__write("\n")
self.__posxy = 0, len(self.screen)
self.posxy = 0, len(self.screen)
self.screen.append("")
else:
while len(self.screen) < len(screen):
Expand All @@ -250,7 +250,7 @@ def refresh(self, screen, c_xy):
self.__gone_tall = 1
self.__move = self.__move_tall

px, py = self.__posxy
px, py = self.posxy
old_offset = offset = self.__offset
height = self.height

Expand All @@ -271,15 +271,15 @@ def refresh(self, screen, c_xy):
if old_offset > offset and self._ri:
self.__hide_cursor()
self.__write_code(self._cup, 0, 0)
self.__posxy = 0, old_offset
self.posxy = 0, old_offset
for i in range(old_offset - offset):
self.__write_code(self._ri)
oldscr.pop(-1)
oldscr.insert(0, "")
elif old_offset < offset and self._ind:
self.__hide_cursor()
self.__write_code(self._cup, self.height - 1, 0)
self.__posxy = 0, old_offset + self.height - 1
self.posxy = 0, old_offset + self.height - 1
for i in range(offset - old_offset):
self.__write_code(self._ind)
oldscr.pop(0)
Expand All @@ -299,7 +299,7 @@ def refresh(self, screen, c_xy):
while y < len(oldscr):
self.__hide_cursor()
self.__move(0, y)
self.__posxy = 0, y
self.posxy = 0, y
self.__write_code(self._el)
y += 1

Expand All @@ -321,7 +321,7 @@ def move_cursor(self, x, y):
self.event_queue.insert(Event("scroll", None))
else:
self.__move(x, y)
self.__posxy = x, y
self.posxy = x, y
self.flushoutput()

def prepare(self):
Expand Down Expand Up @@ -350,7 +350,7 @@ def prepare(self):

self.__buffer = []

self.__posxy = 0, 0
self.posxy = 0, 0
self.__gone_tall = 0
self.__move = self.__move_short
self.__offset = 0
Expand Down Expand Up @@ -559,7 +559,7 @@ def clear(self):
self.__write_code(self._clear)
self.__gone_tall = 1
self.__move = self.__move_tall
self.__posxy = 0, 0
self.posxy = 0, 0
self.screen = []

@property
Expand Down Expand Up @@ -644,8 +644,8 @@ def __write_changed_line(self, y, oldline, newline, px_coord):
# if we need to insert a single character right after the first detected change
if oldline[x_pos:] == newline[x_pos + 1 :] and self.ich1:
if (
y == self.__posxy[1]
and x_coord > self.__posxy[0]
y == self.posxy[1]
and x_coord > self.posxy[0]
and oldline[px_pos:x_pos] == newline[px_pos + 1 : x_pos + 1]
):
x_pos = px_pos
Expand All @@ -654,7 +654,7 @@ def __write_changed_line(self, y, oldline, newline, px_coord):
self.__move(x_coord, y)
self.__write_code(self.ich1)
self.__write(newline[x_pos])
self.__posxy = x_coord + character_width, y
self.posxy = x_coord + character_width, y

# if it's a single character change in the middle of the line
elif (
Expand All @@ -665,7 +665,7 @@ def __write_changed_line(self, y, oldline, newline, px_coord):
character_width = wlen(newline[x_pos])
self.__move(x_coord, y)
self.__write(newline[x_pos])
self.__posxy = x_coord + character_width, y
self.posxy = x_coord + character_width, y

# if this is the last character to fit in the line and we edit in the middle of the line
elif (
Expand All @@ -677,22 +677,22 @@ def __write_changed_line(self, y, oldline, newline, px_coord):
):
self.__hide_cursor()
self.__move(self.width - 2, y)
self.__posxy = self.width - 2, y
self.posxy = self.width - 2, y
self.__write_code(self.dch1)

character_width = wlen(newline[x_pos])
self.__move(x_coord, y)
self.__write_code(self.ich1)
self.__write(newline[x_pos])
self.__posxy = character_width + 1, y
self.posxy = character_width + 1, y

else:
self.__hide_cursor()
self.__move(x_coord, y)
if wlen(oldline) > wlen(newline):
self.__write_code(self._el)
self.__write(newline[x_pos:])
self.__posxy = wlen(newline), y
self.posxy = wlen(newline), y

if "\x1b" in newline:
# ANSI escape characters are present, so we can't assume
Expand All @@ -711,32 +711,36 @@ def __maybe_write_code(self, fmt, *args):
self.__write_code(fmt, *args)

def __move_y_cuu1_cud1(self, y):
dy = y - self.__posxy[1]
assert self._cud1 is not None
assert self._cuu1 is not None
dy = y - self.posxy[1]
if dy > 0:
self.__write_code(dy * self._cud1)
elif dy < 0:
self.__write_code((-dy) * self._cuu1)

def __move_y_cuu_cud(self, y):
dy = y - self.__posxy[1]
dy = y - self.posxy[1]
if dy > 0:
self.__write_code(self._cud, dy)
elif dy < 0:
self.__write_code(self._cuu, -dy)

def __move_x_hpa(self, x: int) -> None:
if x != self.__posxy[0]:
if x != self.posxy[0]:
self.__write_code(self._hpa, x)

def __move_x_cub1_cuf1(self, x: int) -> None:
dx = x - self.__posxy[0]
assert self._cuf1 is not None
assert self._cub1 is not None
dx = x - self.posxy[0]
if dx > 0:
self.__write_code(self._cuf1 * dx)
elif dx < 0:
self.__write_code(self._cub1 * (-dx))

def __move_x_cub_cuf(self, x: int) -> None:
dx = x - self.__posxy[0]
dx = x - self.posxy[0]
if dx > 0:
self.__write_code(self._cuf, dx)
elif dx < 0:
Expand Down Expand Up @@ -766,12 +770,12 @@ def __show_cursor(self):

def repaint(self):
if not self.__gone_tall:
self.__posxy = 0, self.__posxy[1]
self.posxy = 0, self.posxy[1]
self.__write("\r")
ns = len(self.screen) * ["\000" * self.width]
self.screen = ns
else:
self.__posxy = 0, self.__offset
self.posxy = 0, self.__offset
self.__move(0, self.__offset)
ns = self.height * ["\000" * self.width]
self.screen = ns
Expand Down
2 changes: 1 addition & 1 deletion Lib/_pyrepl/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def str_width(c: str) -> int:


def wlen(s: str) -> int:
if len(s) == 1:
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
Expand Down
Loading

0 comments on commit 7658dc8

Please sign in to comment.