Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into typealiasmod
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra committed May 18, 2023
2 parents f98dfcc + 678bf57 commit de0e39e
Show file tree
Hide file tree
Showing 35 changed files with 2,142 additions and 1,658 deletions.
46 changes: 44 additions & 2 deletions Doc/library/urllib.parse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ or on combining URL components into a URL string.
ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
params='', query='', fragment='')

.. warning::

:func:`urlparse` does not perform validation. See :ref:`URL parsing
security <url-parsing-security>` for details.

.. versionchanged:: 3.2
Added IPv6 URL parsing capabilities.
Expand Down Expand Up @@ -324,8 +328,14 @@ or on combining URL components into a URL string.
``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is
decomposed before parsing, no error will be raised.

Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline
``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL.
Following some of the `WHATWG spec`_ that updates RFC 3986, leading C0
control and space characters are stripped from the URL. ``\n``,
``\r`` and tab ``\t`` characters are removed from the URL at any position.

.. warning::

:func:`urlsplit` does not perform validation. See :ref:`URL parsing
security <url-parsing-security>` for details.

.. versionchanged:: 3.6
Out-of-range port numbers now raise :exc:`ValueError`, instead of
Expand All @@ -338,6 +348,9 @@ or on combining URL components into a URL string.
.. versionchanged:: 3.10
ASCII newline and tab characters are stripped from the URL.

.. versionchanged:: 3.12
Leading WHATWG C0 control and space characters are stripped from the URL.

.. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser

.. function:: urlunsplit(parts)
Expand Down Expand Up @@ -414,6 +427,35 @@ or on combining URL components into a URL string.
or ``scheme://host/path``). If *url* is not a wrapped URL, it is returned
without changes.

.. _url-parsing-security:

URL parsing security
--------------------

The :func:`urlsplit` and :func:`urlparse` APIs do not perform **validation** of
inputs. They may not raise errors on inputs that other applications consider
invalid. They may also succeed on some inputs that might not be considered
URLs elsewhere. Their purpose is for practical functionality rather than
purity.

Instead of raising an exception on unusual input, they may instead return some
component parts as empty strings. Or components may contain more than perhaps
they should.

We recommend that users of these APIs where the values may be used anywhere
with security implications code defensively. Do some verification within your
code before trusting a returned component part. Does that ``scheme`` make
sense? Is that a sensible ``path``? Is there anything strange about that
``hostname``? etc.

What constitutes a URL is not universally well defined. Different applications
have different needs and desired constraints. For instance the living `WHATWG
spec`_ describes what user facing web clients such as a web browser require.
While :rfc:`3986` is more general. These functions incorporate some aspects of
both, but cannot be claimed compliant with either. The APIs and existing user
code with expectations on specific behaviors predate both standards leading us
to be very cautious about making API behavior changes.

.. _parsing-ascii-encoded-bytes:

Parsing ASCII Encoded Bytes
Expand Down
1 change: 0 additions & 1 deletion Include/internal/pycore_pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc);

