summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/turtle.rst53
-rw-r--r--Lib/test/test_turtle.py20
-rw-r--r--Lib/turtle.py66
-rw-r--r--Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst1
4 files changed, 128 insertions, 12 deletions
diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst
index 05392d0..10138f4 100644
--- a/Doc/library/turtle.rst
+++ b/Doc/library/turtle.rst
@@ -107,6 +107,7 @@ Turtle motion
| :func:`right` | :func:`rt`
| :func:`left` | :func:`lt`
| :func:`goto` | :func:`setpos` | :func:`setposition`
+ | :func:`teleport`
| :func:`setx`
| :func:`sety`
| :func:`setheading` | :func:`seth`
@@ -372,6 +373,44 @@ Turtle motion
(0.00,0.00)
+.. function:: teleport(x, y=None, *, fill_gap=False)
+
+ :param x: a number or ``None``
+ :param y: a number or ``None``
+ :param fill_gap: a boolean
+
+ Move turtle to an absolute position. Unlike goto(x, y), a line will not
+ be drawn. The turtle's orientation does not change. If currently
+ filling, the polygon(s) teleported from will be filled after leaving,
+ and filling will begin again after teleporting. This can be disabled
+ with fill_gap=True, which makes the imaginary line traveled during
+ teleporting act as a fill barrier like in goto(x, y).
+
+ .. doctest::
+ :skipif: _tkinter is None
+ :hide:
+
+ >>> turtle.goto(0, 0)
+
+ .. doctest::
+ :skipif: _tkinter is None
+
+ >>> tp = turtle.pos()
+ >>> tp
+ (0.00,0.00)
+ >>> turtle.teleport(60)
+ >>> turtle.pos()
+ (60.00,0.00)
+ >>> turtle.teleport(y=10)
+ >>> turtle.pos()
+ (60.00,10.00)
+ >>> turtle.teleport(20, 30)
+ >>> turtle.pos()
+ (20.00,30.00)
+
+ .. versionadded: 3.12
+
+
.. function:: setx(x)
:param x: a number (integer or float)
@@ -537,8 +576,7 @@ Turtle motion
:skipif: _tkinter is None
>>> turtle.color("blue")
- >>> turtle.stamp()
- 11
+ >>> stamp_id = turtle.stamp()
>>> turtle.fd(50)
@@ -575,15 +613,8 @@ Turtle motion
.. doctest::
>>> for i in range(8):
- ... turtle.stamp(); turtle.fd(30)
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
+ ... unused_stamp_id = turtle.stamp()
+ ... turtle.fd(30)
>>> turtle.clearstamps(2)
>>> turtle.clearstamps(-2)
>>> turtle.clearstamps()
diff --git a/Lib/test/test_turtle.py b/Lib/test/test_turtle.py
index 95af84e..3f9f129 100644
--- a/Lib/test/test_turtle.py
+++ b/Lib/test/test_turtle.py
@@ -267,6 +267,14 @@ class TestTNavigator(VectorComparisonMixin, unittest.TestCase):
self.assertAlmostEqual(self.nav.xcor(), 100)
self.assertAlmostEqual(self.nav.ycor(), -100)
+ def test_teleport(self):
+ self.nav.teleport(20, -30, fill_gap=True)
+ self.assertAlmostEqual(self.nav.xcor(), 20)
+ self.assertAlmostEqual(self.nav.ycor(), -30)
+ self.nav.teleport(-20, 30, fill_gap=False)
+ self.assertAlmostEqual(self.nav.xcor(), -20)
+ self.assertAlmostEqual(self.nav.ycor(), 30)
+
def test_pos(self):
self.assertEqual(self.nav.pos(), self.nav._position)
self.nav.goto(100, -100)
@@ -440,6 +448,18 @@ class TestTPen(unittest.TestCase):
tpen.showturtle()
self.assertTrue(tpen.isvisible())
+ def test_teleport(self):
+
+ tpen = turtle.TPen()
+
+ for fill_gap_value in [True, False]:
+ tpen.penup()
+ tpen.teleport(100, 100, fill_gap=fill_gap_value)
+ self.assertFalse(tpen.isdown())
+ tpen.pendown()
+ tpen.teleport(-100, -100, fill_gap=fill_gap_value)
+ self.assertTrue(tpen.isdown())
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/turtle.py b/Lib/turtle.py
index 1b36932..2de406e 100644
--- a/Lib/turtle.py
+++ b/Lib/turtle.py
@@ -135,7 +135,7 @@ _tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
- 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
+ 'speed', 'st', 'stamp', 'teleport', 'tilt', 'tiltangle', 'towards',
'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
'write', 'xcor', 'ycor']
_tg_utilities = ['write_docstringdict', 'done']
@@ -1614,6 +1614,13 @@ class TNavigator(object):
"""move turtle to position end."""
self._position = end
+ def teleport(self, x=None, y=None, *, fill_gap: bool = False) -> None:
+ """To be overwritten by child class RawTurtle.
+ Includes no TPen references."""
+ new_x = x if x is not None else self._position[0]
+ new_y = y if y is not None else self._position[1]
+ self._position = Vec2D(new_x, new_y)
+
def forward(self, distance):
"""Move the turtle forward by the specified distance.
@@ -2293,6 +2300,15 @@ class TPen(object):
else:
return self._color(self._fillcolor)
+ def teleport(self, x=None, y=None, *, fill_gap: bool = False) -> None:
+ """To be overwritten by child class RawTurtle.
+ Includes no TNavigator references.
+ """
+ pendown = self.isdown()
+ if pendown:
+ self.pen(pendown=False)
+ self.pen(pendown=pendown)
+
def showturtle(self):
"""Makes the turtle visible.
@@ -2710,6 +2726,54 @@ class RawTurtle(TPen, TNavigator):
if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
raise TurtleGraphicsError("bad color sequence: %s" % str(args))
return "#%02x%02x%02x" % (r, g, b)
+
+ def teleport(self, x=None, y=None, *, fill_gap: bool = False) -> None:
+ """Instantly move turtle to an absolute position.
+
+ Arguments:
+ x -- a number or None
+ y -- a number None
+ fill_gap -- a boolean This argument must be specified by name.
+
+ call: teleport(x, y) # two coordinates
+ --or: teleport(x) # teleport to x position, keeping y as is
+ --or: teleport(y=y) # teleport to y position, keeping x as is
+ --or: teleport(x, y, fill_gap=True)
+ # teleport but fill the gap in between
+
+ Move turtle to an absolute position. Unlike goto(x, y), a line will not
+ be drawn. The turtle's orientation does not change. If currently
+ filling, the polygon(s) teleported from will be filled after leaving,
+ and filling will begin again after teleporting. This can be disabled
+ with fill_gap=True, which makes the imaginary line traveled during
+ teleporting act as a fill barrier like in goto(x, y).
+
+ Example (for a Turtle instance named turtle):
+ >>> tp = turtle.pos()
+ >>> tp
+ (0.00,0.00)
+ >>> turtle.teleport(60)
+ >>> turtle.pos()
+ (60.00,0.00)
+ >>> turtle.teleport(y=10)
+ >>> turtle.pos()
+ (60.00,10.00)
+ >>> turtle.teleport(20, 30)
+ >>> turtle.pos()
+ (20.00,30.00)
+ """
+ pendown = self.isdown()
+ was_filling = self.filling()
+ if pendown:
+ self.pen(pendown=False)
+ if was_filling and not fill_gap:
+ self.end_fill()
+ new_x = x if x is not None else self._position[0]
+ new_y = y if y is not None else self._position[1]
+ self._position = Vec2D(new_x, new_y)
+ self.pen(pendown=pendown)
+ if was_filling and not fill_gap:
+ self.begin_fill()
def clone(self):
"""Create and return a clone of the turtle.
diff --git a/Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst b/Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst
new file mode 100644
index 0000000..f14c953
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst
@@ -0,0 +1 @@
+Added :func:`turtle.teleport` to the :mod:`turtle` module to move a turtle to a new point without tracing a line, visible or invisible. Patch by Liam Gersten.