
2) Some OTHER exception occurs on the reevaluation. It's a chained exception like any other.
Except it's not a chained exception and displaying as such would be VERY confusing IMO. Granted we could easily strip the chained exception and just return the original one. So after reconsideration I agree this is not an issue.
It's only really the fourth case that would be confusing
I generally agree with your analysis but I think this 4th case is more problematic than you think. Given no information I am immediately going to split my assertion so I can see what part is failing. However, if the interpreter gives me incorrect information I am going to be super confused. Most people will not have carefully read section 7.3 of the language reference and will not understand this critical aspect of the execution of assertion statements. They will assume that the interpreter is not lying to them. I think storing the intermediate results on the stack is vastly preferable to revaluation for this reason. On Mon, Oct 4, 2021 at 3:20 PM Chris Angelico <rosuav@gmail.com> wrote:
On Tue, Oct 5, 2021 at 9:02 AM Caleb Donovick <donovick@cs.stanford.edu> wrote:
I wonder, could this be simplified a bit, on the assumption that a well-written assertion shouldn't have a problem with being executed twice?
While I agree as an engineering principle an assert should not have side
and hence re-evaluation should be fine in most cases, it is not universal. It is possible for assertions to not have side effects but yet change value between evaluations if they interact with a shared resource such as the file system..
For example consider the following assertion:
assert os.path.isdir("config") and os.path.isfile("config/setup.yml")
It is completely possible for the value of this expression to change between evaluations. Granted this would like mean their is some more significant issue with my code, however, I would like the interpreter to give me accurate information about why my assertion failed. Bad information is worse than no information. Like imagine that on the first evaluation the directory config does not exist but on
effects the second it has been created by another process.
A naive revaluation strategy would likely result in it pointing at the second clause and saying the assertion failed their when it really failed on the first clause. This would send me down a rabbit hole of debugging why setup.yml was not constructed properly instead of debugging why the config directory didn’t exist.
That seems like an abuse of assertions. If you have assertions that depend on external state that can change that quickly, then the assertion is *already useless*. What do you gain by asserting something that might have changed by the next line of code?
Further while it is bad engineering practices to have side effects in an assert it is completely possible. For example consider the following pathological example:
class PathologicalFoo: def __init__(self): self._val = 0
def get(self): old_val = self._val self._val = 1 return old_val
foo = PathologicalFoo() assert foo.get() == 1
Yes, side effects in assertions are always possible. If someone has assertions with side effects, do we say that python -O is buggy, or the assertion is buggy? In a world in which assertions might and might not be evaluated, is it such a stretch to demand that they can be safely reevaluated (in the same context)? Yes, it's a change to the expectations, but one which well-designed assertions shouldn't be bothered by.
My imagining of this is that it'd be handled when an AssertionError reaches top level, and it'd be broadly thus:
try: all_your_code() except AssertionError as e: ... reevaluate etc
Meaning there are four possibilities: 1) The assertion is consistent, and the extra info is absolutely correct 2) Some OTHER exception occurs on the reevaluation. It's a chained exception like any other. 3) No assertion failure happens (eg PathologicalFoo). Might require a minor special case "if nothing goes wrong, print out the original" but that's the most obvious thing to do. 4) The assertion fails in an inconsistent way, but it still fails. You'll get the second form instead of the first.
It's only really the fourth case that would be confusing, and only if the first evaluation actually causes the problem (otherwise it's just an inconsistent assertion and you'd need to debug both parts anyway). This is a pretty narrow problem, and even then, you've been shown a weird assertion that needs to be debugged. Is it that bad to say that an assertion that gives inconsistent results is buggy?
ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GYNRJA... Code of Conduct: http://python.org/psf/codeofconduct/