extern void _Py_InitVersion(void);
extern PyStatus _PyFaulthandler_Init(int enable);
extern int _PyTraceMalloc_Init(int enable);
extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp);
extern PyStatus _PySys_Create(
PyThreadState *tstate,
Expand Down
34 changes: 34 additions & 0 deletions Include/tracemalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,40 @@ PyAPI_FUNC(int) PyTraceMalloc_Untrack(
PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback(
unsigned int domain,
uintptr_t ptr);

/* Return non-zero if tracemalloc is tracing */
PyAPI_FUNC(int) _PyTraceMalloc_IsTracing(void);

/* Clear the tracemalloc traces */
PyAPI_FUNC(void) _PyTraceMalloc_ClearTraces(void);

/* Clear the tracemalloc traces */
PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTraces(void);

/* Clear tracemalloc traceback for an object */
PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetObjectTraceback(PyObject *obj);

/* Initialize tracemalloc */
PyAPI_FUNC(int) _PyTraceMalloc_Init(void);

/* Start tracemalloc */
PyAPI_FUNC(int) _PyTraceMalloc_Start(int max_nframe);

/* Stop tracemalloc */
PyAPI_FUNC(void) _PyTraceMalloc_Stop(void);

/* Get the tracemalloc traceback limit */
PyAPI_FUNC(int) _PyTraceMalloc_GetTracebackLimit(void);

/* Get the memory usage of tracemalloc in bytes */
PyAPI_FUNC(size_t) _PyTraceMalloc_GetMemory(void);

/* Get the current size and peak size of traced memory blocks as a 2-tuple */
PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTracedMemory(void);

/* Set the peak size of traced memory blocks to the current size */
PyAPI_FUNC(void) _PyTraceMalloc_ResetPeak(void);

#endif

#endif /* !Py_TRACEMALLOC_H */
3 changes: 3 additions & 0 deletions Lib/asyncio/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ def pipe_connection_lost(self, fd, exc):
self._stdin_closed.set_result(None)
else:
self._stdin_closed.set_exception(exc)
# Since calling `wait_closed()` is not mandatory,
# we shouldn't log the traceback if this is not awaited.
self._stdin_closed._log_traceback = False
return
if fd == 1:
reader = self.stdout
Expand Down
5 changes: 5 additions & 0 deletions Lib/idlelib/NEWS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Released on 2023-10-02
=========================


gh-104499: Fix completions for Tk Aqua 8.7 (currently blank).

gh-104486: Make About print both tcl and tk versions if different,
as is expected someday.

gh-88496 Fix IDLE test hang on macOS.

gh-103314 Support sys.last_exc after exceptions in Shell.
Expand Down
10 changes: 3 additions & 7 deletions Lib/idlelib/autocomplete_w.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,11 @@ def show_window(self, comp_lists, index, complete, mode, userWantsWin):
self.userwantswindow = userWantsWin
self.lasttypedstart = self.start

# Put widgets in place
self.autocompletewindow = acw = Toplevel(self.widget)
# Put it in a position so that it is not seen.
acw.wm_geometry("+10000+10000")
# Make it float
acw.withdraw()
acw.wm_overrideredirect(1)
try:
# This command is only needed and available on Tk >= 8.4.0 for OSX
# Without it, call tips intrude on the typing process by grabbing
# the focus.
# Prevent grabbing focus on maxOS.
acw.tk.call("::tk::unsupported::MacWindowStyle", "style", acw._w,
"help", "noActivates")
except TclError:
Expand Down Expand Up @@ -271,6 +266,7 @@ def winconfig_event(self, event):
# place acw above current line
new_y -= acw_height
acw.wm_geometry("+%d+%d" % (new_x, new_y))
acw.deiconify()
acw.update_idletasks()
except TclError:
pass
Expand Down
37 changes: 16 additions & 21 deletions Lib/idlelib/help_about.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@

from idlelib import textview

version = python_version()
pyver = python_version()


def build_bits():
"Return bits for platform."
if sys.platform == 'darwin':
return '64' if sys.maxsize > 2**32 else '32'
else:
return architecture()[0][:2]
if sys.platform == 'darwin':
bits = '64' if sys.maxsize > 2**32 else '32'
else:
bits = architecture()[0][:2]


class AboutDialog(Toplevel):
Expand All @@ -45,7 +42,7 @@ def __init__(self, parent, title=None, *, _htest=False, _utest=False):
self.create_widgets()
self.resizable(height=False, width=False)
self.title(title or
f'About IDLE {version} ({build_bits()} bit)')
f'About IDLE {pyver} ({bits} bit)')
self.transient(parent)
self.grab_set()
self.protocol("WM_DELETE_WINDOW", self.ok)
Expand Down Expand Up @@ -76,8 +73,8 @@ def create_widgets(self):
bg=self.bg, font=('courier', 24, 'bold'))
header.grid(row=0, column=0, sticky=E, padx=10, pady=10)

tk_patchlevel = self.info_patchlevel()
ext = '.png' if tk_patchlevel >= (8, 6) else '.gif'
tkpatch = self._root().getvar('tk_patchLevel')
ext = '.png' if tkpatch >= '8.6' else '.gif'
icon = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'Icons', f'idle_48{ext}')
self.icon_image = PhotoImage(master=self._root(), file=icon)
Expand All @@ -102,13 +99,11 @@ def create_widgets(self):
height=2, bg=self.bg).grid(row=8, column=0, sticky=EW,
columnspan=3, padx=5, pady=5)

pyver = Label(frame_background,
text='Python version: ' + version,
fg=self.fg, bg=self.bg)
pyver.grid(row=9, column=0, sticky=W, padx=10, pady=0)
tkver = Label(frame_background, text=f'Tk version: {tk_patchlevel}',
fg=self.fg, bg=self.bg)
tkver.grid(row=9, column=1, sticky=W, padx=2, pady=0)
tclver = str(self.info_patchlevel())
tkver = ' and ' + tkpatch if tkpatch != tclver else ''
versions = f"Python {pyver} with tcl/tk {tclver}{tkver}"
vers = Label(frame_background, text=versions, fg=self.fg, bg=self.bg)
vers.grid(row=9, column=0, sticky=W, padx=10, pady=0)
py_buttons = Frame(frame_background, bg=self.bg)
py_buttons.grid(row=10, column=0, columnspan=2, sticky=NSEW)
self.py_license = Button(py_buttons, text='License', width=8,
Expand All @@ -128,10 +123,10 @@ def create_widgets(self):
height=2, bg=self.bg).grid(row=11, column=0, sticky=EW,
columnspan=3, padx=5, pady=5)

