Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
darwin = sys.platform == 'darwin'

class EditorWindow:
is_shell = False # PyShell overrides.
from idlelib.percolator import Percolator
from idlelib.colorizer import ColorDelegator, color_config
from idlelib.undo import UndoDelegator
Expand Down Expand Up @@ -80,7 +81,6 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
self.recent_files_path = idleConf.userdir and os.path.join(
idleConf.userdir, 'recent-files.lst')

self.prompt_last_line = '' # Override in PyShell
self.text_frame = text_frame = Frame(top)
self.vbar = vbar = Scrollbar(text_frame, name='vbar')
width = idleConf.GetOption('main', 'EditorWindow', 'width', type='int')
Expand Down Expand Up @@ -1434,7 +1434,7 @@ def newline_and_indent_event(self, event):
# First need to find the last statement.
lno = index2line(text.index('insert'))
y = pyparse.Parser(self.indentwidth, self.tabwidth)
if not self.prompt_last_line:
if not self.is_shell:
for context in self.num_context_lines:
startat = max(lno - context, 1)
startatindex = repr(startat) + ".0"
Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/hyperparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def index2line(index):
return int(float(index))
lno = index2line(text.index(index))

if not editwin.prompt_last_line:
if not editwin.is_shell:
for context in editwin.num_context_lines:
startat = max(lno - context, 1)
startatindex = repr(startat) + ".0"
Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/idle_test/test_autocomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(self, root, text):
self.text = text
self.indentwidth = 8
self.tabwidth = 8
self.prompt_last_line = '>>>' # Currently not used by autocomplete.
self.is_shell = True


class AutoCompleteTest(unittest.TestCase):
Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/idle_test/test_calltip.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ class mock_Shell:
def __init__(self, text):
text.tag_prevrange = Mock(return_value=None)
self.text = text
self.prompt_last_line = ">>> "
self.is_shell = True
self.indentwidth = 4
self.tabwidth = 8

Expand Down
8 changes: 4 additions & 4 deletions Lib/idlelib/idle_test/test_hyperparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __init__(self, text):
self.text = text
self.indentwidth = 8
self.tabwidth = 8
self.prompt_last_line = '>>>'
self.is_shell = True
self.num_context_lines = 50, 500, 1000

_build_char_in_string_func = EditorWindow._build_char_in_string_func
Expand Down Expand Up @@ -53,7 +53,7 @@ def setUp(self):

def tearDown(self):
self.text.delete('1.0', 'end')
self.editwin.prompt_last_line = '>>>'
self.editwin.is_shell = True

