Skip to content

Table > value should not work - #828

Merged
astrofrog merged 10 commits into
astropy:masterfrom
astrofrog:table-disallow-inequality-comparisons
Sep 30, 2013
Merged

astrofrog merged 10 commits into
astropy:masterfrom
astrofrog:table-disallow-inequality-comparisons

Conversation

@astrofrog

Copy link
Copy Markdown
Member

In Python 2, the following works:

In [1]: from astropy.table import Table

In [2]: t = Table([[1,2,3]])

In [3]: t > 0.2
Out[3]: True

but I think it shouldn't, and indeed doesn't in Python 3:

In [1]: from astropy.table import Table

In [2]: t = Table([[1,2,3]])

In [3]: t > 0.2
ERROR: TypeError: unorderable types: Table() > float() [IPython.core.interactiveshell]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-26baf2ef9239> in <module>()
----> 1 t > 0.2

TypeError: unorderable types: Table() > float()

The Python 2 behavior led me to confusion when I did t[t > 0.2] by mistake, when I meant t[t['RA'] > 0.2].

@ghost ghost assigned taldcroft Feb 26, 2013
@taldcroft

Copy link
Copy Markdown
Member

That's a generic property of object in Python 2.

In [1]: class A(object):
   ...:     pass
   ...: 
In [2]: a = A()
In [3]: a > 2
Out[3]: True

Do you think we should overload all the comparisons to allow raising an exception?

@astrofrog

Copy link
Copy Markdown
Member Author

I think it would be safest to disable comparisons, just because the whole t[t['col'] > 2] is such a useful syntax that it will be easy to make mistakes. I don't feel strongly about this, so I'll let you decide.

@astrofrog

Copy link
Copy Markdown
Member Author

Interestingly this is not an issue in Python 3:

In [2]: class A(object):
   ...:     pass
   ...: 

In [3]: a = A()

In [4]: a > 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-6cf549916675> in <module>()
----> 1 a > 2

TypeError: unorderable types: A() > int()

Pull request will follow for Python 2

@astrofrog

Copy link
Copy Markdown
Member Author

The attached code disables inequality comparisons for Python 2 (they already are in Python 3). Note that Numpy structured arrays also have this 'feature':

In [4]: np.array(list(zip([1,2,3],[2,3,4])), dtype=[('a', float), ('b', float)]) > 1
Out[4]: True

but I think it will just lead to confusion.

Comment thread astropy/table/table.py Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@astrofrog: As you say this is already disabled on Python 3, is there any benefit to only defining these functions on Python 2?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good point - how would I go about doing this?

@astrofrog

Copy link
Copy Markdown
Member Author

@taldcroft @mdboom - does this look better?

@taldcroft

Copy link
Copy Markdown
Member

Looks fine to me.

@taldcroft

Copy link
Copy Markdown
Member

I changed my mind on __eq__ and __ne__. I think they should follow the behavior of numpy structured arrays, which is to give return the (in)equality of each row.

In [5]: t = Table.read([' a b c d',
                 ' 2 c 7.0 0',
                 ' 2 b 5.0 1',
                 ' 2 b 6.0 2',
                 ' 2 a 4.0 3',
                 ' 0 a 0.0 4',
                 ' 1 b 3.0 5',
                 ' 1 a 2.0 6',
                 ' 1 a 1.0 7',
                 ], format='ascii')
In [8]: t._data == t._data
Out[8]: array([ True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)

In [9]: t._data != t._data
Out[9]: array([False, False, False, False, False, False, False, False], dtype=bool)

So I think the Table.__eq__ should basically return self._data == other. Will that work?

@taldcroft

Copy link
Copy Markdown
Member
    def __eq__(self, other):
        if isinstance(other, Table):
            other = other._data
        return self._data == other

    def __ne__(self, other):
        if isinstance(other, Table):
            other = other._data
        return self._data != other

@mdboom

mdboom commented Sep 30, 2013

Copy link
Copy Markdown
Contributor

Looks good to me, and I agree with @taldcroft about __eq__ and __ne__.

@astrofrog

Copy link
Copy Markdown
Member Author

Ok, great! The above commits implement what @taldcroft was suggesting, so I think this is good to merge. However, I'll let @taldcroft check first.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add tests for comparing to a numpy structured array on the left and right sides? I assume this will work, but am not 100% sure.

t2._data == t
t2 == t._data

@astrofrog

Copy link
Copy Markdown
Member Author

@taldcroft - you're not going to believe this, it looks like there's a bug in numpy.ma ;)

In [75]: x = np.ma.MaskedArray([(2,),(2,)], dtype = [('a', '<i8')])

In [76]: y = np.array([(2,), (2,)], dtype=[('a', '<i8')])

In [77]: x == y
...
IndexError: arrays used as indices must be of integer (or boolean) type

Working on a workaround...

@taldcroft

Copy link
Copy Markdown
Member

@astrofrog - why am I not surprised...

@astrofrog

Copy link
Copy Markdown
Member Author

Well here's the best I can do. I'm stuck at the very last line in the test_table.py file because in that case t._data.__eq__ gets called and I have no control over that, and it bugs. The other way around, I was able to add a workaround. What do you think we should do? The problem is that __array_priority__ won't work because __array__ is defined (c.f. the whole issue with Quantity).

@astrofrog

Copy link
Copy Markdown
Member Author

Also, __eq__ is a little ugly as a result. Why, oh why did I even try testing the masked arrays.

Comment thread astropy/table/table.py

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

By the way this is needed because it won't work if you compare a masked to non-masked structured array.

@astrofrog

Copy link
Copy Markdown
Member Author

Failures on Python 2? That's what happens when you develop only in Python 3...

@taldcroft

Copy link
Copy Markdown
Member

It seems like there must be a way to simplify the logic in __eq__, but it's not a big deal and might make understanding the behavior even trickier. Otherwise it looks like this is good.

@astrofrog

Copy link
Copy Markdown
Member Author

Will try and simplify things :) What do you think we should do about the failing test?

@taldcroft

Copy link
Copy Markdown
Member

About the failed test, I would say to write this case as a known bug and leave it at that for now (and probably put in an astropy issue just so it doesn't get forgotten).

@ghost ghost assigned astrofrog Sep 30, 2013
@astrofrog

Copy link
Copy Markdown
Member Author

I tried simplifying the logic, but it's much more readable in its present form.

@taldcroft - if the tests pass, is this good to merge?

@taldcroft

Copy link
Copy Markdown
Member

Yes, good to merge.

astrofrog added a commit that referenced this pull request Sep 30, 2013
@astrofrog
astrofrog merged commit 14a4858 into astropy:master Sep 30, 2013
astrofrog added a commit that referenced this pull request Oct 24, 2013
…arisons

Table > value should not work
Conflicts:

	astropy/table/table.py
	astropy/table/tests/test_table.py
@astrofrog
astrofrog deleted the table-disallow-inequality-comparisons branch July 5, 2016 15:53
@eerovaher eerovaher mentioned this pull request Jan 24, 2024
1 task done
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.

3 participants