idlever = Label(frame_background,
text='IDLE version: ' + version,
idle = Label(frame_background,
text='IDLE',
fg=self.fg, bg=self.bg)
idlever.grid(row=12, column=0, sticky=W, padx=10, pady=0)
idle.grid(row=12, column=0, sticky=W, padx=10, pady=0)
idle_buttons = Frame(frame_background, bg=self.bg)
idle_buttons.grid(row=13, column=0, columnspan=3, sticky=NSEW)
self.readme = Button(idle_buttons, text='README', width=8,
Expand Down
4 changes: 2 additions & 2 deletions Lib/idlelib/idle_test/test_help_about.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def tearDownClass(cls):
del cls.root

def test_build_bits(self):
self.assertIn(help_about.build_bits(), ('32', '64'))
self.assertIn(help_about.bits, ('32', '64'))

def test_dialog_title(self):
"""Test about dialog title"""
Expand Down Expand Up @@ -107,7 +107,7 @@ def test_dialog_title(self):
"""Test about dialog title"""
self.assertEqual(self.dialog.title(),
f'About IDLE {python_version()}'
f' ({help_about.build_bits()} bit)')
f' ({help_about.bits} bit)')


class CloseTest(unittest.TestCase):
Expand Down
62 changes: 62 additions & 0 deletions Lib/test/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,68 @@ def f(x: *b)
^^^^^^^^^^^
SyntaxError: bytes can only contain ASCII literal characters
Invalid expressions in type scopes:
>>> type A[T: (x:=3)] = int
Traceback (most recent call last):
...
SyntaxError: named expression cannot be used within a TypeVar bound
>>> type A[T: (yield 3)] = int
Traceback (most recent call last):
...
SyntaxError: yield expression cannot be used within a TypeVar bound
>>> type A[T: (await 3)] = int
Traceback (most recent call last):
...
SyntaxError: await expression cannot be used within a TypeVar bound
>>> type A[T: (yield from [])] = int
Traceback (most recent call last):
...
SyntaxError: yield expression cannot be used within a TypeVar bound
>>> type A = (x := 3)
Traceback (most recent call last):
...
SyntaxError: named expression cannot be used within a type alias
>>> type A = (yield 3)
Traceback (most recent call last):
...
SyntaxError: yield expression cannot be used within a type alias
>>> type A = (await 3)
Traceback (most recent call last):
...
SyntaxError: await expression cannot be used within a type alias
>>> type A = (yield from [])
Traceback (most recent call last):
...
SyntaxError: yield expression cannot be used within a type alias
>>> class A[T]((x := 3)): ...
Traceback (most recent call last):
...
SyntaxError: named expression cannot be used within the definition of a generic
>>> class A[T]((yield 3)): ...
Traceback (most recent call last):
...
SyntaxError: yield expression cannot be used within the definition of a generic
>>> class A[T]((await 3)): ...
Traceback (most recent call last):
...
SyntaxError: await expression cannot be used within the definition of a generic
>>> class A[T]((yield from [])): ...
Traceback (most recent call last):
...
SyntaxError: yield expression cannot be used within the definition of a generic
"""

import re
Expand Down
14 changes: 7 additions & 7 deletions Lib/test/test_type_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,11 @@ class Foo[T: Foo, U: (Foo, Foo)]:
type_params = Foo.__type_params__
self.assertEqual(len(type_params), 2)
self.assertEqual(type_params[0].__name__, "T")
self.assertEqual(type_params[0].__bound__, Foo)
self.assertEqual(type_params[0].__constraints__, None)
self.assertIs(type_params[0].__bound__, Foo)
self.assertEqual(type_params[0].__constraints__, ())

self.assertEqual(type_params[1].__name__, "U")
self.assertEqual(type_params[1].__bound__, None)
self.assertIs(type_params[1].__bound__, None)
self.assertEqual(type_params[1].__constraints__, (Foo, Foo))

def test_evaluation_error(self):
Expand All @@ -439,16 +439,16 @@ class Foo[T: Undefined, U: (Undefined,)]:
type_params = Foo.__type_params__
with self.assertRaises(NameError):
type_params[0].__bound__
self.assertEqual(type_params[0].__constraints__, None)
self.assertEqual(type_params[1].__bound__, None)
self.assertEqual(type_params[0].__constraints__, ())
self.assertIs(type_params[1].__bound__, None)
with self.assertRaises(NameError):
type_params[1].__constraints__

Undefined = "defined"
self.assertEqual(type_params[0].__bound__, "defined")
self.assertEqual(type_params[0].__constraints__, None)
self.assertEqual(type_params[0].__constraints__, ())

self.assertEqual(type_params[1].__bound__, None)
self.assertIs(type_params[1].__bound__, None)
self.assertEqual(type_params[1].__constraints__, ("defined",))


Expand Down
Loading

0 comments on commit de0e39e

Please sign in to comment.