def get_parser(self, index):
"""
Expand All @@ -70,8 +70,8 @@ def test_init(self):
p = self.get_parser('1.5')
self.assertIn('precedes', str(ve.exception))

# test without ps1
self.editwin.prompt_last_line = ''
# test an editor
self.editwin.is_shell = False

# number of lines lesser than 50
p = self.get_parser('end')
Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/idle_test/test_parenmatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self, text):
self.text = text
self.indentwidth = 8
self.tabwidth = 8
self.prompt_last_line = '>>>' # Currently not used by parenmatch.
self.is_shell = True


class ParenMatchTest(unittest.TestCase):
Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/pyshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,7 @@ def display_executing_dialog(self):


class PyShell(OutputWindow):
is_shell = True
from idlelib.squeezer import Squeezer

shell_title = "IDLE Shell"
Expand Down Expand Up @@ -909,7 +910,6 @@ def __init__(self, flist=None):
self.indentwidth = 4

self.sys_ps1 = sys.ps1 if hasattr(sys, 'ps1') else '>>>\n'
self.prompt_last_line = self.sys_ps1.split('\n')[-1]
self.prompt = self.sys_ps1 # Changes when debug active

text = self.text
Expand Down
8 changes: 2 additions & 6 deletions Lib/test/libregrtest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,7 @@ def finalize_tests(self, coverage: trace.CoverageResults | None) -> None:
os.unlink(self.next_single_filename)

if coverage is not None:
# uses a new-in-Python 3.13 keyword argument that mypy doesn't know about yet:
coverage.write_results(show_missing=True, summary=True, # type: ignore[call-arg]
coverage.write_results(show_missing=True, summary=True,
coverdir=self.coverage_dir,
ignore_missing_files=True)

Expand Down Expand Up @@ -539,10 +538,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
if self.num_workers < 0:
# Use all CPUs + 2 extra worker processes for tests
# that like to sleep
#
# os.process.cpu_count() is new in Python 3.13;
# mypy doesn't know about it yet
self.num_workers = (os.process_cpu_count() or 1) + 2 # type: ignore[attr-defined]
self.num_workers = (os.process_cpu_count() or 1) + 2

# For a partial run, we do not need to clutter the output.
if (self.want_header
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/libregrtest/mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[mypy]
files = Lib/test/libregrtest
explicit_package_bases = True
python_version = 3.12
python_version = 3.15
platform = linux
pretty = True

Expand Down
9 changes: 3 additions & 6 deletions Lib/test/libregrtest/refleak.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,8 @@ def runtest_refleak(test_name, test_func,

# `ByteString` is not included in `collections.abc.__all__`
with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
ByteString = collections.abc.ByteString
# Mypy doesn't even think `ByteString` is a class, hence the `type: ignore`
for obj in ByteString.__subclasses__() + [ByteString]: # type: ignore[attr-defined]
ByteString = collections.abc.ByteString # type: ignore[attr-defined]
for obj in ByteString.__subclasses__() + [ByteString]:
abcs[obj] = _get_dump(obj)[0]

warmups = hunt_refleak.warmups
Expand Down Expand Up @@ -151,9 +150,7 @@ def runtest_refleak(test_name, test_func,
# Also, readjust the reference counts and alloc blocks by ignoring
# any strings that might have been interned during test_func. These
# strings will be deallocated at runtime shutdown
interned_immortal_after = getunicodeinternedsize(
# Use an internal-only keyword argument that mypy doesn't know yet
_only_immortal=True) # type: ignore[call-arg]
interned_immortal_after = getunicodeinternedsize(_only_immortal=True)
alloc_after = getallocatedblocks() - interned_immortal_after
rc_after = gettotalrefcount()
fd_after = fd_count()
Expand Down
7 changes: 2 additions & 5 deletions Lib/test/libregrtest/results.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import sys
import trace
from _colorize import get_colors # type: ignore[import-not-found]
from typing import TYPE_CHECKING
lazy from xml.etree.ElementTree import Element

from .runtests import RunTests
from .result import State, TestResult, TestStats, Location
from .utils import (
StrPath, TestName, TestTuple, TestList, FilterDict,
printlist, count, format_duration)

if TYPE_CHECKING:
from xml.etree.ElementTree import Element


# Python uses exit code 1 when an exception is not caught
# argparse.ArgumentParser.error() uses exit code 2
Expand Down Expand Up @@ -41,7 +38,7 @@ def __init__(self) -> None:
self.test_times: list[tuple[float, TestName]] = []
self.stats = TestStats()
# used by --junit-xml
self.testsuite_xml: list['Element'] = []
self.testsuite_xml: list[Element] = []
# used by -T with -j
self.covered_lines: set[Location] = set()

Expand Down
3 changes: 1 addition & 2 deletions Lib/test/libregrtest/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,8 +652,7 @@ def display_header(use_resources: dict[str, str | None],

cpu_count: object = os.cpu_count()
if cpu_count:
# The function is new in Python 3.13; mypy doesn't know about it yet:
process_cpu_count = os.process_cpu_count() # type: ignore[attr-defined]
process_cpu_count = os.process_cpu_count()
if process_cpu_count and process_cpu_count != cpu_count:
cpu_count = f"{process_cpu_count} (process) / {cpu_count} (system)"
print("== CPU count:", cpu_count)
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10299,6 +10299,17 @@ def test_args_kwargs(self):
self.assertEqual(repr(P.args), "P.args")
self.assertEqual(repr(P.kwargs), "P.kwargs")

def test_args_kwargs_weakrefs(self):
P = ParamSpec('P')
for attr_name in ('args', 'kwargs'):
with self.subTest(attr_name=attr_name):
callback_fired = []
attr = getattr(P, attr_name)
ref = weakref.ref(attr, lambda _: callback_fired.append(True))
del attr
self.assertEqual(callback_fired, [True])
self.assertIsNone(ref())

def test_stringized(self):
P = ParamSpec('P')
class C(Generic[P]):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix calltips, parenthesis matching and auto-indent in the IDLE Shell after
output containing unbalanced quotes or parentheses.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix a crash when a weak-reference callback is attached to a
:class:`typing.ParamSpecArgs` or :class:`typing.ParamSpecKwargs` instance.
1 change: 1 addition & 0 deletions Objects/typevarobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,7 @@ paramspecattr_dealloc(PyObject *self)
_PyObject_GC_UNTRACK(self);

Py_XDECREF(psa->__origin__);
PyObject_ClearWeakRefs(self);

Py_TYPE(self)->tp_free(self);
Py_DECREF(tp);
Expand Down
Loading