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: 3 additions & 1 deletion Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5411,6 +5411,8 @@ information, consult your Unix manpages.
The following scheduling policies are exposed if they are supported by the
operating system.

.. _os-scheduling-policy:

.. data:: SCHED_OTHER

The default scheduling policy.
Expand Down Expand Up @@ -5514,7 +5516,7 @@ operating system.

.. function:: sched_yield()

Voluntarily relinquish the CPU.
Voluntarily relinquish the CPU. See :manpage:`sched_yield(2)` for details.


.. function:: sched_setaffinity(pid, mask, /)
Expand Down
11 changes: 10 additions & 1 deletion Doc/library/time.rst
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ Functions
The suspension time may be longer than requested by an arbitrary amount,
because of the scheduling of other activity in the system.

.. rubric:: Windows implementation

On Windows, if *secs* is zero, the thread relinquishes the remainder of its
time slice to any other thread that is ready to run. If there are no other
threads ready to run, the function returns immediately, and the thread
Expand All @@ -393,12 +395,19 @@ Functions
<https://learn.microsoft.com/windows-hardware/drivers/kernel/high-resolution-timers>`_
which provides resolution of 100 nanoseconds. If *secs* is zero, ``Sleep(0)`` is used.

Unix implementation:
.. rubric:: Unix implementation

* Use ``clock_nanosleep()`` if available (resolution: 1 nanosecond);
* Or use ``nanosleep()`` if available (resolution: 1 nanosecond);
* Or use ``select()`` (resolution: 1 microsecond).

.. note::

To emulate a "no-op", use :keyword:`pass` instead of ``time.sleep(0)``.

To voluntarily relinquish the CPU, specify a real-time :ref:`scheduling
policy <os-scheduling-policy>` and use :func:`os.sched_yield` instead.

.. audit-event:: time.sleep secs

.. versionchanged:: 3.5
Expand Down
85 changes: 85 additions & 0 deletions Doc/library/turtle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,31 @@ useful when working with learners for whom typing is not a skill.
use turtle graphics with a learner.


Automatically begin and end filling
-----------------------------------

Starting with Python 3.14, you can use the :func:`fill` :term:`context manager`
instead of :func:`begin_fill` and :func:`end_fill` to automatically begin and
end fill. Here is an example::

with fill():
for i in range(4):
forward(100)
right(90)

forward(200)

The code above is equivalent to::

begin_fill()
for i in range(4):
forward(100)
right(90)
end_fill()

forward(200)


Use the ``turtle`` module namespace
-----------------------------------

Expand Down Expand Up @@ -351,6 +376,7 @@ Pen control

Filling
| :func:`filling`
| :func:`fill`
| :func:`begin_fill`
| :func:`end_fill`

Expand Down Expand Up @@ -381,6 +407,7 @@ Using events
| :func:`ondrag`

Special Turtle methods
| :func:`poly`
| :func:`begin_poly`
| :func:`end_poly`
| :func:`get_poly`
Expand All @@ -403,6 +430,7 @@ Window control
| :func:`setworldcoordinates`

Animation control
| :func:`no_animation`
| :func:`delay`
| :func:`tracer`
| :func:`update`
Expand Down Expand Up @@ -1275,6 +1303,29 @@ Filling
... else:
... turtle.pensize(3)

.. function:: fill()

Fill the shape drawn in the ``with turtle.fill():`` block.

.. doctest::
:skipif: _tkinter is None

>>> turtle.color("black", "red")
>>> with turtle.fill():
... turtle.circle(80)

Using :func:`!fill` is equivalent to adding the :func:`begin_fill` before the
fill-block and :func:`end_fill` after the fill-block:

.. doctest::
:skipif: _tkinter is None

>>> turtle.color("black", "red")
>>> turtle.begin_fill()
>>> turtle.circle(80)
>>> turtle.end_fill()

.. versionadded:: next


.. function:: begin_fill()
Expand Down Expand Up @@ -1648,6 +1699,23 @@ Using events
Special Turtle methods
----------------------


.. function:: poly()

Record the vertices of a polygon drawn in the ``with turtle.poly():`` block.
The first and last vertices will be connected.

.. doctest::
:skipif: _tkinter is None

>>> with turtle.poly():
... turtle.forward(100)
... turtle.right(60)
... turtle.forward(100)

.. versionadded:: next


.. function:: begin_poly()

Start recording the vertices of a polygon. Current turtle position is first
Expand Down Expand Up @@ -1926,6 +1994,23 @@ Window control
Animation control
-----------------

.. function:: no_animation()

Temporarily disable turtle animation. The code written inside the
``no_animation`` block will not be animated;
once the code block is exited, the drawing will appear.

.. doctest::
:skipif: _tkinter is None

>>> with screen.no_animation():
... for dist in range(2, 400, 2):
... fd(dist)
... rt(90)

.. versionadded:: next


.. function:: delay(delay=None)

:param delay: positive integer
Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,14 @@ tkinter
(Contributed by Zhikang Yan in :gh:`126899`.)


turtle
------

* Add context managers for :func:`turtle.fill`, :func:`turtle.poly`
and :func:`turtle.no_animation`.
(Contributed by Marie Roald and Yngve Mardal Moe in :gh:`126350`.)


unicodedata
-----------

Expand Down
2 changes: 1 addition & 1 deletion Lib/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ class excel:
written as two quotes
"""

import re
import types
from _csv import Error, writer, reader, register_dialect, \
unregister_dialect, get_dialect, list_dialects, \
Expand Down Expand Up @@ -281,6 +280,7 @@ def _guess_quote_and_delimiter(self, data, delimiters):
If there is no quotechar the delimiter can't be determined
this way.
"""
import re

matches = []
for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?",
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1665,5 +1665,13 @@ def test_tolist(self, size):
self.assertEqual(ls[:8], list(example[:8]))
self.assertEqual(ls[-8:], list(example[-8:]))

def test_gh_128961(self):
a = array.array('i')
it = iter(a)
list(it)
it.__setstate__(0)
self.assertRaises(StopIteration, next, it)


if __name__ == "__main__":
unittest.main()
2 changes: 2 additions & 0 deletions Lib/test/test_tracemalloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,8 @@ def test_stop_untrack(self):

@unittest.skipIf(_testcapi is None, 'need _testcapi')
@threading_helper.requires_working_threading()
# gh-128679: Test crash on a debug build (especially on FreeBSD).
@unittest.skipIf(support.Py_DEBUG, 'need release build')
def test_tracemalloc_track_race(self):
# gh-128679: Test fix for tracemalloc.stop() race condition
_testcapi.tracemalloc_track_race()
Expand Down
112 changes: 109 additions & 3 deletions Lib/test/test_turtle.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import os
import pickle
import re
import tempfile
import unittest
import unittest.mock
import tempfile
from test import support
from test.support import import_helper
from test.support import os_helper
Expand Down Expand Up @@ -54,6 +54,21 @@
"""


def patch_screen():
"""Patch turtle._Screen for testing without a display.

We must patch the _Screen class itself instead of the _Screen
instance because instantiating it requires a display.
"""
return unittest.mock.patch(
"turtle._Screen.__new__",
**{
"return_value.__class__": turtle._Screen,
"return_value.mode.return_value": "standard",
},
)


class TurtleConfigTest(unittest.TestCase):

def get_cfg_file(self, cfg_str):
Expand Down Expand Up @@ -513,7 +528,7 @@ def test_save_overwrites_if_specified(self) -> None:

turtle.TurtleScreen.save(screen, file_path, overwrite=True)
with open(file_path) as f:
assert f.read() == "postscript"
self.assertEqual(f.read(), "postscript")

def test_save(self) -> None:
screen = unittest.mock.Mock()
Expand All @@ -524,7 +539,98 @@ def test_save(self) -> None:

turtle.TurtleScreen.save(screen, file_path)
with open(file_path) as f:
assert f.read() == "postscript"
self.assertEqual(f.read(), "postscript")

def test_no_animation_sets_tracer_0(self):
s = turtle.TurtleScreen(cv=unittest.mock.MagicMock())

with s.no_animation():
self.assertEqual(s.tracer(), 0)

def test_no_animation_resets_tracer_to_old_value(self):
s = turtle.TurtleScreen(cv=unittest.mock.MagicMock())

for tracer in [0, 1, 5]:
s.tracer(tracer)
with s.no_animation():
pass
self.assertEqual(s.tracer(), tracer)

def test_no_animation_calls_update_at_exit(self):
s = turtle.TurtleScreen(cv=unittest.mock.MagicMock())
s.update = unittest.mock.MagicMock()

with s.no_animation():
s.update.assert_not_called()
s.update.assert_called_once()


class TestTurtle(unittest.TestCase):
def setUp(self):
with patch_screen():
self.turtle = turtle.Turtle()

def test_begin_end_fill(self):
self.assertFalse(self.turtle.filling())
self.turtle.begin_fill()
self.assertTrue(self.turtle.filling())
self.turtle.end_fill()
self.assertFalse(self.turtle.filling())

def test_fill(self):
# The context manager behaves like begin_fill and end_fill.
self.assertFalse(self.turtle.filling())
with self.turtle.fill():
self.assertTrue(self.turtle.filling())
self.assertFalse(self.turtle.filling())

def test_fill_resets_after_exception(self):
# The context manager cleans up correctly after exceptions.
try:
with self.turtle.fill():
self.assertTrue(self.turtle.filling())
raise ValueError
except ValueError:
self.assertFalse(self.turtle.filling())

def test_fill_context_when_filling(self):
# The context manager works even when the turtle is already filling.
self.turtle.begin_fill()
self.assertTrue(self.turtle.filling())
with self.turtle.fill():
self.assertTrue(self.turtle.filling())
self.assertFalse(self.turtle.filling())

def test_begin_end_poly(self):
self.assertFalse(self.turtle._creatingPoly)
self.turtle.begin_poly()
self.assertTrue(self.turtle._creatingPoly)
self.turtle.end_poly()
self.assertFalse(self.turtle._creatingPoly)

def test_poly(self):
# The context manager behaves like begin_poly and end_poly.
self.assertFalse(self.turtle._creatingPoly)
with self.turtle.poly():
self.assertTrue(self.turtle._creatingPoly)
self.assertFalse(self.turtle._creatingPoly)

def test_poly_resets_after_exception(self):
# The context manager cleans up correctly after exceptions.
try:
with self.turtle.poly():
self.assertTrue(self.turtle._creatingPoly)
raise ValueError
except ValueError:
self.assertFalse(self.turtle._creatingPoly)

def test_poly_context_when_creating_poly(self):
# The context manager works when the turtle is already creating poly.
self.turtle.begin_poly()
self.assertTrue(self.turtle._creatingPoly)
with self.turtle.poly():
self.assertTrue(self.turtle._creatingPoly)
self.assertFalse(self.turtle._creatingPoly)


class TestModuleLevel(unittest.TestCase):
Expand Down
Loading
Loading