mirror of
https://github.com/python/cpython.git
synced 2026-04-14 07:41:00 +00:00
Merge branch 'main' of https://github.com/python/cpython
This commit is contained in:
commit
7fbdc8fb54
15 changed files with 155 additions and 33 deletions
|
|
@ -2247,17 +2247,34 @@ expression support in the :mod:`re` module).
|
|||
>>> '\t'.isprintable(), '\n'.isprintable()
|
||||
(False, False)
|
||||
|
||||
See also :meth:`isspace`.
|
||||
|
||||
|
||||
.. method:: str.isspace()
|
||||
|
||||
Return ``True`` if there are only whitespace characters in the string and there is
|
||||
at least one character, ``False`` otherwise.
|
||||
|
||||
For example:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> ''.isspace()
|
||||
False
|
||||
>>> ' '.isspace()
|
||||
True
|
||||
>>> '\t\n'.isspace() # TAB and BREAK LINE
|
||||
True
|
||||
>>> '\u3000'.isspace() # IDEOGRAPHIC SPACE
|
||||
True
|
||||
|
||||
A character is *whitespace* if in the Unicode character database
|
||||
(see :mod:`unicodedata`), either its general category is ``Zs``
|
||||
("Separator, space"), or its bidirectional class is one of ``WS``,
|
||||
``B``, or ``S``.
|
||||
|
||||
See also :meth:`isprintable`.
|
||||
|
||||
|
||||
.. method:: str.istitle()
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,17 @@ def __repr__(self):
|
|||
return "Type %s() to see the full %s text" % ((self.__name,)*2)
|
||||
|
||||
def __call__(self):
|
||||
from _pyrepl.pager import get_pager
|
||||
try:
|
||||
from _pyrepl.pager import get_pager
|
||||
except ModuleNotFoundError:
|
||||
try:
|
||||
from pydoc import get_pager
|
||||
except ModuleNotFoundError:
|
||||
def get_pager():
|
||||
def _print(text, title=None):
|
||||
print(text)
|
||||
return _print
|
||||
|
||||
self.__setup()
|
||||
|
||||
pager = get_pager()
|
||||
|
|
|
|||
|
|
@ -12,13 +12,16 @@
|
|||
import types
|
||||
import warnings
|
||||
|
||||
from _colorize import get_theme
|
||||
from _pyrepl.console import InteractiveColoredConsole
|
||||
try:
|
||||
from _colorize import get_theme
|
||||
from _pyrepl.console import InteractiveColoredConsole as InteractiveConsole
|
||||
except ModuleNotFoundError:
|
||||
from code import InteractiveConsole
|
||||
|
||||
from . import futures
|
||||
|
||||
|
||||
class AsyncIOInteractiveConsole(InteractiveColoredConsole):
|
||||
class AsyncIOInteractiveConsole(InteractiveConsole):
|
||||
|
||||
def __init__(self, locals, loop):
|
||||
super().__init__(locals, filename="<stdin>")
|
||||
|
|
@ -185,7 +188,10 @@ def interrupt(self) -> None:
|
|||
if os.getenv('PYTHON_BASIC_REPL'):
|
||||
CAN_USE_PYREPL = False
|
||||
else:
|
||||
from _pyrepl.main import CAN_USE_PYREPL
|
||||
try:
|
||||
from _pyrepl.main import CAN_USE_PYREPL
|
||||
except ModuleNotFoundError:
|
||||
CAN_USE_PYREPL = False
|
||||
|
||||
return_code = 0
|
||||
loop = asyncio.new_event_loop()
|
||||
|
|
|
|||
|
|
@ -97,12 +97,16 @@
|
|||
import selectors
|
||||
import threading
|
||||
import _colorize
|
||||
import _pyrepl.utils
|
||||
|
||||
from contextlib import ExitStack, closing, contextmanager
|
||||
from types import CodeType
|
||||
from warnings import deprecated
|
||||
|
||||
try:
|
||||
import _pyrepl.utils
|
||||
except ModuleNotFoundError:
|
||||
_pyrepl = None
|
||||
|
||||
|
||||
class Restart(Exception):
|
||||
"""Causes a debugger to be restarted for the debugged python program."""
|
||||
|
|
@ -1097,7 +1101,7 @@ def handle_command_def(self, line):
|
|||
return False
|
||||
|
||||
def _colorize_code(self, code):
|
||||
if self.colorize:
|
||||
if self.colorize and _pyrepl:
|
||||
colors = list(_pyrepl.utils.gen_colors(code))
|
||||
chars, _ = _pyrepl.utils.disp_str(code, colors=colors, force_color=True)
|
||||
code = "".join(chars)
|
||||
|
|
|
|||
41
Lib/pydoc.py
41
Lib/pydoc.py
|
|
@ -78,20 +78,41 @@ class or function within a module or module in a package. If the
|
|||
from reprlib import Repr
|
||||
from traceback import format_exception_only
|
||||
|
||||
from _pyrepl.pager import (get_pager, pipe_pager,
|
||||
plain_pager, tempfile_pager, tty_pager)
|
||||
try:
|
||||
from _pyrepl.pager import (get_pager, pipe_pager,
|
||||
plain_pager, tempfile_pager, tty_pager)
|
||||
|
||||
# Expose plain() as pydoc.plain()
|
||||
from _pyrepl.pager import plain # noqa: F401
|
||||
# Expose plain() as pydoc.plain()
|
||||
from _pyrepl.pager import plain # noqa: F401
|
||||
|
||||
# --------------------------------------------------------- old names
|
||||
getpager = get_pager
|
||||
pipepager = pipe_pager
|
||||
plainpager = plain_pager
|
||||
tempfilepager = tempfile_pager
|
||||
ttypager = tty_pager
|
||||
|
||||
# --------------------------------------------------------- old names
|
||||
except ModuleNotFoundError:
|
||||
# Minimal alternatives for cases where _pyrepl is absent.
|
||||
|
||||
getpager = get_pager
|
||||
pipepager = pipe_pager
|
||||
plainpager = plain_pager
|
||||
tempfilepager = tempfile_pager
|
||||
ttypager = tty_pager
|
||||
def plain(text: str) -> str:
|
||||
"""Remove boldface formatting from text."""
|
||||
return re.sub('.\b', '', text)
|
||||
|
||||
def plain_pager(text: str, title: str = '') -> None:
|
||||
"""Simply print unformatted text. This is the ultimate fallback."""
|
||||
encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
|
||||
text = text.encode(encoding, 'backslashreplace').decode(encoding)
|
||||
text = plain(text)
|
||||
sys.stdout.write(text)
|
||||
|
||||
def get_pager():
|
||||
"""Unconditionally return the plain pager, since _pyrepl is absent."""
|
||||
return plain_pager
|
||||
|
||||
# --------------------------------------------------------- old names
|
||||
getpager = get_pager
|
||||
plainpager = plain_pager
|
||||
|
||||
|
||||
# --------------------------------------------------------- common routines
|
||||
|
|
|
|||
|
|
@ -529,6 +529,8 @@ def register_readline():
|
|||
import _pyrepl.unix_console
|
||||
console_errors = _pyrepl.unix_console._error
|
||||
from _pyrepl.main import CAN_USE_PYREPL
|
||||
except ModuleNotFoundError:
|
||||
CAN_USE_PYREPL = False
|
||||
finally:
|
||||
sys.path = original_path
|
||||
except ImportError:
|
||||
|
|
|
|||
|
|
@ -3023,6 +3023,13 @@ def force_color(color: bool):
|
|||
import _colorize
|
||||
from .os_helper import EnvironmentVarGuard
|
||||
|
||||
if color:
|
||||
try:
|
||||
import _pyrepl # noqa: F401
|
||||
except ModuleNotFoundError:
|
||||
# Can't force enable color without _pyrepl, so just skip.
|
||||
raise unittest.SkipTest("_pyrepl is missing")
|
||||
|
||||
with (
|
||||
swap_attr(_colorize, "can_colorize", lambda *, file=None: color),
|
||||
EnvironmentVarGuard() as env,
|
||||
|
|
|
|||
|
|
@ -204,5 +204,20 @@ def default_factory():
|
|||
self.assertEqual(test_dict[key], 2)
|
||||
self.assertEqual(count, 2)
|
||||
|
||||
def test_repr_recursive_factory(self):
|
||||
# gh-145492: defaultdict.__repr__ should not cause infinite recursion
|
||||
# when the factory's __repr__ calls repr() on the defaultdict.
|
||||
class ProblematicFactory:
|
||||
def __call__(self):
|
||||
return {}
|
||||
def __repr__(self):
|
||||
repr(dd)
|
||||
return "ProblematicFactory()"
|
||||
|
||||
dd = defaultdict(ProblematicFactory())
|
||||
# Should not raise RecursionError
|
||||
r = repr(dd)
|
||||
self.assertIn('ProblematicFactory()', r)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ def test_others(self):
|
|||
ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'curframe_locals',
|
||||
'_InteractState', 'rlcompleter'),
|
||||
)
|
||||
cm('pydoc', ignore=('input', 'output',)) # properties
|
||||
cm('pydoc', ignore=('input', 'output', # properties
|
||||
'getpager', 'plainpager', )) # aliases
|
||||
|
||||
# Tests for modules inside packages
|
||||
cm('email.parser')
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
from test.support import import_helper, load_package_tests
|
||||
|
||||
|
||||
import_helper.import_module("_pyrepl")
|
||||
|
||||
|
||||
if sys.platform != "win32":
|
||||
import_helper.import_module("termios")
|
||||
|
||||
|
|
|
|||
|
|
@ -426,6 +426,13 @@ def test_toplevel_contextvars_async(self):
|
|||
p = spawn_asyncio_repl()
|
||||
p.stdin.write(user_input)
|
||||
user_input2 = "async def set_var(): var.set('ok')\n"
|
||||
try:
|
||||
import _pyrepl # noqa: F401
|
||||
except ModuleNotFoundError:
|
||||
# If we're going to be forced into the regular REPL, then we need an
|
||||
# extra newline here. Omit it by default to catch any breakage to
|
||||
# the new REPL's behavior.
|
||||
user_input2 += "\n"
|
||||
p.stdin.write(user_input2)
|
||||
user_input3 = "await set_var()\n"
|
||||
p.stdin.write(user_input3)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
Allows omitting the internal library ``_pyrepl`` with limited loss of
|
||||
functionality. This allows complete removal of the modern REPL, which is an
|
||||
unsupported configuration, but still desirable for some distributions.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Fix infinite recursion in :class:`collections.defaultdict` ``__repr__``
|
||||
when a ``defaultdict`` contains itself. Based on analysis by KowalskiThomas
|
||||
in :gh:`145492`.
|
||||
|
|
@ -2385,9 +2385,10 @@ defdict_repr(PyObject *op)
|
|||
}
|
||||
defrepr = PyUnicode_FromString("...");
|
||||
}
|
||||
else
|
||||
else {
|
||||
defrepr = PyObject_Repr(dd->default_factory);
|
||||
Py_ReprLeave(dd->default_factory);
|
||||
Py_ReprLeave(dd->default_factory);
|
||||
}
|
||||
}
|
||||
if (defrepr == NULL) {
|
||||
Py_DECREF(baserepr);
|
||||
|
|
|
|||
|
|
@ -562,13 +562,25 @@ pymain_run_stdin(PyConfig *config)
|
|||
return pymain_exit_err_print();
|
||||
}
|
||||
|
||||
if (!isatty(fileno(stdin))
|
||||
|| _Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL")) {
|
||||
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
||||
int run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
|
||||
return (run != 0);
|
||||
int run;
|
||||
if (isatty(fileno(stdin))
|
||||
&& !_Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL")) {
|
||||
PyObject *pyrepl = PyImport_ImportModule("_pyrepl");
|
||||
if (pyrepl != NULL) {
|
||||
run = pymain_start_pyrepl(0);
|
||||
Py_DECREF(pyrepl);
|
||||
return run;
|
||||
}
|
||||
if (!PyErr_ExceptionMatches(PyExc_ModuleNotFoundError)) {
|
||||
fprintf(stderr, "Could not import _pyrepl.main\n");
|
||||
return pymain_exit_err_print();
|
||||
}
|
||||
PyErr_Clear();
|
||||
}
|
||||
return pymain_start_pyrepl(0);
|
||||
|
||||
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
||||
run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
|
||||
return (run != 0);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -594,14 +606,24 @@ pymain_repl(PyConfig *config, int *exitcode)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!isatty(fileno(stdin))
|
||||
|| _Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL")) {
|
||||
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
||||
int run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
|
||||
*exitcode = (run != 0);
|
||||
return;
|
||||
if (isatty(fileno(stdin))
|
||||
&& !_Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL")) {
|
||||
PyObject *pyrepl = PyImport_ImportModule("_pyrepl");
|
||||
if (pyrepl != NULL) {
|
||||
int run = pymain_start_pyrepl(1);
|
||||
*exitcode = (run != 0);
|
||||
Py_DECREF(pyrepl);
|
||||
return;
|
||||
}
|
||||
if (!PyErr_ExceptionMatches(PyExc_ModuleNotFoundError)) {
|
||||
PyErr_Clear();
|
||||
fprintf(stderr, "Could not import _pyrepl.main\n");
|
||||
return;
|
||||
}
|
||||
PyErr_Clear();
|
||||
}
|
||||
int run = pymain_start_pyrepl(1);
|
||||
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
||||
int run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
|
||||
*exitcode = (run != 0);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue