Skip to content

Commit 7fbdc8f

Browse files
committed
Merge branch 'main' of https://github.com/python/cpython
2 parents 1900aa9 + 9585f50 commit 7fbdc8f

File tree

15 files changed

+159
-37
lines changed

15 files changed

+159
-37
lines changed

Doc/library/stdtypes.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,17 +2247,34 @@ expression support in the :mod:`re` module).
22472247
>>> '\t'.isprintable(), '\n'.isprintable()
22482248
(False, False)
22492249

2250+
See also :meth:`isspace`.
2251+
22502252

22512253
.. method:: str.isspace()
22522254

22532255
Return ``True`` if there are only whitespace characters in the string and there is
22542256
at least one character, ``False`` otherwise.
22552257

2258+
For example:
2259+
2260+
.. doctest::
2261+
2262+
>>> ''.isspace()
2263+
False
2264+
>>> ' '.isspace()
2265+
True
2266+
>>> '\t\n'.isspace() # TAB and BREAK LINE
2267+
True
2268+
>>> '\u3000'.isspace() # IDEOGRAPHIC SPACE
2269+
True
2270+
22562271
A character is *whitespace* if in the Unicode character database
22572272
(see :mod:`unicodedata`), either its general category is ``Zs``
22582273
("Separator, space"), or its bidirectional class is one of ``WS``,
22592274
``B``, or ``S``.
22602275

2276+
See also :meth:`isprintable`.
2277+
22612278

22622279
.. method:: str.istitle()
22632280

Lib/_sitebuiltins.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,17 @@ def __repr__(self):
6565
return "Type %s() to see the full %s text" % ((self.__name,)*2)
6666

6767
def __call__(self):
68-
from _pyrepl.pager import get_pager
68+
try:
69+
from _pyrepl.pager import get_pager
70+
except ModuleNotFoundError:
71+
try:
72+
from pydoc import get_pager
73+
except ModuleNotFoundError:
74+
def get_pager():
75+
def _print(text, title=None):
76+
print(text)
77+
return _print
78+
6979
self.__setup()
7080

7181
pager = get_pager()

Lib/asyncio/__main__.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
import types
1313
import warnings
1414

15-
from _colorize import get_theme
16-
from _pyrepl.console import InteractiveColoredConsole
15+
try:
16+
from _colorize import get_theme
17+
from _pyrepl.console import InteractiveColoredConsole as InteractiveConsole
18+
except ModuleNotFoundError:
19+
from code import InteractiveConsole
1720

1821
from . import futures
1922

2023

21-
class AsyncIOInteractiveConsole(InteractiveColoredConsole):
24+
class AsyncIOInteractiveConsole(InteractiveConsole):
2225

2326
def __init__(self, locals, loop):
2427
super().__init__(locals, filename="<stdin>")
@@ -185,7 +188,10 @@ def interrupt(self) -> None:
185188
if os.getenv('PYTHON_BASIC_REPL'):
186189
CAN_USE_PYREPL = False
187190
else:
188-
from _pyrepl.main import CAN_USE_PYREPL
191+
try:
192+
from _pyrepl.main import CAN_USE_PYREPL
193+
except ModuleNotFoundError:
194+
CAN_USE_PYREPL = False
189195

190196
return_code = 0
191197
loop = asyncio.new_event_loop()

Lib/pdb.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,16 @@
9797
import selectors
9898
import threading
9999
import _colorize
100-
import _pyrepl.utils
101100

102101
from contextlib import ExitStack, closing, contextmanager
103102
from types import CodeType
104103
from warnings import deprecated
105104

105+
try:
106+
import _pyrepl.utils
107+
except ModuleNotFoundError:
108+
_pyrepl = None
109+
106110

107111
class Restart(Exception):
108112
"""Causes a debugger to be restarted for the debugged python program."""
@@ -1097,7 +1101,7 @@ def handle_command_def(self, line):
10971101
return False
10981102

10991103
def _colorize_code(self, code):
1100-
if self.colorize:
1104+
if self.colorize and _pyrepl:
11011105
colors = list(_pyrepl.utils.gen_colors(code))
11021106
chars, _ = _pyrepl.utils.disp_str(code, colors=colors, force_color=True)
11031107
code = "".join(chars)

Lib/pydoc.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,41 @@ class or function within a module or module in a package. If the
7878
from reprlib import Repr
7979
from traceback import format_exception_only
8080

