-
Notifications
You must be signed in to change notification settings - Fork 292
Assert statements will now raise a check50.Failure by default #361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 4.0.0-dev
Are you sure you want to change the base?
Conversation
Added conditional inferencing on basic binary conditions. Currently, assert x == y will now raise assert x in y will now raise This inferencing can be overridden by simply including the correct exception (or message) to raise: assert x in y, check50.Mismatch(x, y) will still raise More complex conditions, such as: assert (x in y) and (a == b) will still raise a Also added an additional note in the docstring for
|
Nice stuff! Here are my thoughts after trying some checks: Rephrasing "assertion failed:"This would require some explaining for students in early phases, maybe "Expected" or "Checking" is easier to grasp. Difference in behaviorThere is a small difference in behavior between the default
This can be useful, but annoying too as you'd want to carefully pick your variable names because they might just end up as feedback :) Whereas the specific errors don't show the variable names, but the values instead:
gives:
Again useful, but annoying too as most of the times you'd need to signal in some way where that "actual" value is coming from. Although for shorter and simpler checks this is often implicit from the check description. Now in both cases you'd need to be mindful of two different things: either pick your variable names wisely, or remember to mention where "actual" is coming from. Unsure what the best course of action is. I see both behaviors having their application, you might want to signal the variable That said, you can overwrite it both ways:
and
So in that sense the control for a check writer to show what they want is already there. It just seems odd that the default behavior is different. Maybe do both all the time? Rewrite:
to
and in the case of This is in line with Missing importMissing
|
Thanks for all the feedback! I've implemented most of these changes:
assert "1" == '2' will raise
num1 = '1'
num2 = '2'
assert num1 in num2 will raise
Mixing of variables and literals will also work.
num1 = '1'
num2 = '2'
assert num1 == num2 will raise
As opposed to:
num1 = '1'
assert num1 > '2' will raise
|
Got it! I've fixed some of these bugs today. Definitely was a challenge :) Having this check: @check50.check()
def foo():
"""foo"""
assert check50.run("pwd").stdout() == "foo"
@check50.check()
def bar():
"""bar"""
def get_output():
return "bar"
assert get_output() == "foo" will result in this error message
Essentially, during the rewrite stage, I parsed the conditional, and if I found a function, I would reconstruct it as a string from the ground up, and awaited evaluation. Then, I used Now, there's an issue with the current iteration of this assertion rewrite, and it has to do with what you've mentioned already:
This was originally caused by me evaluating and injecting the left side and right side of the conditional (if it existed) into Unfortunately, this merely delays the problem, and there's still two executions of the same function. I haven't figured out how to fix this yet, but I think a viable solution would be wrapping every function contained in the assertion conditional in some kind of memoization function that stores its results and that of its arguments (if the arguments are function calls as well). I think this could avoid us having to use Something like: assert foo(bar, qux()) to check50_assert(memo(foo(bar, memo(qux()))), ...) What do you think? Looks a bit messy, but it shouldn't be visible to the check writer anyways. I'll probably have to implement this tomorrow. The last issue is something I have to look at where the HTML/Jinja does not interpret new lines as line breaks within the |
I was writing this while a new commit popped up, unsure if still relevant:From a distant point of view, wouldn't it make sense to write the visit methods for all the operator Nodes ( Edit: ^ but you would be dealing with nested expressions and that might not be simple to solve. On some futher thought: in case of testing through asserts in the context of Small catch on memoization, you'd probably need to use from random import random
import check50
check50.check()
def foo():
"""foo"""
assert random() == random() # :) Perhaps: assert check50_assert(memo("random()", 0) == memo("random()", 1), ...) |
Finally fixed it! I ended up not passing in the bare conditional at all and went for creating a new, evaluatable
Then, running Now, running these checks:
|
Note to future self: tests failed on commit because the file in check50/tests/checks/internal_directories/init.py has |
Related to #228.
Using
assert
will now no longer raise Python's standardAssertionError
.When
check50
is ran in a CLI, it will make a temporary copy of the checks file, rewrite all assertions, and then run the checks on that temporary, modified file.For instance, a check written as so:
will be rewritten internally as:
If
output == 'abc'
evaluates toFalse
, acheck50.Failure
exception is raised with the message:Assertion failure: output == 'abc
.Custom messages are also supported. For instance,
will now raise
check50.Failure
with the messageExpected output to be 'abc'
.Custom exceptions are also supported. For instance,
will now raise
check50.Mismatch('abc', output)
.If the user adds a valid Python object but it is neither an exception or string, the additional argument is silently ignored and a
check50.Failure
is raised with the default message. For instancewill now raise
check50.Failure
with the messageAssertion failure: output == 'abc
.