Open iuriguilherme opened 1 year ago
It is not clear to me exactly what you think is the bug here, and why it is a bug.
You have two code snippets, one of which fails with a TclError
error, and the second which would have failed with a ZeroDivisionError
except that you catch it. It is not clear to me why you are showing us both.
In the second, you try to divide by zero. What else do you expect to happen if not a ZeroDivisionError
?
Here is the last output before error:
radius 166085052802334249071698173012318266377090314221836038405624081264312004535368411213882210420911325849217643483175642178117589293984700913410158163128380945274525164734707988099102348195826982095574448167592415830999693168152203192072486723685128099869307736906836693804557289630130245874228969230203908723929, angle 646
screen xscale 1.9171917571829891e-305
screen yscale 1.2686018129018626e-305
and the full traceback:
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
File "/usr/local/lib/python3.10/turtle.py", line 1992, in circle
self._go(l)
File "/usr/local/lib/python3.10/turtle.py", line 1606, in _go
self._goto(ende)
File "/usr/local/lib/python3.10/turtle.py", line 3195, in _goto
self._newLine()
File "/usr/local/lib/python3.10/turtle.py", line 3287, in _newLine
self.screen._drawline(self.currentLineItem, self.currentLine,
File "/usr/local/lib/python3.10/turtle.py", line 544, in _drawline
self.cv.coords(lineitem, *cl)
File "<string>", line 1, in coords
File "/usr/local/lib/python3.10/tkinter/__init__.py", line 2793, in coords
return [self.tk.getdouble(x) for x in
File "/usr/local/lib/python3.10/tkinter/__init__.py", line 2793, in <listcomp>
return [self.tk.getdouble(x) for x in
_tkinter.TclError: expected floating-point number but got "floating"
Because I ran it in the interactive interpreter, the first line isn't shown, but "line 5" is inside the while loop:
pen.circle(radius, angle)
The actual failing line begins with return [self.tk.getdouble(x) for x in
but the rest is not shown. Here is the full line, in context:
# This is from tkinter/__init__.py
# The Canvas class
def coords(self, *args):
"""Return a list of coordinates for the item given in ARGS."""
# XXX Should use _flatten on args
return [self.tk.getdouble(x) for x in
self.tk.splitlist(
self.tk.call((self._w, 'coords') + args))]
Now this is interesting, I tried to make a shorter reproducer, by setting the program state straight to the last set of values which existed before the TclError
. It raises a completely different exception.
radius = 166085052802334249071698173012318266377090314221836038405624081264312004535368411213882210420911325849217643483175642178117589293984700913410158163128380945274525164734707988099102348195826982095574448167592415830999693168152203192072486723685128099869307736906836693804557289630130245874228969230203908723929
angle = 646
import turtle
pen = turtle.Turtle()
pen.getscreen().xscale = 1.9171917571829891e-305
pen.getscreen().yscale = 1.2686018129018626e-305
pen.circle(radius, angle)
Which gives a different exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.10/turtle.py", line 1992, in circle
self._go(l)
File "/usr/local/lib/python3.10/turtle.py", line 1606, in _go
self._goto(ende)
File "/usr/local/lib/python3.10/turtle.py", line 3168, in _goto
nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
OverflowError: cannot convert float infinity to integer
@iuriguilherme I think at this point you need to:
OverflowError
and ZeroDivisionError
for out of range data are not bugs, and you cannot expect to change the scale of the turtle screen forever without getting out of range.TclError
with the strange error message about "floating".I fear that this will end up being some quirk or bug in tcl/tk that we can't do anything about, but we might be lucky and maybe we can improve it from the tkinter end.
In the second, you try to divide by zero. What else do you expect to happen if not a
ZeroDivisionError
?
The point is why would screen.xscale
and/or screen.yscale
be equal to 0.0?
This happens when you try to use llx, lly, urx, ury values so high for screen.setworldcoordinates()
that some line in the code of that function makes the scale revert to 0.0. Which will cause a ZeroDivisionError
at the next screen.setworldcoordinates()
call because of the line I referenced: https://github.com/python/cpython/blob/3ef9f6b508a8524f385cdc9fdd4b4afca0eac59b/Lib/turtle.py#L1105
The reason I deliberately try to raise a ZeroDivisionError
before trying to call that function is because I wouldn't be able to "rollback" from a failed setworldcoordinates()
attempt. If I just let that function raise a ZeroDivisionError
, my screen would white out because self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
at line 1105 raises that exception after changing other properties of the screen. It doesn't have its own try/except block so the screen is partially reconfigured, which is undesired behavior.
I had fixed the code to prevent that happening, I'll try to wreck the code again and will update this issue. My OP uses 3.11
On Sun, Jan 22, 2023 at 06:57:11PM -0800, Iuri Guilherme wrote:
The point is why would
screen.xscale
and/orscreen.yscale
be equal to 0.0?
Maybe I'm missing something, but isn't that just underflow?
You're zooming out to see an ever increasing section of the turtle world, which makes the scale get smaller and smaller, and eventually it underflows to zero.
eventually it underflows to zero.
That is the problem, it shouldn't become zero. If the new scale is a number too close to zero that the system can't handle because of a floating point precision problem, it should round up and not default to zero IMO
Anyway, the side effect is that TurtleScreen.setworldcoordinates()
will fail as a consequence of tha
Here a code example that can be used to see how and when will it break: https://gist.github.com/iuriguilherme/7b5843bf3a78850d859d384002b6871d
Can you replicate this issue with a minimal reproducible example? Something that doesn't require an entire script using async, logging and sympy, but will still demonstrate the scale going to zero.
Ideally, it should be only four or five lines, and one of them is import turtle
. I tried earlier, but got confusingly different exceptions.
I can confirm that your first script does what you say (I haven't tried your second and third scripts).
But I can't replicate the issue directly. That's probably because I don't understand turtle well enough.
I further "minimalized" the same gist without all the cosmetics. From my end I observed the following (YMMV):
There's a j variable which is the rate of the increasing
j = 2 (or 1) will raise ZeroDivisionError: float division by zero
because screen scale is zero
j = 3 will raise _tkinter.TclError: expected floating-point number but got "floating"
because turtle.pos() will be (inf, inf) which is NaN and tk.getdouble() can't handle it
j = 4 will raise OverflowError: int too large to convert to float
because it will be too large for turtle.forward()
I made a turtle draw a spiral while rescaling the screen according to the last position of the turtle.
Simple code to reproduce (increasing the speed variable will make it crash sooner):
This will raise
_tkinter.TclError: expected floating-point number but got "floating"
when x or y scale gets near 1e-306.But in the code I'm using with a RawTurtle and a TurtleScreen I get
ZeroDivisionError
because somewhere after 6.7e-307 (in my machine) both TurtleScreen's x and y scales becomes 0.0, RawTurtle's position becomes (-inf, -inf) and then this line of code is reached: https://github.com/python/cpython/blob/3ef9f6b508a8524f385cdc9fdd4b4afca0eac59b/Lib/turtle.py#L1105I had to set this in my code to prevent screen becoming blank (because of scale becoming 0.0), so I could stop drawing before it crashes: