Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c06c3db

Browse files
authored
Merge branch 'main' into warnings-as-error-2
2 parents 9e532fa + d3adf02 commit c06c3db

File tree

8 files changed

+296
-21
lines changed

8 files changed

+296
-21
lines changed

Doc/library/turtle.rst

+85
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,31 @@ useful when working with learners for whom typing is not a skill.
213213
use turtle graphics with a learner.
214214

215215

216+
Automatically begin and end filling
217+
-----------------------------------
218+
219+
Starting with Python 3.14, you can use the :func:`fill` :term:`context manager`
220+
instead of :func:`begin_fill` and :func:`end_fill` to automatically begin and
221+
end fill. Here is an example::
222+
223+
with fill():
224+
for i in range(4):
225+
forward(100)
226+
right(90)
227+
228+
forward(200)
229+
230+
The code above is equivalent to::
231+
232+
begin_fill()
233+
for i in range(4):
234+
forward(100)
235+
right(90)
236+
end_fill()
237+
238+
forward(200)
239+
240+
216241
Use the ``turtle`` module namespace
217242
-----------------------------------
218243

@@ -351,6 +376,7 @@ Pen control
351376
352377
Filling
353378
| :func:`filling`
379+
| :func:`fill`
354380
| :func:`begin_fill`
355381
| :func:`end_fill`
356382
@@ -381,6 +407,7 @@ Using events
381407
| :func:`ondrag`
382408
383409
Special Turtle methods
410+
| :func:`poly`
384411
| :func:`begin_poly`
385412
| :func:`end_poly`
386413
| :func:`get_poly`
@@ -403,6 +430,7 @@ Window control
403430
| :func:`setworldcoordinates`
404431
405432
Animation control
433+
| :func:`no_animation`
406434
| :func:`delay`
407435
| :func:`tracer`
408436
| :func:`update`
@@ -1275,6 +1303,29 @@ Filling
12751303
... else:
12761304
... turtle.pensize(3)
12771305

1306+
.. function:: fill()
1307+
1308+
Fill the shape drawn in the ``with turtle.fill():`` block.
1309+
1310+
.. doctest::
1311+
:skipif: _tkinter is None
1312+
1313+
>>> turtle.color("black", "red")
1314+
>>> with turtle.fill():
1315+
... turtle.circle(80)
1316+
1317+
Using :func:`!fill` is equivalent to adding the :func:`begin_fill` before the
1318+
fill-block and :func:`end_fill` after the fill-block:
1319+
1320+
.. doctest::
1321+
:skipif: _tkinter is None
1322+
1323+
>>> turtle.color("black", "red")
1324+
>>> turtle.begin_fill()
1325+
>>> turtle.circle(80)
1326+
>>> turtle.end_fill()
1327+
1328+
.. versionadded:: next
12781329

12791330

12801331
.. function:: begin_fill()
@@ -1648,6 +1699,23 @@ Using events
16481699
Special Turtle methods
16491700
----------------------
16501701

1702+
1703+
.. function:: poly()
1704+
1705+
Record the vertices of a polygon drawn in the ``with turtle.poly():`` block.
1706+
The first and last vertices will be connected.
1707+
1708+
.. doctest::
1709+
:skipif: _tkinter is None
1710+
1711+
>>> with turtle.poly():
1712+
... turtle.forward(100)
1713+
... turtle.right(60)
1714+
... turtle.forward(100)
1715+
1716+
.. versionadded:: next
1717+
1718+
16511719
.. function:: begin_poly()
16521720

16531721
Start recording the vertices of a polygon. Current turtle position is first
@@ -1926,6 +1994,23 @@ Window control
19261994
Animation control
19271995
-----------------
19281996

1997+
.. function:: no_animation()
1998+
1999+
Temporarily disable turtle animation. The code written inside the
2000+
``no_animation`` block will not be animated;
2001+
once the code block is exited, the drawing will appear.
2002+
2003+
.. doctest::
2004+
:skipif: _tkinter is None
2005+
2006+
>>> with screen.no_animation():
2007+
... for dist in range(2, 400, 2):
2008+
... fd(dist)
2009+
... rt(90)
2010+
2011+
.. versionadded:: next
2012+
2013+
19292014
.. function:: delay(delay=None)
19302015

19312016
:param delay: positive integer

Doc/whatsnew/3.14.rst

+8
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,14 @@ tkinter
660660
(Contributed by Zhikang Yan in :gh:`126899`.)
661661

662662

663+
turtle
664+
------
665+
666+
* Add context managers for :func:`turtle.fill`, :func:`turtle.poly`
667+
and :func:`turtle.no_animation`.
668+
(Contributed by Marie Roald and Yngve Mardal Moe in :gh:`126350`.)
669+
670+
663671
unicodedata
664672
-----------
665673

Lib/test/test_array.py

+8
Original file line numberDiff line numberDiff line change
@@ -1665,5 +1665,13 @@ def test_tolist(self, size):
16651665
self.assertEqual(ls[:8], list(example[:8]))
16661666
self.assertEqual(ls[-8:], list(example[-8:]))
16671667

1668+
def test_gh_128961(self):
1669+
a = array.array('i')
1670+
it = iter(a)
1671+
list(it)
1672+
it.__setstate__(0)
1673+
self.assertRaises(StopIteration, next, it)
1674+
1675+
16681676
if __name__ == "__main__":
16691677
unittest.main()

