Skip to content

Chain exceptions where appropriate #15986

Closed

Description

@eric-wieser

Picking up from #15731, there are many places in numpy where we do something like:

try:
    something_which_throws_typeError
except TypeError:
    raise ValueError("a clearer explanation of what went wrong")

It would produce a marginally clearer error if we could change these to use traceback chaining. Our two options are either:

  1. The inner error provides valuable information that is not present in the outer error. We should use from e.
    try:
        something_which_throws_typeError
    except TypeError as e:
        raise ValueError("a clearer explanation of what went wrong") from e
  2. The inner error provides no valuable information that is not present in the outer error. We should use from None:
    try:
        some_dict[name]
    except KeyError:
        raise ValueError("The name %s is not supported" % name) from None
    In that example all the information from the KeyError is already in the message of the new error, so there is no point chaining

An example of such a change would be this line of this otherwise-discarded patch.

For now, I would recommend we only apply this to cases where the exception is thrown unconditionally, as other cases can be more nuanced.


Please see this list for potential places to contribute. Special thanks to @nkleinbaer for compiling the list!

Activity

  1. seberg commented on Apr 17, 2020

    @seberg
    Member

    Sure @JanukanS, thanks. We don't usually assign issues. So you can search for these type of calls and simply open a PR with suggested changes linking this issue.

  2. keremh commented on Apr 18, 2020

    @keremh
    Contributor

    Hi @seberg
    I determined the part to be changed, can i work on this issue too?

  3. ayao451 commented on Jun 30, 2020

    @ayao451

    Can I work on this issue? It is my first issue and I want to give it a try!

  4. rossbar commented on Jul 1, 2020

    @rossbar
    Contributor

    @ayao451 please feel free. A good place to start might be by checking the PRs linked in this issue: exception chaining has been added in quite a few places, and a few other instances have been identified as better off unchanged (e.g. nested exceptions in the test suite).

  5. rossbar commented on Jul 12, 2020

    @rossbar
    Contributor

    A lot of these instances have been fixed (thanks to all the contributors for this!) It would be nice to have a "definition of done" for this issue if anyone wants to do a little forensics to see what's already been tackled, what's been reviewed and determined better left as-is, and what still remains to be done.

  6. nkleinbaer commented on Jul 17, 2020

    @nkleinbaer

    @rossbar I think I can help the 'forensics' you describe above. My thought was to create a regex expression to search for instances of nested exceptions in the codebase (excluding tests). Something like (\s*)except .*\n(\1\s+.*\n)*\1\s+raise to capture the indentation level of the original except statement, then searching for raise within that indent block.

    Then I could cross-reference that list with those instances that have already been addressed in the PRs above, and make a table of what's been addressed and what still needs to be reviewed.

    Does that seem like a reasonable approach? I'm a complete beginner, found this issue through the 'good first issue' tag, so just want to ensure I'm not going down a rabbit hole or creating additional confusion.

  7. rossbar commented on Jul 18, 2020

    @rossbar
    Contributor

    @nkleinbaer that approach sounds reasonable, and I think tabulating the results in this issue would be very useful. Even if the cross-referencing proves to be difficult to automate, having a list of all of the potential instances for exception chaining would help finish off this issue. If you are interested in taking this on I think that'd be great! Feel free ping with any questions/comments.

  8. nkleinbaer commented on Jul 18, 2020

    @nkleinbaer

    OK, to start off here is a table of the files that have been touched in reference to this issue, the number of instances reviewed, the action taken, and associated PRs. I've used the nomenclature "Implemented exception chaining" to indicate something of the form except SomeError as e: raise SomeOtherError from e and "Explicitly silenced exception chaining" to indicate the form except SomeError as e: raise SomeOtherError from None. Please correct if the this can be phrased better.

    In some cases my regex found additional instances of 'nested' exceptions in these files that I do not see included in the PRs. It may be the case that they were intentionally left as is, but because I cannot find any documented 'review' of them I have included them for completeness.

    File Action Taken Associated PR(s) Comments
    ctypeslib.py 1 instance each: explicitly silenced exception chaining and implemented exception chaining #16418 1 additional instances may need review
    except OSError:
    core/_dtype.py 1 instance(s): explicitly silenced exception chaining #16418
    core/_internal.py 2 instance(s): explicitly silenced exception chaining #16747
    core/fromnumeric.py 1 instance(s): implemented exception chaining #16418
    core/memap.py 1 instance(s): explicitly silenced exception chaining #16067
    core/records.py 2 instance(s): implemented exception chaining #16418 1 additional instance may need review
    except Exception:
    core/code_generators/generate_umath.py 1 instance(s): implemented exception chaining #16254
    distutils/command/build_clib.py 1 instance(s): implemented exception chaining #16032
    distutils/command/build_ext.py 1 instance(s): implemented exception chaining #16042
    lib/_datasource.py 1 instance(s): Completely removed nested exception -> left inner exception by itself #16761
    lib/hisograms.py 1 instance(s): implemented exception chaining #16064 1 additional instance added in #16129 - seems to implement exception chaining correctly but may need review
    lib/index_tricks.py 1 instance(s): implemented exception chaining #16064 1 additional instance needs review
    except (ValueError, TypeError):
    lib/npyio.py 2 instance(s): implemented exception chaining #16121 A bit confused on what happened here. My regex finds 8 instances total - I think all have been reviewed and some were determined to be better left as is in #16218, may be worth a second look
    lib/shape_base.py 1 instance(s): explicitly silenced exception chaining #16064 2 additional instances may need review
    except TypeError:
    except TypeError:
    lib/ufunclike.py 2 instance(s): implemented exception chaining #16064
    linalg/linalg.py 2 instance(s): implemented exception chaining #16061
    ma/core.py 1 instance(s): explicitly silenced exception chaining #16067 3 additional instances may need review
    except ValueError:
    except (OverflowError, ValueError):
    except IndexError:
    matrixlib/defmatrix.py 1 instance(s): explicitly silenced exception chaining #16215
    polynomial/polyutils.py 2 instance(s): implemented exception chaining #16061
  9. nkleinbaer commented on Jul 18, 2020

    @nkleinbaer

    And here is a table of additional files/instances found by my regex that have NOT yet been reviewed in a PR related to this issue. Some of these look like they are already handling exception chaining properly (example einsumfunc.py), but again included here for completeness because I see no documentation of an explicit review.

    File Instances found by Regex Instances
    init.py 2
    except ImportError:
    except AssertionError:
    compat/py3k.py 1
    except AttributeError:
    core/_type_aliases.py 1
    except StopIteration:
    core/einsumfunc.py 2
    except TypeError as e:
    except TypeError as e:
    core/code_generators/genapi.py 1
    except Exception:
    distutils/conv_template.py 4
    except KeyError:
    except ValueError as e:
    except ValueError as e:
    except ValueError as e:
    distutils/mingw32ccompiler.py 1
    except KeyError:
    distutils/unixccompiler.py 2
    except DistutilsExecError as e:
    except DistutilsExecError as e:
    distutils/command/config.py 3
    except IOError as e:
    except (DistutilsExecError, CompileError) as e:
    except Exception:
    distutils/fcompiler/init.py 2
    except DistutilsExecError as e:
    except DistutilsExecError as e:
    distutils/fcompiler/compaq.py 3
    except AttributeError as e:
    except IOError as e:
    except ValueError as e:
    distutils/fcompiler/environment.py 1
    fft/_pocketfft.py 1
    except KeyError:
    lib/arraypad.py 1
    raise ValueError("unsupported keyword arguments for mode '{}': {}"
    lib/arraysetops.py 2
    except np.AxisError:
    except TypeError:
    lib/format.py 4
    except struct.error:
    except SyntaxError as e:
    except TypeError:
    except UnicodeError as err:
    linalg/lapack_lite/make_lite.py 1
    except subprocess.CalledProcessError:
    ma/mrecords.py 3
    except (TypeError, KeyError):
    except Exception:
    except (TypeError, KeyError):
    ma/timer_comparison.py 1
    except ValueError:
    polynomial/_polybase.py 2
    except ZeroDivisionError as e:
    except ZeroDivisionError as e:
  10. rossbar commented on Jul 19, 2020

    @rossbar
    Contributor

    Thanks for taking the time to put this report together @nkleinbaer , this is a really nice review of the current state of things!

    I think the most effective way to present the information to help close this issue would be if we could take all of the instances that you found in your regex search, and list them using a list of checkboxes, e.g.

     - [x] https://github.com/numpy/numpy/blob/6ef5ec39cdfaf77aa4600ec2e3bf9f679a4fd527/numpy/ctypeslib.py#L151
     - [ ] https://github.com/numpy/numpy/blob/6ef5ec39cdfaf77aa4600ec2e3bf9f679a4fd527/numpy/__init__.py#L127
     ...
    

    where instances that have been changed or reviewed get a check, and instances that haven't been addressed yet are left un-checked. That way, we have a running list of the instances where a decision has been made (whether to chain exceptions, use from None, or leave as-is) so that contributors can focus on the remaining ones.

    This should give us a list like:

    which I believe GitHub will summarize in a progress bar for the issue.

    If it is easy for you to re-organize your results in this way and you don't mind the extra effort, it'd be great if you could add a list formatted as described in a comment below, then I will take the list and move it up to the top comment so it is more visible. You've already done plenty though, so if you don't have the bandwidth that's totally fine - just let me know and I'll organize the list using your results. Thanks for all you've done so far!

  11. nkleinbaer commented on Jul 20, 2020

    @nkleinbaer

    Sure, I can do that! I actually wanted to have check boxes in the tables above, but couldn't figure out how to do the formatting (not sure if possible at all). Mega-checklist to follow.

  12. 17 remaining items

  13. labbunny commented on Apr 21, 2021

    @labbunny

    Hello everyone. I'm new to open-source and I want to start doing some work.
    Can I jump in and contribute to the solution of this issue? As you see I already tried to commit some code but it failed on few tests. Can somebody explain what went wrong? @eric-wieser perhaps?

  14. mattip commented on Jun 9, 2021

    @mattip
    Member

    ... with that please realize that this is a low priority issue, so PRs may take a while to get reviewed and merged. And as I commented above:

    We would like to suggest that contributors show the output from the error. This will require you think about the error: is the code path actually hit? Does it make sense to chain the exception?

  15. adithya-1 commented on Aug 17, 2021

    @adithya-1

    Hey @eric-wieser, I am new to open source and would like to contribute to this project. Can I work on this issue?

  16. added 2 commits that reference this issue on Aug 17, 2021
  17. mattip commented on Aug 19, 2021

    @mattip
    Member

    I think we have gotten about as much mileage as possible from this issue and would like to close it. @eric-wieser what do you think?

  18. eric-wieser commented on Aug 19, 2021

    @eric-wieser
    MemberAuthor

    I think I agree @mattip, feel free to close. We can still review any remaining open PRs.

    I'm curious if any contributors who contributed for the first time to numpy thanks to this issue ended up making further contributions later, or if they've all just been drive-by one-off contributions.

  19. mattip commented on Aug 19, 2021

    @mattip
    Member

    Maybe they are now contributing elsewhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions