> (in general, always use ValueError and avoid assert).
ValueError is for when,
> an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception
(the docs explicitly note only for builtins, but I'm frankly okay w/ people using it in their code.)
You should not be raising this when you should be raising AssertionError, however, the two conditions are very different; the latter is for conditions that should be true but for some reason aren't. I find these usually crop up when running through a bunch of ifs:
if a:
elif b:
elif c:
else:
# *One* of the above should always match, in this case.
# This branch should never be taken, and it wasn't any fault of the user we're here.
raise AssertionError('good description of the situation')
Attempts to restructure the above are usually fairly bad: you can omit the `else`, but then execution will never take any branch, and if the branches do something like initialize a variable that the code following the branches will make use of, you're doomed anyways, and it's better to bail in an informative manner. You can meld the last elif and else together (i.e., the else just handles case C above), but then it also inadvertently handles unexpected states D, E, etc. too.IMO, AssertionErrors should indicate bugs in the called API. ValueErrors indicate bugs in the caller's use of the API.
(You may choose a less "destructive" method of asserting, such as logging, but in my experience, these get lost, and if you're in an undefined state then you still need to find some way to repair that state, and in my experience most attempts to do so are more trouble than they're worth. It's better to fail earlier and harder and louder, s.t. bugs are discovered and swiftly fixed.)