81-
from _pyrepl.pager import (get_pager, pipe_pager,
82-
plain_pager, tempfile_pager, tty_pager)
83-
84-
# Expose plain() as pydoc.plain()
85-
from _pyrepl.pager import plain # noqa: F401
86-
87-
88-
# --------------------------------------------------------- old names
89-
90-
getpager = get_pager
91-
pipepager = pipe_pager
92-
plainpager = plain_pager
93-
tempfilepager = tempfile_pager
94-
ttypager = tty_pager
81+
try:
82+
from _pyrepl.pager import (get_pager, pipe_pager,
83+
plain_pager, tempfile_pager, tty_pager)
84+
85+
# Expose plain() as pydoc.plain()
86+
from _pyrepl.pager import plain # noqa: F401
87+
88+
# --------------------------------------------------------- old names
89+
getpager = get_pager
90+
pipepager = pipe_pager
91+
plainpager = plain_pager
92+
tempfilepager = tempfile_pager
93+
ttypager = tty_pager
94+
95+
except ModuleNotFoundError:
96+
# Minimal alternatives for cases where _pyrepl is absent.
97+
98+
def plain(text: str) -> str:
99+
"""Remove boldface formatting from text."""
100+
return re.sub('.\b', '', text)
101+
102+
def plain_pager(text: str, title: str = '') -> None:
103+
"""Simply print unformatted text. This is the ultimate fallback."""
104+
encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
105+
text = text.encode(encoding, 'backslashreplace').decode(encoding)
106+
text = plain(text)
107+
sys.stdout.write(text)
108+
109+
def get_pager():
110+
"""Unconditionally return the plain pager, since _pyrepl is absent."""
111+
return plain_pager
112+
113+
# --------------------------------------------------------- old names
114+
getpager = get_pager
115+
plainpager = plain_pager
95116

96117

97118
# --------------------------------------------------------- common routines

Lib/site.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ def register_readline():
529529
import _pyrepl.unix_console
530530
console_errors = _pyrepl.unix_console._error
531531
from _pyrepl.main import CAN_USE_PYREPL
532+
except ModuleNotFoundError:
533+
CAN_USE_PYREPL = False
532534
finally:
533535
sys.path = original_path
534536
except ImportError:

Lib/test/support/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3023,6 +3023,13 @@ def force_color(color: bool):
30233023
import _colorize
30243024
from .os_helper import EnvironmentVarGuard
30253025

3026+
if color:
3027+
try:
3028+
import _pyrepl # noqa: F401
3029+
except ModuleNotFoundError:
3030+
# Can't force enable color without _pyrepl, so just skip.
3031+
raise unittest.SkipTest("_pyrepl is missing")
3032+
30263033
with (
30273034
swap_attr(_colorize, "can_colorize", lambda *, file=None: color),
30283035
EnvironmentVarGuard() as env,

Lib/test/test_defaultdict.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,20 @@ def default_factory():
204204
self.assertEqual(test_dict[key], 2)
205205
self.assertEqual(count, 2)
206206

207+
def test_repr_recursive_factory(self):
208+
# gh-145492: defaultdict.__repr__ should not cause infinite recursion
209+
# when the factory's __repr__ calls repr() on the defaultdict.
210+
class ProblematicFactory:
211+
def __call__(self):
212+
return {}
213+
def __repr__(self):
214+
repr(dd)
215+
return "ProblematicFactory()"
216+
217+
dd = defaultdict(ProblematicFactory())
218+
# Should not raise RecursionError
219+
r = repr(dd)
220+
self.assertIn('ProblematicFactory()', r)
221+
207222
if __name__ == "__main__":
208223
unittest.main()

Lib/test/test_pyclbr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ def test_others(self):
252252
ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'curframe_locals',
253253
'_InteractState', 'rlcompleter'),
254254
)
255-
cm('pydoc', ignore=('input', 'output',)) # properties
255+
cm('pydoc', ignore=('input', 'output', # properties
256+
'getpager', 'plainpager', )) # aliases
256257

257258
# Tests for modules inside packages
258259
cm('email.parser')

Lib/test/test_pyrepl/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
from test.support import import_helper, load_package_tests
44

55

6+
import_helper.import_module("_pyrepl")
7+
8+
69
if sys.platform != "win32":
710
import_helper.import_module("termios")
811

0 commit comments

Comments
 (0)