-
Notifications
You must be signed in to change notification settings - Fork 300
Portable comparisons (for sorting) #1709
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
Conversation
lib/iris/coords.py
Outdated
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.
Does it even make sense to use the units or coordinate system in the comparison? I'm not even sure they're comparable. Should I leave them out?
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.
Also, thinking about it a bit, those first elements should ensure never comparing None with str, so maybe I can leave out those or ''?
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.
Does it even make sense to use the units or coordinate system in the comparison?
Yes - so we can have consistent (albeit arbitrary) ordering for coordinates which are not equal.
maybe I can leave out those
or ''?
👍
|
Oh, I forgot I added some usage of |
lib/iris/_merge.py
Outdated
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.
Could this if be replaced with return (axis_index, isinstance(name, int), str(name))?
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.
Yes, I think so; probably can leave out the str too for the same reason as above.
5277a33 to
184e165
Compare
|
I added one more sorting fix, 184e165. |
lib/iris/io/format_picker.py
Outdated
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.
Hmm, now that I think about it, this one may only work if names are unique? (because __eq__ still uses hash.)
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.
Agreed.
|
Maybe that will work better. |
|
So I've found two more comparison issues: I'm not sure what the expected value should be for these. In those two tests, some fields of the |
|
the tests that are failing are failing in the iris.coords the error is due to the fact that a mock object is being evaluated compared to an integer. this is because the tests provide a mocked version of the x_coord+name and _y_coord_name in the mock field most mock tests only use the parts of the PP field they require @QuLogic please may you be more specific when you say:
which expected values? for which 'these'? thank you |
|
The PP loader calls |
I see. Those metadata elements are not required for this test, the only important facet for setting the cell_methods for the lbproc codes is whether the grid is rotated or not, so I mocked out the behaviour with the _{x|y}_coord_name I'm afraid I don't understand the nature of the test failure. I can see that the we could make up a set of arbitrary values for the field to enable this test to pass, although this adds complexity to the test |
|
Perhaps this was happening all along but on Python 2 the comparison just returns Python 3: >>> from mock import MagicMock
>>> m = MagicMock()
>>> m > 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: MagicMock() > int()Python 2: >>> from mock import MagicMock
>>> m = MagicMock()
>>> m > 1
False |
|
Yes, that's correct; Python 2 sorts them arbitrarily. If the actual points don't really matter, how about just setting them to 0? |
I'm not sure that's true. The code from here onward has several conditions that depend on |
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.
We don't really want this list changing order ... that indicates a potential change in behaviour.
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.
The order comes from the FormatSpecification comparitor:
def __lt__(self, other):
if not isinstance(other, FormatSpecification):
return NotImplemented
return (-self.priority, hash(self)) < (-other.priority, hash(other))Eww 😱
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 the simplest solution is to tweak the definitions in lib/iris/fileformats/__init__.py to use unique numbers that preserve the current order?
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.
I assumed (perhaps incorrectly) that as long as they are at the same priority, it should not matter which one is ordered first. I don't think the tests have complained so far...
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.
Format specifications with the same priority should have mutually exclusive file matching criteria, in which case we would be able to get away with it. I'll check...
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.
Mostly they are mutually exclusive, but sadly not in the case of the ABF/L formats vs. the other "priority 3" formats. For example, a FieldsFile named "foo.abf" would load OK using the old order, but would try to load as an ABF file using the new order.
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.
NB. We really shouldn't be relying on consistent hash results anyway - e.g. http://bugs.python.org/issue13703.
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.
Given the minimal impact I suggest we just accept the change as it makes the order more predictable and controllable.
👍 Yes, that makes sense. Just as we don't really care about FWIW, I'd set |
Sometimes the name can be an int and sometimes a str, which are unsortable in Python 3. Emulate Python 2 behaviour for consistency.
This should allow consistent comparisons when some elements of the tuple are None. It's only used for sorting.
Again, an element may be None, so emulate Python 2 behaviour and sort that first.
This attribute is compared with 128 during parsing, but Mock is not comparable.
It doesn't make sense to use the hash of an object as a sort key since it turns out to be non-portable.
Again, an element may be None, so emulate Python 2 behaviour and sort that first.
4ba7cdb to
bc96904
Compare
|
Sorry for the delay; I needed to set a few of the ones you mentioned plus |
Portable comparisons (for sorting) in Py3.
There are a few mixed comparisons (
Nonewithint,strwithint, etc.) that do not work directly with Python 3. So add an extra element to the sorting key so that those comparisons do not occur (and work similar to Python 2).