-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Issue #3473 #3474
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
Issue #3473 #3474
Changes from all commits
0700b2b
a6feb0b
1ffb6bb
9b485d6
d29c9eb
25045f3
2c0c161
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -443,12 +443,16 @@ def approx(expected, rel=None, abs=None, nan_ok=False): | |
# This has the advantage that it made it easy to support mapping types | ||
# (i.e. dict). The old code accepted mapping types, but would only compare | ||
# their keys, which is probably not what most people would expect. | ||
|
||
if _is_numpy_array(expected): | ||
if isinstance(expected, String): | ||
raise TypeError("Strings can not be approximated") | ||
elif _is_numpy_array(expected): | ||
cls = ApproxNumpy | ||
elif isinstance(expected, Mapping): | ||
cls = ApproxMapping | ||
elif isinstance(expected, Sequence) and not isinstance(expected, String): | ||
for value in expected: | ||
if isinstance(value, (Sequence, String, Mapping)): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe it is better to do check for numbers, and provide a better message to locate the problem: number_types = six.integer_types + (float,)
for index, value in enumerate(expected):
if not isinstance(value, number_types):
msg = 'Sequence must contain only numbers, but found {!r} ({!r}) at index {}'
raise TypeError(msg.format(value, type(value), index)) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We also should add a test for this 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I cant just check for int, float, and long though. I would also have to check for each numpy type too. I do agree that a better message should be there :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nicoddemus How should I approach numpy types? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's already a There's the situation where the user passes a builtin
I think it is worthwhile trying to go with 1), this will make things more convenient for our users at the cost of a little more What do you folks think? |
||
raise TypeError("Sequence contained a value that was not float or int") | ||
cls = ApproxSequence | ||
elif isinstance(expected, Decimal): | ||
cls = ApproxDecimal | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
``pytest.approx`` does not handle strings, but this was not easily apparent so it now raises a ``TypeError`` when a string is passed in as the expected argument. | ||
``pytest.approx`` did not check all elements in a sequence to make sure they were valid type, a ``TypeError`` is now raised when an invalid element is in a sequence. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it would be better if we change the
else:
clause here to check forfloat
/int
, and then add anelse:
clause which fails with everything else?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But isn't string the only thing that cannot currently be approx'd?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind! I did some tests and noticed it doesnt accept things I thought it could.
Would be the final commit correct?
Im not sure how that gets us from passing in [6, (5,4)] though. Because the above clauses would see it as valid, but math.isinf freaks out about it (rightly so).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @Drew-Ack, thanks for replying so quickly!
I'm not sure I follow, could you clarify please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem! Love pytest afterall :)
As an example this elif:
allows this [5, (6,7)] as valid input into the approx function. This technically shouldnt be, because even though its a sequence it will just blow up when appox runs.
The issue comes when math.isinf runs. math.isinf is evaluated in the ApproxSequence class. I show this in #3473
I assume this clause is used purely to delegate which class to use, but provides no checking to make sure the sequence is valid.
Is this something we should try to do?
Should we throw an exception out when an invalid sequence like [5, (6,7)] is given
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad, it was obvious you meant
[5, (6, 7)]
the literal. Sorry about that.I see. I guess we can iterate over every element of
Sequence
andMapping
to ensure their elements arefloat
orint
objects; there might be a performance problem but I don't think people are usingpytest.approx
with arrays so large that this would make a difference.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the first open source project I've contributed too, so I will defer to you developers on what is best practice.
It seems to me we are just picking what point to throw an exception at.
I put together a small test case to see how long it would take :)
Its roughly .28 seconds to run through 1 million elements.
Its roughly 2.8 seconds to run through 10 million.
The pattern holds as you increase by x10
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great, thanks for contributing to pytest, we definitely appreciate it!
What do you think @RonnyPfannschmidt? I think we can get away by keeping things simple and just going with my suggestion in #3474 (comment), but I don't oppose if others prefer to be more through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
basically massive sequences shouldn't use python lists ^^ so the check should be reasonably fine for normal sequences
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, @Drew-Ack could go with a more through check for sequences then? Thanks!