Lib/test/test_turtle.py

+109-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import os
22
import pickle
33
import re
4+
import tempfile
45
import unittest
56
import unittest.mock
6-
import tempfile
77
from test import support
88
from test.support import import_helper
99
from test.support import os_helper
@@ -54,6 +54,21 @@
5454
"""
5555

5656

57+
def patch_screen():
58+
"""Patch turtle._Screen for testing without a display.
59+
60+
We must patch the _Screen class itself instead of the _Screen
61+
instance because instantiating it requires a display.
62+
"""
63+
return unittest.mock.patch(
64+
"turtle._Screen.__new__",
65+
**{
66+
"return_value.__class__": turtle._Screen,
67+
"return_value.mode.return_value": "standard",
68+
},
69+
)
70+
71+
5772
class TurtleConfigTest(unittest.TestCase):
5873

5974
def get_cfg_file(self, cfg_str):
@@ -513,7 +528,7 @@ def test_save_overwrites_if_specified(self) -> None:
513528

514529
turtle.TurtleScreen.save(screen, file_path, overwrite=True)
515530
with open(file_path) as f:
516-
assert f.read() == "postscript"
531+
self.assertEqual(f.read(), "postscript")
517532

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

525540
turtle.TurtleScreen.save(screen, file_path)
526541
with open(file_path) as f:
527-
assert f.read() == "postscript"
542+
self.assertEqual(f.read(), "postscript")
543+
544+
def test_no_animation_sets_tracer_0(self):
545+
s = turtle.TurtleScreen(cv=unittest.mock.MagicMock())
546+
547+
with s.no_animation():
548+
self.assertEqual(s.tracer(), 0)
549+
550+
def test_no_animation_resets_tracer_to_old_value(self):
551+
s = turtle.TurtleScreen(cv=unittest.mock.MagicMock())
552+
553+
for tracer in [0, 1, 5]:
554+
s.tracer(tracer)
555+
with s.no_animation():
556+
pass
557+
self.assertEqual(s.tracer(), tracer)
558+
559+
def test_no_animation_calls_update_at_exit(self):
560+
s = turtle.TurtleScreen(cv=unittest.mock.MagicMock())
561+
s.update = unittest.mock.MagicMock()
562+
563+
with s.no_animation():
564+
s.update.assert_not_called()
565+
s.update.assert_called_once()
566+
567+
568+
class TestTurtle(unittest.TestCase):
569+
def setUp(self):
570+
with patch_screen():
571+
self.turtle = turtle.Turtle()
572+
573+
def test_begin_end_fill(self):
574+
self.assertFalse(self.turtle.filling())
575+
self.turtle.begin_fill()
576+
self.assertTrue(self.turtle.filling())
577+
self.turtle.end_fill()
578+
self.assertFalse(self.turtle.filling())
579+
580+
def test_fill(self):
581+
# The context manager behaves like begin_fill and end_fill.
582+
self.assertFalse(self.turtle.filling())
583+
with self.turtle.fill():
584+
self.assertTrue(self.turtle.filling())
585+
self.assertFalse(self.turtle.filling())
586+
587+
def test_fill_resets_after_exception(self):
588+
# The context manager cleans up correctly after exceptions.
589+
try:
590+
with self.turtle.fill():
591+
self.assertTrue(self.turtle.filling())
592+
raise ValueError
593+
except ValueError:
594+
self.assertFalse(self.turtle.filling())
595+
596+
def test_fill_context_when_filling(self):
597+
# The context manager works even when the turtle is already filling.
598+
self.turtle.begin_fill()
599+
self.assertTrue(self.turtle.filling())
600+
with self.turtle.fill():
601+
self.assertTrue(self.turtle.filling())
602+
self.assertFalse(self.turtle.filling())
603+
604+
def test_begin_end_poly(self):
605+
self.assertFalse(self.turtle._creatingPoly)
606+
self.turtle.begin_poly()
607+
self.assertTrue(self.turtle._creatingPoly)
608+
self.turtle.end_poly()
609+
self.assertFalse(self.turtle._creatingPoly)
610+
611+
def test_poly(self):
612+
# The context manager behaves like begin_poly and end_poly.
613+
self.assertFalse(self.turtle._creatingPoly)
614+
with self.turtle.poly():
615+
self.assertTrue(self.turtle._creatingPoly)
616+
self.assertFalse(self.turtle._creatingPoly)
617+
618+
def test_poly_resets_after_exception(self):
619+
# The context manager cleans up correctly after exceptions.
620+
try:
621+
with self.turtle.poly():
622+
self.assertTrue(self.turtle._creatingPoly)
623+
raise ValueError
624+
except ValueError:
625+
self.assertFalse(self.turtle._creatingPoly)
626+
627+
def test_poly_context_when_creating_poly(self):
628+
# The context manager works when the turtle is already creating poly.
629+
self.turtle.begin_poly()
630+
self.assertTrue(self.turtle._creatingPoly)
631+
with self.turtle.poly():
632+
self.assertTrue(self.turtle._creatingPoly)
633+
self.assertFalse(self.turtle._creatingPoly)
528634

529635

530636
class TestModuleLevel(unittest.TestCase):

0 commit comments

Comments
 (0)