-
Notifications
You must be signed in to change notification settings - Fork 28
Patch flip #558
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
Patch flip #558
Conversation
WalkthroughAdds CoordManager.flip to reverse 1D coordinates (propagating to dependents), a proc-level flip(patch, *dims, flip_coords=True), exposes patch.flip, updates dispersion to use patch.flip("distance"), and adds tests for coord and patch flipping behaviors. Changes
Suggested labels
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used🧬 Code graph analysis (2)dascore/core/coordmanager.py (2)
tests/test_proc/test_basic.py (4)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
🔇 Additional comments (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #558 +/- ##
=======================================
Coverage 99.92% 99.92%
=======================================
Files 127 127
Lines 10586 10616 +30
=======================================
+ Hits 10578 10608 +30
Misses 8 8
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Docstrings generation was requested by @d-chambers. * #558 (comment) The following files were modified: * `dascore/core/coordmanager.py` * `dascore/proc/basic.py`
|
Note Generated docstrings for this pull request at #559 |
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.
Actionable comments posted: 1
🧹 Nitpick comments (8)
dascore/proc/basic.py (1)
758-791: Normalize dims, no-op fast-path, and clearer handling when dims is empty
- Deduplicate dims to avoid double-flipping a dimension.
- Fast-return when no dims and flip_coords is False to avoid unnecessary history churn.
- Guard np.flip when dims is empty (axis=()) to be explicit.
@patch_function() def flip(patch, *dims, flip_coords=True): @@ - axes = tuple(patch.get_axis(name) for name in dims) - data = np.flip(patch.data, axis=axes) - coords = patch.coords - if flip_coords: - coords = coords.flip(*dims) - return patch.new(data=data, coords=coords) + # drop duplicate dims, preserve first-seen order + dims = tuple(dict.fromkeys(dims)) + if not dims and not flip_coords: + return patch # no-op + axes = tuple(patch.get_axis(name) for name in dims) + data = np.flip(patch.data, axis=axes) if dims else patch.data + coords = patch.coords.flip(*dims) if flip_coords and dims else patch.coords + return patch.new(data=data, coords=coords)tests/test_proc/test_basic.py (1)
777-813: Augment flip tests to assert data reversal and double-flip identityAdd assertions that data actually reversed, and that double flip restores the original; also verify data reversal when flip_coords=False.
class TestFlip: @@ def test_no_coords(self, random_patch): """Ensure coord doesn't change with flip_coords=False""" flipped_patch = random_patch.flip("time", flip_coords=False) assert flipped_patch.get_coord("time") == random_patch.get_coord("time") + + def test_flip_reverses_data_time(self, random_patch): + axis = random_patch.get_axis("time") + out = random_patch.flip("time") + expected = np.flip(random_patch.data, axis=axis) + assert np.array_equal(out.data, expected) + + def test_double_flip_restores(self, random_patch): + out = random_patch.flip("time").flip("time") + assert random_patch.equals(out) + + def test_flip_coords_false_reverses_data_only(self, random_patch): + axis = random_patch.get_axis("time") + out = random_patch.flip("time", flip_coords=False) + assert np.array_equal(out.data, np.flip(random_patch.data, axis=axis)) + assert out.get_coord("time") == random_patch.get_coord("time")dascore/core/coordmanager.py (1)
1098-1120: Nit: avoid shadowing dims variable inside the loopdims is used as both the method’s argument and a local name for associated coord dims. Rename the local to assoc_dims for clarity.
- dims = dim_map[associated] - axis = dims.index(name) - out[associated] = (dims, _flip_coord(out[associated], axis)) + assoc_dims = dim_map[associated] + axis = assoc_dims.index(name) + out[associated] = (assoc_dims, _flip_coord(out[associated], axis))tests/test_core/test_coordmanager.py (5)
1355-1373: Assert immutability (flip should not mutate original CoordManager)Add a quick identity check to ensure a new instance is returned.
flipped_cm = cm.flip("time") # The flipped coordinate should be reversed flipped_time = flipped_cm.get_array("time") assert np.array_equal(flipped_time, original_time[::-1]) # Other coordinates should remain unchanged assert np.array_equal( flipped_cm.get_array("distance"), cm.get_array("distance") ) # Shape and dimensions should remain the same assert flipped_cm.shape == cm.shape assert flipped_cm.dims == cm.dims + # Should not mutate original object + assert flipped_cm is not cm
1393-1412: Also verify 2D associated coord flips along the targeted axisWhen flipping distance, 2D coords that include distance (e.g., quality with dims ("time","distance")) should reverse along that axis. Adding this assertion hardens coverage and would catch regressions from implementation refactors.
Note: Impl in dascore/core/coordmanager.py flips associated coords via dim_to_coord_map; a test on quality guards against variable shadowing in that method.
# Associated coordinates (like latitude) should also be flipped flipped_latitude = flipped_cm.get_array("latitude") assert np.array_equal(flipped_latitude, original_latitude[::-1]) # Time should remain unchanged assert np.array_equal(flipped_cm.get_array("time"), cm.get_array("time")) + + # 2D associated coordinate (quality) should be flipped along distance axis + q_before = cm.coord_map["quality"].values + q_after = flipped_cm.coord_map["quality"].values + assert np.array_equal(q_after, q_before[:, ::-1])
1374-1392: Strengthen multi-dim flip test by asserting 2D coord flips on both axesThis ensures quality reverses on time and distance when both dims are flipped.
flipped_cm = cm.flip("time", "distance") # Both coordinates should be reversed flipped_time = flipped_cm.get_array("time") flipped_distance = flipped_cm.get_array("distance") assert np.array_equal(flipped_time, original_time[::-1]) assert np.array_equal(flipped_distance, original_distance[::-1]) # Shape and dimensions should remain the same assert flipped_cm.shape == cm.shape assert flipped_cm.dims == cm.dims + + # And 2D coord should reverse on both axes + q0 = cm.coord_map["quality"].values + q1 = flipped_cm.coord_map["quality"].values + assert np.array_equal(q1, q0[::-1, ::-1])
1420-1426: Clarify semantics for flipping non‑dim 1D coords (e.g., 'latitude')Today, flip allows flipping any 1D coord, not just dims. Flipping a non‑dim coord alone will reverse it without touching its associated dim, which changes value‑to‑index alignment. If this is intended, make it explicit with a test; if not, consider raising CoordError for non‑dim inputs.
+ def test_flip_non_dim_coord_semantics(self, cm_multidim): + """Flipping a 1D non-dim coord reverses it without altering dims.""" + lat0 = cm_multidim.get_array("latitude") + dist0 = cm_multidim.get_array("distance") + out = cm_multidim.flip("latitude") + assert np.array_equal(out.get_array("latitude"), lat0[::-1]) + assert np.array_equal(out.get_array("distance"), dist0)Alternative: if undesired, assert it raises and adjust implementation accordingly.
1464-1477: Add a companion “flip all dims” test for associated coords (multidim fixture)The cm_basic case can’t validate associated coords. Consider an extra test using cm_multidim to confirm propagation when flipping all dims.
+ def test_flip_all_dimensions_propagates_to_associated(self, cm_multidim): + out = cm_multidim.flip(*cm_multidim.dims) + # latitude shares 'distance' -> should reverse + lat0 = cm_multidim.get_array("latitude") + assert np.array_equal(out.get_array("latitude"), lat0[::-1]) + # quality shares both -> reverse on both axes + q0 = cm_multidim.coord_map["quality"].values + q1 = out.coord_map["quality"].values + assert np.array_equal(q1, q0[::-1, ::-1])
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
dascore/core/coordmanager.py(2 hunks)dascore/core/patch.py(1 hunks)dascore/proc/basic.py(1 hunks)dascore/transform/dispersion.py(1 hunks)tests/test_core/test_coordmanager.py(1 hunks)tests/test_proc/test_basic.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
tests/test_proc/test_basic.py (5)
tests/test_core/test_coordmanager.py (1)
TestFlip(1347-1477)dascore/core/coordmanager.py (4)
flip(1084-1123)shape(793-799)get_array(1072-1074)get_coord(1039-1058)dascore/proc/basic.py (1)
flip(759-790)dascore/core/patch.py (4)
data(272-283)shape(286-299)dims(212-226)coords(255-269)dascore/proc/coords.py (2)
get_array(151-200)get_coord(96-148)
dascore/core/coordmanager.py (3)
dascore/utils/misc.py (1)
broadcast_for_index(137-158)dascore/core/coords.py (3)
ndim(468-470)get_coord(1515-1703)index(698-717)dascore/exceptions.py (1)
CoordError(38-39)
dascore/core/patch.py (2)
dascore/core/coordmanager.py (1)
flip(1084-1123)dascore/proc/basic.py (1)
flip(759-790)
dascore/proc/basic.py (4)
dascore/utils/patch.py (1)
patch_function(180-286)dascore/core/coordmanager.py (2)
flip(1084-1123)get_axis(756-771)dascore/core/patch.py (3)
dims(212-226)data(272-283)coords(255-269)dascore/proc/coords.py (1)
get_axis(787-806)
tests/test_core/test_coordmanager.py (5)
tests/test_proc/test_basic.py (1)
TestFlip(777-812)tests/conftest.py (2)
cm_basic(106-108)cm_multidim(129-139)dascore/core/coordmanager.py (4)
get_array(1072-1074)flip(1084-1123)shape(793-799)get_axis(756-771)dascore/exceptions.py (1)
CoordError(38-39)dascore/core/coords.py (1)
empty(679-696)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
- GitHub Check: test_code (ubuntu-latest, 3.13)
- GitHub Check: test_code (windows-latest, 3.11)
- GitHub Check: test_code (ubuntu-latest, 3.10)
- GitHub Check: test_code_min_deps (windows-latest, 3.12)
- GitHub Check: test_code (macos-latest, 3.12)
- GitHub Check: test_code (windows-latest, 3.13)
- GitHub Check: test_code (ubuntu-latest, 3.12)
- GitHub Check: test_code (windows-latest, 3.12)
- GitHub Check: test_code (ubuntu-latest, 3.11)
- GitHub Check: test_code (windows-latest, 3.10)
- GitHub Check: test_code (macos-latest, 3.10)
- GitHub Check: test_code (macos-latest, 3.11)
- GitHub Check: test_code_min_deps (windows-latest, 3.13)
- GitHub Check: Run benchmarks
- GitHub Check: test_code_min_deps (macos-latest, 3.12)
- GitHub Check: test_code_min_deps (ubuntu-latest, 3.12)
- GitHub Check: test_code_min_deps (ubuntu-latest, 3.13)
- GitHub Check: test_code_min_deps (macos-latest, 3.13)
🔇 Additional comments (3)
dascore/core/patch.py (1)
425-425: LGTM: public Patch.flip binding is consistent with other proc bindingsBinding flip alongside pad/roll/where maintains a uniform API surface. No issues.
dascore/transform/dispersion.py (1)
81-81: Doc example improvement: prefer patch.flip over manual reversalSwitching the left-sided example to use patch.flip("distance") improves clarity and reusability. Looks good.
tests/test_core/test_coordmanager.py (1)
1348-1353: Good addition: solid coverage of flip happy paths and errorsThe new TestFlip suite meaningfully exercises dim flips, propagation to associated coords, empty coords, and double‑flip invariants. LGTM overall.
Minor follow‑up: do we want to define behavior for duplicate dims passed to flip (e.g., flip("time", "time"))? Current impl will no‑op the duplicate; consider either deduping inputs or raising ParameterError for consistency with transpose tests.
CodSpeed Performance ReportMerging #558 will not alter performanceComparing Summary
|
Description
This PR implements the
Patch.flipmethod which just flips the underlying data, and optionally, the coordinates.Checklist
I have (if applicable):
Summary by CodeRabbit