Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which exception should I raise on bad/illegal argument combinations in Python?

I was wondering about the best practices for indicating invalid argument combinations in Python. I've come across a few situations where you have a function like so:

def import_to_orm(name, save=False, recurse=False):
    """
    :param name: Name of some external entity to import.
    :param save: Save the ORM object before returning.
    :param recurse: Attempt to import associated objects as well. Because you
        need the original object to have a key to relate to, save must be
        `True` for recurse to be `True`.
    :raise BadValueError: If `recurse and not save`.
    :return: The ORM object.
    """
    pass

The only annoyance with this is that every package has its own, usually slightly differing BadValueError. I know that in Java there exists java.lang.IllegalArgumentException -- is it well understood that everybody will be creating their own BadValueErrors in Python or is there another, preferred method?

like image 948
cdleary Avatar asked Nov 01 '08 23:11

cdleary


4 Answers

I would just raise ValueError, unless you need a more specific exception..

def import_to_orm(name, save=False, recurse=False):
    if recurse and not save:
        raise ValueError("save must be True if recurse is True")

There's really no point in doing class BadValueError(ValueError):pass - your custom class is identical in use to ValueError, so why not use that?

like image 176
dbr Avatar answered Nov 19 '22 22:11

dbr


I would inherit from ValueError

class IllegalArgumentError(ValueError):
    pass

It is sometimes better to create your own exceptions, but inherit from a built-in one, which is as close to what you want as possible.

If you need to catch that specific error, it is helpful to have a name.

like image 23
Markus Jarderot Avatar answered Nov 19 '22 20:11

Markus Jarderot


I think the best way to handle this is the way python itself handles it. Python raises a TypeError. For example:

$ python -c 'print(sum())'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: sum expected at least 1 arguments, got 0

Our junior dev just found this page in a google search for "python exception wrong arguments" and I'm surprised that the obvious (to me) answer wasn't ever suggested in the decade since this question was asked.

like image 43
J Bones Avatar answered Nov 19 '22 21:11

J Bones


It depends on what the problem with the arguments is.

If the argument has the wrong type, raise a TypeError. For example, when you get a string instead of one of those Booleans.

if not isinstance(save, bool):
    raise TypeError(f"Argument save must be of type bool, not {type(save)}")

Note, however, that in Python we rarely make any checks like this. If the argument really is invalid, some deeper function will probably do the complaining for us. And if we only check the boolean value, perhaps some code user will later just feed it a string knowing that non-empty strings are always True. It might save him a cast.

If the arguments have invalid values, raise ValueError. This seems more appropriate in your case:

if recurse and not save:
    raise ValueError("If recurse is True, save should be True too")

Or in this specific case, have a True value of recurse imply a True value of save. Since I would consider this a recovery from an error, you might also want to complain in the log.

if recurse and not save:
    logging.warning("Bad arguments in import_to_orm() - if recurse is True, so should save be")
    save = True
like image 34
Gloweye Avatar answered Nov 19 '22 21:11

Gloweye