Skip to content

feature: More granular exception control #2856

Description

@hansonmcoombs

Is your feature request related to a problem? Please describe.

I often find debugging errors and edge cases to be quite challenging as the issues that cause the exception are often hidden beneath a layer of other general exceptions, which obfuscate the actual source of the error. As and example: when debugging the edge case raised in: #2855 The actual exception I got was: "unable to read budget information from first entry in list file". This is useful for providing a high level explanation of the issue, but makes debugging quite difficult. Additionally many of the exceptions raised like this are the base class Exception, which means that any try/except clause will include all Exceptions that could be raised throughout the case. As an example a try/except clause for the budget file issue would capture both FileNotFoundExceptions as well as the general parsing exception. I could always test whether the file exists first, but here I would have to test all possible exceptions rather than just being able to handle a specific exception appropriately.

Describe the solution you'd like

I would suggest two simple solutions:

  1. Create one or more deticated "FlopyParsingException" or simlilar, so that people could catch just that exception.
  2. Add from context to the raised exception so that those of us who end up debugging can get some additional clarity on the error.

Implementing this in the ListBudget._set_entries method would transform

    def _set_entries(self):
        if len(self.idx_map) < 1:
            return None, None
        if len(self.entries) > 0:
            raise Exception(f"entries already set:{self.entries}")
        if not self.idx_map:
            raise Exception("must call build_index before call set_entries")
        try:
            incdict, cumdict = self._get_sp(
                self.idx_map[0][0], self.idx_map[0][1], self.idx_map[0][2]
            )
        except Exception
            raise Exception(
                "unable to read budget information from first entry in list file"
            )

to

    def _set_entries(self):
        if len(self.idx_map) < 1:
            return None, None
        if len(self.entries) > 0:
            raise Exception(f"entries already set:{self.entries}")
        if not self.idx_map:
            raise Exception("must call build_index before call set_entries")
        try:
            incdict, cumdict = self._get_sp(
                self.idx_map[0][0], self.idx_map[0][1], self.idx_map[0][2]
            )
        except Exception as e:
            raise FlopyParsingException(
                "unable to read budget information from first entry in list file"
            ) from e

Where FlopyParsingException is defined as:

class  FlopyParsingException(Exception):
    """An exception to catch errors when parsing modflow text files"""
    pass

This would transfrom the traceback from:

File ".../python3.14/site-packages/flopy/utils/mflistfile.py", line 679, in _set_entries
    raise Exception(
        "unable to read budget information from first entry in list file"
    )
Exception: unable to read budget information from first entry in list file

to

Traceback (most recent call last):
  File ".../python3.14/site-packages/flopy/utils/mflistfile.py", line 675, in _set_entries
    incdict, cumdict = self._get_sp(
    ^^^^^^^^^^^^^^^^
ValueError: not enough values to unpack (expected 2, got 0)

The above exception was the direct cause of the following exception:

File ".../python3.14/site-packages/flopy/utils/mflistfile.py", line 679, in _set_entries
    raise FlopyParsingException(
        "unable to read budget information from first entry in list file"
    )
FlopyParsingException: unable to read budget information from first entry in list file

I would be happy to help implement this with a pull request, but I would want some consensus that this is the way to go.

Describe alternatives you've considered
None

Activity

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions