• how to discover what values produced an exception?

    From Johanne Fairchild@21:1/5 to All on Fri May 3 10:56:39 2024
    How to discover what values produced an exception? Or perhaps---why
    doesn't the Python traceback show the values involved in the TypeError?
    For instance:

    --8<-------------------------------------------------------->8---
    (0,0) < 4
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: '<' not supported between instances of 'tuple' and 'int' --8<-------------------------------------------------------->8---

    It could have said something like:

    --8<-------------------------------------------------------->8---
    TypeError: '<' not supported between instances of 'tuple' and 'int'
    in (0,0) < 4. --8<-------------------------------------------------------->8---

    We would know which were the values that caused the problem, which would
    be very helpful.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Johanne Fairchild on Fri May 3 14:26:58 2024
    Johanne Fairchild <jfairchild@tudado.org> wrote or quoted:
    How to discover what values produced an exception?

    An exception isn't always tied to a value. I could, like, write:

    if 3 > 2: "".call()

    And I'd get an AttributeError exception. Can I now say the
    values 3 and 2 caused this exception? Or was it the empty
    string? Or the lack of a call method?

    Let me try your example here: In the console:

    ( 0, 0 )< 4
    |TypeError: '<' not supported between instances of 'tuple' and 'int'

    In this case, the values aren't important, one could even
    say they're a distraction. What matters are the types of the
    values, and those were given. However, the values are visible
    in the console as they were typed in. In a script:

    |Traceback (most recent call last):
    | File "Main.py", line 1, in <module>
    | ( 0, 0 )< 4
    |TypeError: '<' not supported between instances of 'tuple' and 'int'

    . Now I can see the offending line, which in this case even spills
    the beans on the values.

    Sometimes you really need those values. If they're values of global
    names, you can kind of get them in the IDLE shell up to a point.

    So I write this script in the IDLE editor and then run it:

    a = 4
    ( 0, 0 )< a

    . Now I get this in the IDLE console:

    |Traceback (most recent call last):
    | File "Main.py", line 2, in <module>
    | ( 0, 0 )< a
    |TypeError: '<' not supported between instances of 'tuple' and 'int'

    . Then I can type

    a

    into the console, hit Return, and I see the value 4.

    This script here has local variables, and that trick ain't
    gonna fly no more:

    def main():
    a = 4
    ( 0, 0 )< a

    main()

    Now you got to add a debug print statement and run the script again.

    def main():
    a = 4
    print( a )
    ( 0, 0 )< a

    main()

    In a bigger script there's all kinds of values and variables,
    and sometimes the Python implementation can't know which ones
    are critical for an exception, so the programmer's got to step
    in and write those debug print statements.

    (You could also use the IDLE debugger to see local variables,
    but I prefer debug print statements.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Johanne Fairchild via Python-list on Fri May 3 17:39:46 2024
    On 5/3/2024 9:56 AM, Johanne Fairchild via Python-list wrote:
    How to discover what values produced an exception? Or perhaps---why
    doesn't the Python traceback show the values involved in the TypeError?
    For instance:

    --8<-------------------------------------------------------->8---
    (0,0) < 4
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: '<' not supported between instances of 'tuple' and 'int' --8<-------------------------------------------------------->8---

    It could have said something like:

    --8<-------------------------------------------------------->8---
    TypeError: '<' not supported between instances of 'tuple' and 'int'
    in (0,0) < 4. --8<-------------------------------------------------------->8---

    We would know which were the values that caused the problem, which would
    be very helpful.

    In this example it would not help at all to know the actual values.
    Knowing that you are trying to compare incomparable types is enough.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alan Bawden@21:1/5 to Johanne Fairchild via Python-list on Fri May 3 19:29:43 2024
    Thomas Passin <list1@tompassin.net> writes:

    On 5/3/2024 9:56 AM, Johanne Fairchild via Python-list wrote:
    > How to discover what values produced an exception? Or perhaps---why
    > doesn't the Python traceback show the values involved in the TypeError?
    > For instance:
    >
    > --8<-------------------------------------------------------->8---
    >>>> (0,0) < 4
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > TypeError: '<' not supported between instances of 'tuple' and 'int'
    > --8<-------------------------------------------------------->8---
    >
    > It could have said something like:
    >
    > --8<-------------------------------------------------------->8---
    > TypeError: '<' not supported between instances of 'tuple' and 'int'
    > in (0,0) < 4.
    > --8<-------------------------------------------------------->8---
    >
    > We would know which were the values that caused the problem, which would
    > be very helpful.

    In this example it would not help at all to know the actual values. Knowing
    that you are trying to compare incomparable types is enough.

    In general, it absolutely can help. The programmer can sometimes
    recognize where a value of unexpected type came from just by looking at
    it, allowing her to quickly deduce just what went wrong without further investigation.

    A good error message shouldn't withhold any information that can
    _easily_ be included. Debugging is more art than science, so there is
    no real way to predict what information might prove useful in solving
    the crime. I emphasized "easily" because of course you have to draw the
    line somewhere.

    The fact that Python error messages often fail to mention the actual
    objects that caused the error has always annoyed me. I've always
    presumed that for some reason it just wasn't easy to do. And it's never
    been more than a minor annoyance to me.

    So the OP is not wrong for wishing for this. Other programming
    languages do it. Other Python programmers miss it.

    - Alan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Sat May 4 14:15:02 2024
    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    Sometimes you really need those values. If they're values of global
    names, you can kind of get them in the IDLE shell up to a point.

    The way I see it, the issue here isn't just on Python,
    the language - it's also on us, the coders! I mean, when
    I define my own function, I can roll with something like:

    def function( value ):
    if value > 0:
    return log( value )
    else:
    raise ZeroDivisionError( 'domain error' )

    print( function( -1 ))

    . Or I can go with something like this:

    def function( value ):
    if value > 0:
    return log( value )
    else:
    message = 'domain error: '
    message += '\nThe argument value was: '+ repr( value ) + '.'
    message += '\nbut a value > 0 was expected.'
    raise ZeroDivisionError( message )

    print( function( -1 ))

    . And you know what? The second option's gonna give you this output:

    ZeroDivisionError: math domain error:
    The argument value was: -1.
    but a value > 0 was expected.

    .

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Sat May 4 14:47:52 2024
    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    raise ZeroDivisionError( 'domain error' )
    ...
    raise ZeroDivisionError( message )

    I meant "ValueError", not "ZeroDivisionErrror"!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dieter.maurer@online.de@21:1/5 to Johanne Fairchild on Sat May 4 18:24:29 2024
    Johanne Fairchild wrote at 2024-5-3 10:56 -0300:
    How to discover what values produced an exception? Or perhaps---why
    doesn't the Python traceback show the values involved in the TypeError?
    For instance:

    --8<-------------------------------------------------------->8---
    (0,0) < 4
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: '<' not supported between instances of 'tuple' and 'int' >--8<-------------------------------------------------------->8---

    It could have said something like:

    --8<-------------------------------------------------------->8---
    TypeError: '<' not supported between instances of 'tuple' and 'int'
    in (0,0) < 4.
    --8<-------------------------------------------------------->8---

    We would know which were the values that caused the problem, which would
    be very helpful.

    Typically, the traceback informs you about the source code line
    where the exception has been raised.
    When the source line contains literals, you see the values.
    If not, then only in special (speak: rather simple) cases the
    knowledge of the values will help much.
    Usually, a more thorough analysis is required to find out the bug
    location and how to fix the bug.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Sat May 4 19:08:26 2024
    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    def function( value ):
    if value > 0:
    return log( value )
    else:
    raise ZeroDivisionError( 'domain error' )

    Otherwise, I reckon the stopgap solution for dealing with those
    "features" would be something like this . . .

    try:
    function( value )
    except ValueError:
    print( 'value =', value )
    raise

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Johanne Fairchild on Sat May 4 20:13:23 2024
    Johanne Fairchild <jfairchild@tudado.org> wrote or quoted:
    We would know which were the values that caused the problem, which would
    be very helpful.

    So, why don't critical values get automatically printed out when
    exceptions happen?

    In Python, printing out a value usually means calling a method
    like "__str__" or "__repr__". But the thing is, the exception
    could have been raised inside that very method. If you then try
    to automatically print out a critical value, that could trigger
    more exceptions or other issues. Basically, you could end up
    activating all sorts of random code, and the consequences of
    that in that kind of situation are hard to predict

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From 2QdxY4RzWzUUiLuE@potatochowder.com@21:1/5 to Johanne Fairchild via Python-list on Sat May 4 15:33:00 2024
    On 2024-05-03 at 10:56:39 -0300,
    Johanne Fairchild via Python-list <python-list@python.org> wrote:

    How to discover what values produced an exception? Or perhaps---why
    doesn't the Python traceback show the values involved in the TypeError?
    For instance:

    --8<-------------------------------------------------------->8---
    (0,0) < 4
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: '<' not supported between instances of 'tuple' and 'int' --8<-------------------------------------------------------->8---

    It could have said something like:

    --8<-------------------------------------------------------->8---
    TypeError: '<' not supported between instances of 'tuple' and 'int'
    in (0,0) < 4. --8<-------------------------------------------------------->8---

    We would know which were the values that caused the problem, which would
    be very helpful.

    I'm not disagreeing that knowing the values could be useful in many
    cases. In the general case, though, it's not practical. Consider a
    function like this:

    def f(x, y):
    return g(x) < h(y)

    The printed values of x, y, g(x), and h(y) could all be millions of (or
    more) glyphs. Worse, one or more of those values could contain circular
    lists or similar structures. And h or g could have changed x or y. In summary, printing run-time values isn't always safe or useful. At least printing the types is safe. In the face of ambiguity, refuse to guess.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)