From 4c3cb33db7a9eb037334c77d07d498aefe0ad282 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 28 Sep 2026 09:00:44 +0100 Subject: [PATCH 1/3] gh-157847: Reorganize `turtle` documentation (#157868) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/library/turtle.rst | 487 +++++++++++++++-------------------------- 1 file changed, 175 insertions(+), 312 deletions(-) diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index cf4ce99e482f21..4c0d9350f5a566 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -30,6 +30,7 @@ moves. .. image:: turtle-star.png + :alt: A yellow starburst of thin spikes with a red outline, drawn by turtle. :align: center Imagine a robotic turtle starting at (0, 0) in the x-y plane. @@ -39,7 +40,7 @@ it moves. Give it the command ``turtle.right(25)``, and it rotates in-place 25 degrees clockwise. Turtle graphics is an implementation of `the drawing tools introduced in Logo -`_ in 1967. It was created as an +`__ in 1967. It was created as an educational tool, and its instant, visible feedback makes it an effective way for learners to encounter programming concepts. It is also a convenient way to produce simple graphical output without bringing in external libraries. @@ -49,7 +50,7 @@ This document includes four main sections: * :ref:`turtle-tutorial` teaches the basics of turtle drawing. * :ref:`turtle-reference` describes the functions, methods and classes this module defines. -* :ref:`turtle-howtos` details how to handle specific tasks. +* :ref:`turtle-howtos` detail how to handle specific tasks. * :ref:`turtle-explanation` provides background on the object-oriented interface. @@ -108,12 +109,12 @@ Notice how the turtle, represented by an arrow, points in different directions as you steer it. Experiment with those commands, and also with ``backward()`` and -``right()``. Many commands also have terser aliases, such as ``fd()`` for +``right()``. Many commands also have shorter aliases, such as ``fd()`` for :func:`forward`. Pen control -~~~~~~~~~~~ +^^^^^^^^^^^ Try changing the color - for example, ``color('blue')`` - and width of the line - for example, ``width(3)`` - and then drawing again. @@ -123,7 +124,7 @@ You can also move the turtle around without drawing, by lifting up the pen: The turtle's position -~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^ Send your turtle back to its starting-point (useful if it has disappeared off-screen):: @@ -189,279 +190,25 @@ Finally, complete the filling:: ``end_fill()`` command.) -.. _turtle-howtos: -.. _turtle-how-to: -.. _how-to: - -How-to guides -============= - -This section covers some typical turtle use-cases and approaches. - - -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 ------------------------------------ - -Using ``from turtle import *`` is convenient - but be warned that it imports a -rather large collection of objects, and if you're doing anything but turtle -graphics you run the risk of a name conflict (this becomes even more an issue -if you're using turtle graphics in a script where other modules might be -imported). - -The solution is to use ``import turtle`` - ``fd()`` becomes -``turtle.fd()``, ``width()`` becomes ``turtle.width()`` and so on. (If typing -"turtle" over and over again becomes tedious, use for example ``import turtle -as t`` instead.) - - -Use turtle graphics in a script -------------------------------- - -It's recommended to use the ``turtle`` module namespace as described -immediately above, for example:: - - import turtle as t - from random import random - - for i in range(100): - steps = int(random() * 100) - angle = int(random() * 360) - t.right(angle) - t.fd(steps) - -Another step is also required though - as soon as the script ends, Python -will also close the turtle's window. Add:: - - t.mainloop() - -to the end of the script. The script will now wait to be dismissed and -will not exit until it is terminated, for example by closing the turtle -graphics window. - - -Use object-oriented turtle graphics ------------------------------------ - -.. seealso:: :ref:`Explanation of the object-oriented interface ` - -Other than for very basic introductory purposes, or for trying things out -as quickly as possible, it's more usual and much more powerful to use the -object-oriented approach to turtle graphics. For example, this allows -multiple turtles on screen at once. - -In this approach, the various turtle commands are methods of objects (mostly of -``Turtle`` objects). You *can* use the object-oriented approach in the shell, -but it would be more typical in a Python script. - -The example above then becomes:: - - from turtle import Turtle - from random import random - - t = Turtle() - for i in range(100): - steps = int(random() * 100) - angle = int(random() * 360) - t.right(angle) - t.fd(steps) - - t.screen.mainloop() - -Note the last line. ``t.screen`` is an instance of the :class:`Screen` -that a Turtle instance exists on; it's created automatically along with -the turtle. - -The turtle's screen can be customised, for example:: - - t.screen.title('Object-oriented turtle demo') - t.screen.bgcolor("orange") - - .. _turtle-reference: .. _turtle-graphics-reference: Reference ========= -.. note:: - - In the following documentation the argument list for functions is given. - Methods, of course, have the additional first argument *self* which is - omitted here. - - -Turtle methods --------------- - -Turtle motion - Move and draw - | :func:`forward` | :func:`fd` - | :func:`backward` | :func:`bk` | :func:`back` - | :func:`right` | :func:`rt` - | :func:`left` | :func:`lt` - | :func:`goto` | :func:`setpos` | :func:`setposition` - | :func:`teleport` - | :func:`setx` - | :func:`sety` - | :func:`setheading` | :func:`seth` - | :func:`home` - | :func:`circle` - | :func:`dot` - | :func:`stamp` - | :func:`clearstamp` - | :func:`clearstamps` - | :func:`undo` - | :func:`speed` - - Tell Turtle's state - | :func:`position` | :func:`pos` - | :func:`towards` - | :func:`xcor` - | :func:`ycor` - | :func:`heading` - | :func:`distance` - - Setting and measurement - | :func:`degrees` - | :func:`radians` - -Pen control - Drawing state - | :func:`pendown` | :func:`pd` | :func:`down` - | :func:`penup` | :func:`pu` | :func:`up` - | :func:`pensize` | :func:`width` - | :func:`pen` - | :func:`isdown` - - Color control - | :func:`color` - | :func:`pencolor` - | :func:`fillcolor` - - Filling - | :func:`filling` - | :func:`fill` - | :func:`begin_fill` - | :func:`end_fill` - - More drawing control - | :func:`reset` - | :func:`clear` - | :func:`write` - -Turtle state - Visibility - | :func:`showturtle` | :func:`st` - | :func:`hideturtle` | :func:`ht` - | :func:`isvisible` - - Appearance - | :func:`shape` - | :func:`resizemode` - | :func:`shapesize` | :func:`turtlesize` - | :func:`shearfactor` - | :func:`tiltangle` - | :func:`tilt` - | :func:`shapetransform` - | :func:`get_shapepoly` - -Using events - | :func:`onclick` - | :func:`onrelease` - | :func:`ondrag` - -Special Turtle methods - | :func:`poly` - | :func:`begin_poly` - | :func:`end_poly` - | :func:`get_poly` - | :func:`clone` - | :func:`getturtle` | :func:`getpen` - | :func:`getscreen` - | :func:`setundobuffer` - | :func:`undobufferentries` - +.. _turtle-methods: +.. _methods-of-rawturtle-turtle-and-corresponding-functions: -Methods of TurtleScreen/Screen ------------------------------- - -Window control - | :func:`bgcolor` - | :func:`bgpic` - | :func:`clearscreen` - | :func:`resetscreen` - | :func:`screensize` - | :func:`setworldcoordinates` - -Animation control - | :func:`no_animation` - | :func:`delay` - | :func:`tracer` - | :func:`update` - -Using screen events - | :func:`listen` - | :func:`onkey` | :func:`onkeyrelease` - | :func:`onkeypress` - | :func:`onclick` | :func:`onscreenclick` - | :func:`ontimer` - | :func:`mainloop` | :func:`done` - -Settings and special methods - | :func:`mode` - | :func:`colormode` - | :func:`getcanvas` - | :func:`getshapes` - | :func:`register_shape` | :func:`addshape` - | :func:`turtles` - | :func:`window_height` - | :func:`window_width` - -Input methods - | :func:`textinput` - | :func:`numinput` - -Methods specific to Screen - | :func:`bye` - | :func:`exitonclick` - | :func:`save` - | :func:`setup` - | :func:`title` - - -Methods of RawTurtle/Turtle and corresponding functions -======================================================= +Turtle methods and functions +---------------------------- Most of the examples in this section refer to a Turtle instance called ``turtle``. -Turtle motion -------------- +.. _turtle-motion: + +Move and draw +^^^^^^^^^^^^^ .. function:: forward(distance) fd(distance) @@ -899,7 +646,7 @@ Turtle motion Tell Turtle's state -------------------- +^^^^^^^^^^^^^^^^^^^ .. function:: position() pos() @@ -999,7 +746,7 @@ Tell Turtle's state Settings for measurement ------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^ .. function:: degrees(fullcircle=360.0) @@ -1050,7 +797,7 @@ Settings for measurement Pen control ------------ +^^^^^^^^^^^ Drawing state ~~~~~~~~~~~~~ @@ -1403,7 +1150,7 @@ More drawing control Turtle state ------------- +^^^^^^^^^^^^ Visibility ~~~~~~~~~~ @@ -1631,7 +1378,7 @@ Appearance Using events ------------- +^^^^^^^^^^^^ .. function:: onclick(fun, btn=1, add=None) :noindex: @@ -1705,7 +1452,7 @@ Using events Special Turtle methods ----------------------- +^^^^^^^^^^^^^^^^^^^^^^ .. function:: poly() @@ -1826,7 +1573,7 @@ Special Turtle methods .. _compoundshapes: Compound shapes ---------------- +^^^^^^^^^^^^^^^ To use compound turtle shapes, which consist of several polygons of different color, you must use the helper class :class:`Shape` explicitly as described @@ -1863,8 +1610,11 @@ below: Shape class *only* when using compound shapes like shown above! -Methods of TurtleScreen/Screen and corresponding functions -========================================================== +.. _methods-of-turtlescreen-screen: +.. _methods-of-turtlescreen-screen-and-corresponding-functions: + +Screen methods and functions +---------------------------- Most of the examples in this section refer to a TurtleScreen instance called ``screen``. @@ -1876,7 +1626,7 @@ Most of the examples in this section refer to a TurtleScreen instance called >>> screen = Screen() Window control --------------- +^^^^^^^^^^^^^^ .. function:: bgcolor() bgcolor(color, /) @@ -2022,7 +1772,7 @@ Window control Animation control ------------------ +^^^^^^^^^^^^^^^^^ .. function:: no_animation() @@ -2092,7 +1842,7 @@ See also the RawTurtle/Turtle method :func:`speed`. Using screen events -------------------- +^^^^^^^^^^^^^^^^^^^ .. function:: listen(xdummy=None, ydummy=None) @@ -2201,7 +1951,7 @@ Using screen events Input methods -------------- +^^^^^^^^^^^^^ .. function:: textinput(title, prompt) @@ -2237,7 +1987,7 @@ Input methods Settings and special methods ----------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. function:: mode(mode=None) @@ -2383,9 +2133,10 @@ Settings and special methods .. _screenspecific: +.. _methods-specific-to-screen-not-inherited-from-turtlescreen: -Methods specific to Screen, not inherited from TurtleScreen ------------------------------------------------------------ +Screen-only methods +^^^^^^^^^^^^^^^^^^^ .. function:: bye() @@ -2462,7 +2213,7 @@ Methods specific to Screen, not inherited from TurtleScreen Public classes -============== +-------------- .. class:: RawTurtle(canvas) @@ -2554,7 +2305,7 @@ Public classes Exceptions -========== +---------- The :mod:`!turtle` module defines the following exception: @@ -2572,43 +2323,120 @@ The :mod:`!turtle` module defines the following exception: turtle.TurtleGraphicsError: bad color string: blau -.. _turtle-explanation: +.. _turtle-howtos: +.. _turtle-how-to: +.. _how-to: -Explanation -=========== +How-to guides +============= -A turtle object draws on a screen object, and there a number of key classes in -the turtle object-oriented interface that can be used to create them and relate -them to each other. +This section covers some typical turtle use-cases and approaches. -A :class:`Turtle` instance will automatically create a :class:`Screen` -instance if one is not already present. -``Turtle`` is a subclass of :class:`RawTurtle`, which *doesn't* automatically -create a drawing surface - a *canvas* will need to be provided or created for -it. The *canvas* can be a :class:`!tkinter.Canvas`, :class:`ScrolledCanvas` -or :class:`TurtleScreen`. +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:: -:class:`TurtleScreen` is the basic drawing surface for a -turtle. :class:`Screen` is a subclass of ``TurtleScreen``, and -includes :ref:`some additional methods ` for managing its -appearance (including size and title) and behaviour. ``TurtleScreen``'s -constructor needs a :class:`!tkinter.Canvas` or a -:class:`ScrolledCanvas` as an argument. + with fill(): + for i in range(4): + forward(100) + right(90) -The functional interface for turtle graphics uses the various methods of -``Turtle`` and ``TurtleScreen``/``Screen``. Behind the scenes, a screen -object is automatically created whenever a function derived from a ``Screen`` -method is called. Similarly, a turtle object is automatically created -whenever any of the functions derived from a Turtle method is called. + forward(200) -To use multiple turtles on a screen, the object-oriented interface must be -used. +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 +----------------------------------- + +Using ``from turtle import *`` is convenient - but be warned that it imports a +rather large collection of objects, and if you're doing anything but turtle +graphics you run the risk of a name conflict (this becomes even more an issue +if you're using turtle graphics in a script where other modules might be +imported). + +The solution is to use ``import turtle`` - ``fd()`` becomes +``turtle.fd()``, ``width()`` becomes ``turtle.width()`` and so on. (If typing +"turtle" over and over again becomes tedious, use for example ``import turtle +as t`` instead.) -Help and configuration -====================== + +Use turtle graphics in a script +------------------------------- + +It's recommended to use the ``turtle`` module namespace as described +immediately above, for example:: + + import turtle as t + from random import random + + for i in range(100): + steps = int(random() * 100) + angle = int(random() * 360) + t.right(angle) + t.fd(steps) + +Another step is also required though - as soon as the script ends, Python +will also close the turtle's window. Add:: + + t.mainloop() + +to the end of the script. The script will now wait to be dismissed and +will not exit until it is terminated, for example by closing the turtle +graphics window. + + +Use object-oriented turtle graphics +----------------------------------- + +.. seealso:: :ref:`Explanation of the object-oriented interface ` + +Other than for very basic introductory purposes, or for trying things out +as quickly as possible, it's more usual and much more powerful to use the +object-oriented approach to turtle graphics. For example, this allows +multiple turtles on screen at once. + +In this approach, the various turtle commands are methods of objects (mostly of +``Turtle`` objects). You *can* use the object-oriented approach in the shell, +but it would be more typical in a Python script. + +The example above then becomes:: + + from turtle import Turtle + from random import random + + t = Turtle() + for i in range(100): + steps = int(random() * 100) + angle = int(random() * 360) + t.right(angle) + t.fd(steps) + + t.screen.mainloop() + +Note the last line. ``t.screen`` is an instance of the :class:`Screen` +that a Turtle instance exists on; it's created automatically along with +the turtle. + +The turtle's screen can be customised, for example:: + + t.screen.title('Object-oriented turtle demo') + t.screen.bgcolor("orange") + + +.. _help-and-configuration: How to use help --------------- @@ -2817,6 +2645,41 @@ study it as an example and see its effects when running the demos (preferably not from within the demo-viewer). +.. _turtle-explanation: + +Explanation +=========== + +A turtle object draws on a screen object, and there a number of key classes in +the turtle object-oriented interface that can be used to create them and relate +them to each other. + +A :class:`Turtle` instance will automatically create a :class:`Screen` +instance if one is not already present. + +``Turtle`` is a subclass of :class:`RawTurtle`, which *doesn't* automatically +create a drawing surface - a *canvas* will need to be provided or created for +it. The *canvas* can be a :class:`!tkinter.Canvas`, :class:`ScrolledCanvas` +or :class:`TurtleScreen`. + + +:class:`TurtleScreen` is the basic drawing surface for a +turtle. :class:`Screen` is a subclass of ``TurtleScreen``, and +includes :ref:`some additional methods ` for managing its +appearance (including size and title) and behaviour. ``TurtleScreen``'s +constructor needs a :class:`!tkinter.Canvas` or a +:class:`ScrolledCanvas` as an argument. + +The functional interface for turtle graphics uses the various methods of +``Turtle`` and ``TurtleScreen``/``Screen``. Behind the scenes, a screen +object is automatically created whenever a function derived from a ``Screen`` +method is called. Similarly, a turtle object is automatically created +whenever any of the functions derived from a Turtle method is called. + +To use multiple turtles on a screen, the object-oriented interface must be +used. + + :mod:`!turtledemo` --- Demo scripts =================================== From 4e9ea689fec273b9f848a648a62eba74a0216dfe Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 28 Sep 2026 09:42:15 +0100 Subject: [PATCH 2/3] gh-158322: Tidy up some docstrings in `turtle` module (#158281) --- Lib/turtle.py | 278 +++++++++++++++++++++----------------------------- 1 file changed, 115 insertions(+), 163 deletions(-) diff --git a/Lib/turtle.py b/Lib/turtle.py index 13cd2d8b7e73cb..27c451f1c62be0 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -22,80 +22,17 @@ # 3. This notice may not be removed or altered from any source distribution. """ -Turtle graphics is a popular way for introducing programming to -kids. It was part of the original Logo programming language developed -by Wally Feurzig and Seymour Papert in 1966. - -Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it -the command turtle.forward(15), and it moves (on-screen!) 15 pixels in -the direction it is facing, drawing a line as it moves. Give it the -command turtle.right(25), and it rotates in-place 25 degrees clockwise. - -By combining together these and similar commands, intricate shapes and -pictures can easily be drawn. - ------ turtle.py - -This module is an extended reimplementation of turtle.py from the -Python standard distribution up to Python 2.5. (See: https://www.python.org) - -It tries to keep the merits of turtle.py and to be (nearly) 100% -compatible with it. This means in the first place to enable the -learning programmer to use all the commands, classes and methods -interactively when using the module from within IDLE run with -the -n switch. - -Roughly it has the following features added: - -- Better animation of the turtle movements, especially of turning the - turtle. So the turtles can more easily be used as a visual feedback - instrument by the (beginning) programmer. - -- Different turtle shapes, image files as turtle shapes, user defined - and user controllable turtle shapes, among them compound - (multicolored) shapes. Turtle shapes can be stretched and tilted, which - makes turtles very versatile geometrical objects. - -- Fine control over turtle movement and screen updates via delay(), - and enhanced tracer() and speed() methods. - -- Aliases for the most commonly used commands, like fd for forward etc., - following the early Logo traditions. This reduces the boring work of - typing long sequences of commands, which often occur in a natural way - when kids try to program fancy pictures on their first encounter with - turtle graphics. - -- Turtles now have an undo()-method with configurable undo-buffer. - -- Some simple commands/methods for creating event driven programs - (mouse-, key-, timer-events). Especially useful for programming games. - -- A scrollable Canvas class. The default scrollable Canvas can be - extended interactively as needed while playing around with the turtle(s). - -- A TurtleScreen class with methods controlling background color or - background image, window and canvas size and other properties of the - TurtleScreen. - -- There is a method, setworldcoordinates(), to install a user defined - coordinate-system for the TurtleScreen. - -- The implementation uses a 2-vector class named Vec2D, derived from tuple. - This class is public, so it can be imported by the application programmer, - which makes certain types of computations very natural and compact. - -- Appearance of the TurtleScreen and the Turtles at startup/import can be - configured by means of a turtle.cfg configuration file. - The default configuration mimics the appearance of the old turtle module. - -- If configured appropriately the module reads in docstrings from a docstring - dictionary in some different language, supplied separately and replaces - the English ones by those read in. There is a utility function - write_docstringdict() to write a dictionary with the original (English) - docstrings to disc, so it can serve as a template for translations. - -Behind the scenes there are some features included with possible -extensions in mind. These will be commented and documented elsewhere. +Imagine a robotic turtle starting at (0, 0) in the x-y plane. +After an `import turtle`, give it the command `turtle.forward(15)`, and it +moves (on-screen!) 15 pixels in the direction it is facing, drawing a line as +it moves. Give it the command `turtle.right(25)`, and it rotates in-place 25 +degrees clockwise. + +Turtle graphics is an implementation of the drawing tools introduced in Logo +in 1967. It was created as an educational tool, and its instant, visible +feedback makes it an effective way for learners to encounter programming +concepts. It is also a convenient way to produce simple graphical output +without bringing in external libraries. """ import tkinter as TK @@ -167,7 +104,7 @@ } def config_dict(filename): - """Convert content of config-file into dictionary.""" + """Convert the content of a config file into a dict.""" with open(filename, "r") as f: cfglines = f.readlines() cfgdict = {} @@ -196,17 +133,17 @@ def config_dict(filename): return cfgdict def readconfig(cfgdict): - """Read config-files, change configuration-dict accordingly. + """Read config files and update the configuration dict accordingly. If there is a turtle.cfg file in the current working directory, - read it from there. If this contains an importconfig-value, - say 'myway', construct filename turtle_mayway.cfg else use - turtle.cfg and read it from the import-directory, where - turtle.py is located. - Update configuration dictionary first according to config-file, - in the import directory, then according to config-file in the - current working directory. - If no config-file is found, the default configuration is used. + read it. If it contains an importconfig value, say 'myway', + use the filename turtle_myway.cfg, otherwise turtle.cfg, and + read that file from the directory where turtle.py is located. + + The configuration dict is updated first from the config file in + the turtle.py directory, then from the one in the current working + directory. If no config file is found, the default configuration + is used. """ default_cfg = "turtle.cfg" cfgdict1 = {} @@ -232,46 +169,54 @@ def readconfig(cfgdict): class Vec2D(tuple): - """A 2 dimensional vector class, used as a helper class - for implementing turtle graphics. - May be useful for turtle graphics programs also. - Derived from tuple, so a vector is a tuple! + """A two-dimensional vector class, used as a helper class for + implementing turtle graphics. May be useful for turtle graphics + programs too. Derived from tuple, so a vector is a tuple! Provides (for a, b vectors, k number): - a+b vector addition - a-b vector subtraction - a*b inner product - k*a and a*k multiplication with scalar - |a| absolute value of a - a.rotate(angle) rotation + a + b: vector addition + a - b: vector subtraction + a * b: inner product + k * a and a * k: multiplication with scalar + abs(a): absolute value of a + a.rotate(angle): rotation """ + def __new__(cls, x, y): return tuple.__new__(cls, (x, y)) + def __add__(self, other): return Vec2D(self[0]+other[0], self[1]+other[1]) + def __mul__(self, other): if isinstance(other, Vec2D): return self[0]*other[0]+self[1]*other[1] return Vec2D(self[0]*other, self[1]*other) + def __rmul__(self, other): if isinstance(other, int) or isinstance(other, float): return Vec2D(self[0]*other, self[1]*other) return NotImplemented + def __sub__(self, other): return Vec2D(self[0]-other[0], self[1]-other[1]) + def __neg__(self): return Vec2D(-self[0], -self[1]) + def __abs__(self): return math.hypot(*self) + def rotate(self, angle): - """rotate self counterclockwise by angle - """ + """Rotate self counterclockwise by angle.""" perp = Vec2D(-self[1], self[0]) angle = math.radians(angle) c, s = math.cos(angle), math.sin(angle) return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s) + def __getnewargs__(self): return (self[0], self[1]) + def __repr__(self): return "(%.2f,%.2f)" % self @@ -285,7 +230,7 @@ def __repr__(self): ## to ScrolledCanvas class def __methodDict(cls, _dict): - """helper function for Scrolled Canvas""" + """Helper function for Scrolled Canvas.""" baseList = list(cls.__bases__) baseList.reverse() for _super in baseList: @@ -295,7 +240,7 @@ def __methodDict(cls, _dict): _dict[key] = value def __methods(cls): - """helper function for Scrolled Canvas""" + """Helper function for Scrolled Canvas.""" _dict = {} __methodDict(cls, _dict) return _dict.keys() @@ -357,7 +302,7 @@ def __init__(self, master, width=500, height=350, self._rootwindow.bind('', self.onResize) def reset(self, canvwidth=None, canvheight=None, bg = None): - """Adjust canvas and scrollbars according to given canvas size.""" + """Adjust canvas size, background color and scrollbars.""" if canvwidth: self.canvwidth = canvwidth if canvheight: @@ -375,8 +320,7 @@ def reset(self, canvwidth=None, canvheight=None, bg = None): def adjustScrolls(self): - """ Adjust scrollbars according to window- and canvas-size. - """ + """Adjust scrollbars according to window and canvas size.""" cwidth = self._canvas.winfo_width() cheight = self._canvas.winfo_height() self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth) @@ -454,7 +398,7 @@ def win_height(self): Canvas = TK.Canvas -class TurtleScreenBase(object): +class TurtleScreenBase: """Provide the basic graphics functionality. Interface between Tkinter and turtle.py. @@ -463,14 +407,13 @@ class TurtleScreenBase(object): """ def _blankimage(self): - """return a blank image object - """ + """Return a blank image object.""" img = TK.PhotoImage(width=1, height=1, master=self.cv) img.blank() return img def _image(self, filename): - """return an image object containing the + """Return an image object containing the imagedata from an image file named filename. """ return TK.PhotoImage(file=filename, master=self.cv) @@ -490,20 +433,21 @@ def __init__(self, cv): self._updating = False def _createpoly(self): - """Create an invisible polygon item on canvas self.cv) - """ + """Create an invisible polygon item on canvas self.cv.""" return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="") def _drawpoly(self, polyitem, coordlist, fill=None, outline=None, width=None, top=False): - """Configure polygonitem polyitem according to provided - arguments: - coordlist is sequence of coordinates - fill is filling color - outline is outline color - top is a boolean value, which specifies if polyitem - will be put on top of the canvas' displaylist so it - will not be covered by other items. + """Configure polygon item polyitem according to the given arguments. + + Arguments: + coordlist -- a sequence of coordinates + fill -- the fill color + outline -- the outline color + width -- the outline width + top -- a boolean value, which specifies if polyitem will be + put on top of the canvas' display list so it will not + be covered by other items """ cl = [] for x, y in coordlist: @@ -520,20 +464,21 @@ def _drawpoly(self, polyitem, coordlist, fill=None, self.cv.tag_raise(polyitem) def _createline(self): - """Create an invisible line item on canvas self.cv) - """ + """Create an invisible line item on canvas self.cv.""" return self.cv.create_line(0, 0, 0, 0, fill="", width=2, capstyle = TK.ROUND) def _drawline(self, lineitem, coordlist=None, fill=None, width=None, top=False): - """Configure lineitem according to provided arguments: - coordlist is sequence of coordinates - fill is drawing color - width is width of drawn line. - top is a boolean value, which specifies if polyitem - will be put on top of the canvas' displaylist so it - will not be covered by other items. + """Configure line item lineitem according to the given arguments. + + Arguments: + coordlist -- a sequence of coordinates + fill -- the drawing color + width -- the width of the drawn line + top -- a boolean value, which specifies if lineitem will be + put on top of the canvas' display list so it will not + be covered by other items """ if coordlist is not None: cl = [] @@ -550,13 +495,13 @@ def _drawline(self, lineitem, coordlist=None, def _delete(self, item): """Delete graphics item from canvas. - If item is"all" delete all graphics items. + + If item is "all", delete all graphics items. """ self.cv.delete(item) def _update(self): - """Redraw graphics items on canvas - """ + """Redraw graphics items on canvas.""" if self._updating: # Reentrant call (e.g. a drag handler moving the turtle, # gh-50966): flush drawing without reprocessing input. @@ -592,10 +537,11 @@ def _bgcolor(self, color=None): return self.cv.cget("bg") def _write(self, pos, txt, align, font, pencolor): - """Write txt at pos in canvas with specified font - and color. - Return text item and x-coord of right bottom corner - of text's bounding box.""" + """Write txt at pos on the canvas with specified font and color. + + Return text item and x-coord of right bottom corner of text's + bounding box. + """ x, y = pos x = x * self.xscale y = y * self.yscale @@ -748,13 +694,13 @@ def _type(self, item): return self.cv.type(item) def _pointlist(self, item): - """returns list of coordinate-pairs of points of item - Example (for insiders): - >>> from turtle import * + """Return list of coordinate pairs of points of item. + + For example: >>> getscreen()._pointlist(getturtle().turtle._item) [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982), (9.9999999999999982, 0.0)] - >>> """ + """ cl = self.cv.coords(item) pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)] return pl @@ -775,8 +721,9 @@ def _rescale(self, xscalefactor, yscalefactor): self.cv.coords(item, *newcoordlist) def _resize(self, canvwidth=None, canvheight=None, bg=None): - """Resize the canvas the turtles are drawing on. Does - not alter the drawing window. + """Resize the canvas the turtles are drawing on. + + Does not alter the drawing window. """ # needs amendment if not isinstance(self.cv, ScrolledCanvas): @@ -790,8 +737,7 @@ def _resize(self, canvwidth=None, canvheight=None, bg=None): self.cv.reset(canvwidth, canvheight, bg) def _window_size(self): - """ Return the width and height of the turtle window. - """ + """Return the width and height of the turtle window.""" width = self.cv.winfo_width() if width <= 1: # the window isn't managed by a geometry manager width = self.cv['width'] @@ -805,7 +751,7 @@ def mainloop(self): No argument. - Must be last statement in a turtle graphics program. + Must be the last statement in a turtle graphics program. Must NOT be used if a script is run from within IDLE in -n mode (No subprocess) - for interactive use of turtle graphics. @@ -868,11 +814,10 @@ class Terminator (Exception): class TurtleGraphicsError(Exception): - """Some TurtleGraphics Error - """ + """Raised for invalid arguments or operations.""" -class Shape(object): +class Shape: """Data structure modeling shapes. attribute _type is one of "polygon", "image", "compound" @@ -916,13 +861,15 @@ def addcomponent(self, poly, fill, outline=None): self._data.append([poly, fill, outline]) -class Tbuffer(object): - """Ring buffer used as undobuffer for RawTurtle objects.""" +class Tbuffer: + """Ring buffer used as undo buffer for RawTurtle objects.""" + def __init__(self, bufsize=10): self.bufsize = bufsize self.buffer = [[None]] * bufsize self.ptr = -1 self.cumulate = False + def reset(self, bufsize=None): if bufsize is None: for i in range(self.bufsize): @@ -931,6 +878,7 @@ def reset(self, bufsize=None): self.bufsize = bufsize self.buffer = [[None]] * bufsize self.ptr = -1 + def push(self, item): if self.bufsize > 0: if not self.cumulate: @@ -938,6 +886,7 @@ def push(self, item): self.buffer[self.ptr] = item else: self.buffer[self.ptr].append(item) + def pop(self): if self.bufsize > 0: item = self.buffer[self.ptr] @@ -947,8 +896,10 @@ def pop(self): self.buffer[self.ptr] = [None] self.ptr = (self.ptr - 1) % self.bufsize return (item) + def nr_of_items(self): return self.bufsize - self.buffer.count([None]) + def __repr__(self): return str(self.buffer) + " " + str(self.ptr) @@ -957,9 +908,9 @@ def __repr__(self): class TurtleScreen(TurtleScreenBase): """Provides screen oriented methods like bgcolor etc. - Only relies upon the methods of TurtleScreenBase and NOT - upon components of the underlying graphics toolkit - - which is Tkinter in this case. + Only relies upon the methods of TurtleScreenBase and not upon + components of the underlying graphics toolkit, which is Tkinter + in this case. """ _RUNNING = True @@ -1293,7 +1244,7 @@ def tracer(self, n=None, delay=None): self.update() def delay(self, delay=None): - """ Return or set the drawing delay in milliseconds. + """Return or set the drawing delay in milliseconds. Optional argument: delay -- positive integer @@ -1337,8 +1288,7 @@ def _incrementudc(self): self._updatecounter %= self._tracing def update(self): - """Perform a TurtleScreen update. - """ + """Perform a TurtleScreen update.""" tracing = self._tracing self._tracing = True for t in self.turtles(): @@ -1348,7 +1298,7 @@ def update(self): self._update() def window_width(self): - """ Return the width of the turtle window. + """Return the width of the turtle window. Example (for a TurtleScreen instance named screen): >>> screen.window_width() @@ -1357,7 +1307,7 @@ def window_width(self): return self._window_size()[0] def window_height(self): - """ Return the height of the turtle window. + """Return the height of the turtle window. Example (for a TurtleScreen instance named screen): >>> screen.window_height() @@ -1582,7 +1532,7 @@ def save(self, filename, *, overwrite=False): addshape = register_shape onkeyrelease = onkey -class TNavigator(object): +class TNavigator: """Navigation part of the RawTurtle. Implements methods for turtle movement. """ @@ -2100,10 +2050,12 @@ def _delay(self, n=None): seth = setheading -class TPen(object): +class TPen: """Drawing part of the RawTurtle. + Implements drawing properties. """ + def __init__(self, resizemode=_CFG["resizemode"]): self._resizemode = resizemode # or "user" or "noresize" self.undobuffer = None @@ -2576,7 +2528,7 @@ def _colorstr(self, args): ht = hideturtle -class _TurtleImage(object): +class _TurtleImage: """Helper class: Datatype to store Turtle attributes """ @@ -3410,9 +3362,10 @@ def _rotate(self, angle): self._update() def _newLine(self, usePos=True): - """Closes current line item and starts a new one. - Remark: if current line became too long, animation - performance (via _drawline) slowed down considerably. + """Closes the current line item and starts a new one. + + If the current line becomes too long, animation performance (via _drawline) + can slow down considerably. """ if len(self.currentLine) > 1: self.screen._drawline(self.currentLineItem, self.currentLine, @@ -3629,7 +3582,7 @@ def end_poly(self): self._creatingPoly = False def get_poly(self): - """Return the lastly recorded polygon. + """Return the last recorded polygon. No argument. @@ -3642,11 +3595,10 @@ def get_poly(self): return tuple(self._poly) def getscreen(self): - """Return the TurtleScreen object, the turtle is drawing on. + """Return the TurtleScreen object the turtle is drawing on. No argument. - Return the TurtleScreen object, the turtle is drawing on. So TurtleScreen-methods can be called for that object. Example (for a Turtle instance named turtle): @@ -4013,7 +3965,7 @@ def write_docstringdict(filename="turtle_docstringdict"): f.close() def read_docstrings(lang): - """Read in docstrings from lang-specific docstring dictionary. + """Read in docstrings from a language-specific docstring dictionary. Transfer docstrings, translated to lang, from a dictionary-file to the methods of classes Screen and Turtle and - in revised form - From 7352b6aaa99ed68b055cb3c063657a2e3ba82190 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Mon, 28 Sep 2026 12:08:26 +0300 Subject: [PATCH 3/3] gh-158213: Don't return a str subclass from PyUnicodeWriter_Finish() (#158214) Since GH-157861, every writer uses the read-only optimization of _PyUnicodeWriter_WriteStr(), so the first write of a str subclass instance into an empty writer kept that object as the buffer, and PyUnicodeWriter_Finish() returned it. io.StringIO.getvalue() then returned the written object itself, and the next write re-read it through its __str__() method, which changed the contents and could make read() read past the end of the buffer. Only use the read-only optimization for exact str objects. A subclass is copied into a new buffer, as before GH-157861. --- Lib/test/test_capi/test_unicode.py | 12 ++++++++++++ Lib/test/test_io/test_memoryio.py | 6 +++++- Objects/unicode_writer.c | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index f4bd961017b0ed..032b910a280083 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -1910,6 +1910,18 @@ def test_create(self): self.assertGreater(writer.get_buffer()[0], len(s)) self.assertEqual(writer.finish(), s) + def test_str_subclass(self): + # The read-only optimization must not return a str subclass + class MyStr(str): + def __str__(self): + return self + + writer = self.create_writer(0) + writer.write_str(MyStr('abc')) + result = writer.finish() + self.assertEqual(result, 'abc') + self.assertIs(type(result), str) + def test_repr_null(self): writer = self.create_writer(0) writer.write_utf8(b'var=', -1) diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py index b378505aa8f7db..b6f3aa93e7aa43 100644 --- a/Lib/test/test_io/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -1118,7 +1118,11 @@ def __str__(self): s = MyStr("correct") memio = self.ioclass() memio.write(s) - self.assertEqual(memio.getvalue(), "correct") + value = memio.getvalue() + self.assertEqual(value, "correct") + self.assertIs(type(value), str) + memio.write("!") + self.assertEqual(memio.getvalue(), "correct!") # Also test the fast path where pos == string_size (STATE_ACCUMULATING) memio2 = self.ioclass() diff --git a/Objects/unicode_writer.c b/Objects/unicode_writer.c index d6564ce84ed54e..c1a2af4d9ac1fe 100644 --- a/Objects/unicode_writer.c +++ b/Objects/unicode_writer.c @@ -313,7 +313,7 @@ _PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str) Py_UCS4 maxchar = PyUnicode_MAX_CHAR_VALUE(str); if (maxchar > writer->maxchar || len > writer->size - writer->pos) { - if (writer->buffer == NULL) { + if (writer->buffer == NULL && PyUnicode_CheckExact(str)) { assert(_PyUnicode_CheckConsistency(str, 1)); writer->readonly = 1; writer->buffer = Py_NewRef(str);