Skip to content
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

BUG: ma.testutils.assert_equal on nans throws AssertionError #6661 #6871

Closed
wants to merge 1 commit into from
Closed

BUG: ma.testutils.assert_equal on nans throws AssertionError #6661 #6871

wants to merge 1 commit into from

Conversation

mcdaniel67
Copy link

Fixes #6661 and makes np.ma.testutils.assert_equal's functionality more closely match np.testing.assert_equal

Previous Functionality:

>>> import numpy as np
>>> from numpy.ma.testutils import assert_equal
>>> from numpy.testing import assert_equal as a_e
>>> a_e(np.nan, np.nan)
>>> assert_equal(np.nan, np.nan)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "numpy/ma/testutils.py", line 130, in assert_equal
    raise AssertionError(msg)
AssertionError:
Items are not equal:
 ACTUAL: nan
 DESIRED: nan

Modified Functionality:

>>> import numpy as np
>>> from numpy.ma.testutils import assert_equal
>>> from numpy.testing import assert_equal as a_e
>>> a_e(np.nan, np.nan)
>>> assert_equal(np.nan, np.nan)

@@ -121,7 +121,11 @@ def assert_equal(actual, desired, err_msg=''):
raise AssertionError("%s not in %s" % (k, actual))
assert_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg))
return
# Case #2: lists .....
# Case #2: nan
if isinstance(actual, float) and isinstance(desired, float) and \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use (...) instead of line continuation here.

@charris
Copy link
Member

charris commented Dec 21, 2015

Oh, this is a horrible, horrible function. Let me think about it...

@mcdaniel67
Copy link
Author

Ok, either way that should be a minor change to make. The reason I elected to go for the line continuation was matching the style used in line 137. And yeah, this function is... interesting.

Would it be worth adding unit tests for np.ma.testutils.assert_equal and working on refactoring?

@charris
Copy link
Member

charris commented Dec 21, 2015

Note xor with two booleans is !=, so that simplifies some stuff also.

Yes, a test would be highly desirable, required even ;)

@charris
Copy link
Member

charris commented Dec 21, 2015

Here is equivalent

def assert_equal(actual, desired, err_msg=''):
    if not (isinstance(actual, masked_array) or
            isinstance(desired, masked_array)):
        return utils.assert_equal(actual, desired)
    if isinstance(desired, dict):
        raise AssertionError()
    if (actual is masked) != (desired is masked):
        raise ValueError()

    actual = np.asanyarray(actual)
    desired = np.asanyarray(desired)
    if actual.dtype.kind == "S" and desired.dtype.kind == "S":
        actual = actual.tolist()
        desired = actual.tolist()
        return _assert_equal_on_sequences(actual, desired, err_msg=err_msg)
    return assert_array_equal(actual, desired, err_msg)

Note that unicode strings are not handled (python 3) and I'm not clear on why the special casing unless there is (was) a problem with fill value. Should be able to use an empty string for masked fill values I think, but currently maskled string arrays use "N/A". We should consider changing that.

@mcdaniel67
Copy link
Author

Ok, thanks! Should I use that as a refactored base to make my changes on top of?

@charris
Copy link
Member

charris commented Dec 21, 2015

It needs some filling out with error messages and such, it is a stripped down version. I think it should solve your problem as is, delegating it to the unmasked version. Writing some tests first would be good. The string problem needs an enhancement. I think we should be using an empty string in those cases.

@charris
Copy link
Member

charris commented Dec 22, 2015

I think the strings can be handled like so. sixu needs import from numpy.compat.

def assert_equal(actual, desired, err_msg=''):
    # if nothing masked, default to ndarray version.
    if not (isinstance(actual, masked_array) or
            isinstance(desired, masked_array)):
        return utils.assert_equal(actual, desired)

    # if desired is a dict, actual must be also.
    if isinstance(desired, dict):
        raise AssertionError()
    # masked only compares with masked.
    if (actual is masked) != (desired is masked):
        raise ValueError()

    actual = np.asanyarray(actual)
    desired = np.asanyarray(desired)

    # Deal with string types
    if actual.dtype.kind in "SU":
        val = b'' if actual.dtype.kind == "S" else sixu('')
        actual = masked_array(actual, copy=False, subok=True, fill_value=val)
    if desired.dtype.kind in "SU":
        val = b'' if desired.dtype.kind == "S" else sixu('')
        desired = masked_array(desired, copy=False, subok=True, fill_value=val)

    return assert_array_equal(actual, desired, err_msg)

@mcdaniel67
Copy link
Author

Ah alright, perfect! Thanks for the help, I'll try my hand at implementing the described changes!

@mcdaniel67
Copy link
Author

Should I push my commits directly to this branch, or would the refactoring indicate that I should do this as a separate PR?

@charris
Copy link
Member

charris commented Dec 23, 2015

Just push to your branch. When everything is ready, you can squash your commits together and rewrite the first commit message to match format in http://docs.scipy.org/doc/numpy-1.10.1/dev/gitwash/development_workflow.html, followed by a force push git push -f origin <your branch>.

Previously, np.ma.testutils.assert_equal failed for two nans. The new functionality more closely mirrors np.testing.assert_equal, and is logically more correct.
Refactored code to be more legible and concise. Added tests for
np.ma.testutils.assert_equal.

Had to modify np.testing.assert_equal to keep
np.ma.testutils.assert_equal working properly.
@mcdaniel67
Copy link
Author

@charris Could you re-review this? I think I've gotten it into a pretty good state.

@mcdaniel67
Copy link
Author

@charris Should I recreate this PR or will it still be reviewed? I know it's far enough down in the listed PRs now that it has the potential to be skipped over easily.

@@ -347,6 +347,8 @@ def assert_equal(actual,desired,err_msg='',verbose=True):
try:
# isscalar test to check cases such as [np.nan] != np.nan
if isscalar(desired) != isscalar(actual):
if desired == actual:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

@charris
Copy link
Member

charris commented Mar 7, 2016

I'll need to take a closer look, I note that you did things differently than suggested, so I need to restudy the problem.

@@ -91,6 +91,21 @@ def _assert_equal_on_sequences(actual, desired, err_msg=''):
return


def _assert_equal_both_non_masked(actual, desired, err_msg=''):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be a separate function, it makes the code harder to follow and is only used once.

@charris
Copy link
Member

charris commented Mar 7, 2016

Close and reopen to see if tests of unsupported Python versions go away. Otherwise may need a rebase on master

@charris charris closed this Mar 7, 2016
@charris charris reopened this Mar 7, 2016
@charris charris added this to the 1.12.0 release milestone Apr 16, 2016
@charris
Copy link
Member

charris commented Jun 15, 2016

@mcdaniel67 Needs to be finished.

@charris charris removed this from the 1.12.0 release milestone Jun 15, 2016
@homu
Copy link
Contributor

homu commented Sep 2, 2016

☔ The latest upstream changes (presumably #7099) made this pull request unmergeable. Please resolve the merge conflicts.

@mcdaniel67 mcdaniel67 closed this Nov 11, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: ma.testutils.assert_equal on nans throws AssertionError
3 participants