Skip to content

refactor(api): Compare opentrons.types.Point with strict floating-point equality#18215

Merged
SyntaxColoring merged 2 commits intoedgefrom
strict_point_equality
May 2, 2025
Merged

refactor(api): Compare opentrons.types.Point with strict floating-point equality#18215
SyntaxColoring merged 2 commits intoedgefrom
strict_point_equality

Conversation

@SyntaxColoring
Copy link
Copy Markdown
Contributor

@SyntaxColoring SyntaxColoring commented Apr 30, 2025

Overview

For a long time, opentrons.types.Point has overridden its == operator to return True if the two points are numerically approximately equal to each other, instead of actually equal.

This was introduced in commit d13ed34 of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do a == b, I strongly expect that to mean actual equality—if I wanted approximation, I would have used isclose(). In other words, I expect point_a == point_b to behave exactly like (point_a.x == point_b.x) and (point_a.y == point_b.y) and (point_a.z == point_b.z).

Also, it breaks the rule that objects that compare equal must have the same hash value.

>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018

So this PR restores strict equality checking. The old behavior is preserved as an explicit method, point.elementwise_isclose(other), for the benefit of the few tests that were implicitly relying on it.

Test Plan and Hands on Testing

  • Analysis snapshot tests pass

Risk assessment

High. Point is used, uh, everywhere, and it's impossible for us to audit all the call sites of Point.__eq__ to determine if any of them were implicitly relying on the approximation.

Review requests

Is this actually a good idea?

@SyntaxColoring SyntaxColoring requested a review from a team as a code owner April 30, 2025 19:47
Copy link
Copy Markdown
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

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

oh yuck. support this

@SyntaxColoring SyntaxColoring merged commit 4250aab into edge May 2, 2025
30 checks passed
@SyntaxColoring SyntaxColoring deleted the strict_point_equality branch May 2, 2025 14:11
ddcc4 pushed a commit that referenced this pull request May 16, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 16, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 16, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 16, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 16, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 16, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 17, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 19, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 19, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 19, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 20, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 20, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 22, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 23, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 24, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 24, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 29, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 29, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
ddcc4 pushed a commit that referenced this pull request May 29, 2025
…oint equality (#18215)

For a long time, `opentrons.types.Point` has overridden its `==`
operator to return `True` if the two points are *numerically
approximately* equal to each other, instead of *actually* equal.

This was introduced in commit d13ed34
of PR #5583, possibly for the benefit of some calibration unit tests?

I personally find this very surprising. If I do `a == b`, I strongly
expect that to mean actual equality—if I wanted approximation, I would
have used `isclose()`. In other words, I expect `point_a == point_b` to
behave exactly like `(point_a.x == point_b.x) and (point_a.y ==
point_b.y) and (point_a.z == point_b.z)`.

Also, it breaks [the rule that objects that compare equal must have the
same hash
value](https://docs.python.org/3/reference/datamodel.html#object.__hash__).

```python
>>> a = Point()
>>> b = Point(z=1e-20)
>>> a == b
True
>>> hash(a)
3010437511937009226
>>> hash(b)
9180445109486892018
```

So this PR restores strict equality checking. The old behavior is
preserved as an explicit method, `point.elementwise_isclose(other)`, for
the benefit of the few tests that were implicitly relying on it.

(cherry picked from commit 4250aab)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants