Increase test coverage, improve docstrings, minor bug fixes - #13
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe changes raise the minimum Python version, refine numerical and masking behavior, update unit and operator handling, improve several constructors and operations, and add extensive tests for core types and extensions. ChangesCore behavior and API refinements
Test coverage
Estimated code review effort: 5 (Critical) | ~120 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #13 +/- ##
===========================================
+ Coverage 72.83% 96.11% +23.28%
===========================================
Files 24 24
Lines 7123 7207 +84
Branches 1599 1617 +18
===========================================
+ Hits 5188 6927 +1739
+ Misses 1497 162 -1335
+ Partials 438 118 -320 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
polymath/polynomial.py (4)
105-115:as_vectorreusesselfinstead of each derivative when building_derivsIn
as_vector, the recursive branch currently does:derivs = {} if recursive: for key, value in self._derivs.items(): derivs[key] = self.as_vector(recursive=False)This means every derivative entry ends up pointing at the same vectorized copy of
self, not the corresponding derivative polynomial (value). The resultingVectorhas incorrect derivative content.A minimal fix is to convert each derivative value instead:
- derivs = {} - if recursive: - for key, value in self._derivs.items(): - derivs[key] = self.as_vector(recursive=False) - - obj.insert_derivs(derivs) + derivs = {} + if recursive: + for key, value in self._derivs.items(): + # Preserve derivative structure but convert each Polynomial derivative + # to a plain Vector. + derivs[key] = value.as_vector(recursive=False) + + obj.insert_derivs(derivs)This keeps the existing API while making derivative propagation through
as_vectorlogically correct.
373-382:__mul__denominator handling and docstring are inconsistentThe docstring says a
ValueErroris raised “whenself._drank != arg._drankand both are non‑zero”, but the implementation raises whenever_drankdiffers, including mixing a denominator‐bearing polynomial with one that hasdrank == 0:if isinstance(arg, Polynomial): if self._drank != arg._drank: raise ValueError('incompatible denominators for multiply')Tests (
tests/test_polynomial.py,p_mul_drank1 *__mul__ p_mul_drank2) explicitly expect the error fordrank=1timesdrank=0, so behavior is fine; the docstring is now misleading.I’d suggest updating the docstring to match reality, e.g.:
- Raises: - ValueError: If the polynomials have incompatible denominators. This - occurs when self._drank != arg._drank and both are non-zero. For example, - a polynomial with drank=1 cannot be multiplied by a polynomial with - drank=2. + Raises: + ValueError: If the polynomials have incompatible denominators, i.e. + when ``self._drank != arg._drank``. Mixing polynomials with and + without denominators, or with different denominator ranks, is not + supported.
505-525:__pow__returns the original object for exponent 1 (aliasing)The repeated‑squaring implementation initializes
result = Noneand then:while power > 0: if power % 2 == 1: if result is None: result = base else: result = result * base base = base * base power //= 2For
arg == 1, this returnsresult is selfrather than a new Polynomial. That means callers who later mutate the result (e.g. via in‑place operators) will accidentally mutate the original polynomial, unlike thearg >= 2cases which always build new instances via*.If you want
p ** 1to behave like a pure expression, consider starting from an identity polynomial and always multiplying:- # Use repeated squaring algorithm - result = None + # Use repeated-squaring algorithm starting from the multiplicative identity + result = Polynomial([1.]) base = self power = int(arg)so that even
arg == 1returns a distinct object (1 * base) instead of aliasingself.
672-783:roots()doesn't account for_drankand will fail for polynomials with denominatorsThe higher-order
roots()logic (all-zeros detection, leading-zero shifts, companion matrix, and masking) hard-codes axis operations that assume the coefficient axis is at-1:all_zeros = np.all(coefficients == 0., axis=-1) shifts = (coefficients[..., 0] == 0.) coefficients[shifts, :-1] = coefficients[shifts, 1:] matrix[..., 0, :] = -coefficients[..., 1:] / coefficients[..., 0:1]However, the polynomial's
orderproperty reveals that the coefficient axis is actually at-self._drank - 1:return self.item[-self._drank - 1] - 1This means:
- When
_drank == 0: coefficient axis is at-1✓ (current code works)- When
_drank > 0: coefficient axis is at-2, -3, etc., but the code still uses-1✗ (indexes denominator axes instead)For polynomials with denominators, operations like
all_zeros = np.all(coefficients == 0., axis=-1)andshifts = (coefficients[..., 0] == 0.)will act on the wrong axes, causing shape mismatches, boolean indexing errors, or incorrect masking. The linear and quadratic cases useto_scalars()which correctly extracts coefficients via numerator indexing, but the higher-order path is broken. Tests coverroots()only for_drank == 0.Recommendation: Either explicitly disallow denominators with a check like
if self._drank: raise ValueError("Polynomial.roots() does not support denominators (drank > 0) yet"), or refactor to usecoef_axis = -self._drank - 1consistently throughout the higher-order implementation and add test coverage for_drank > 0.
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (2)
tests/test_matrix3.py (1)
664-666: Remove unused exception variablee.The exception handler assigns
as ebut never uses it.polymath/polynomial.py (1)
253-286: State recomputation duplicated between__iadd__and__isub__The manual state recomputation logic (lines 261-275) is duplicated in
__isub__(lines 335-349). As noted in a previous review, this is brittle and should be factored into a helper method.
There was a problem hiding this comment.
Actionable comments posted: 7
♻️ Duplicate comments (7)
polymath/polynomial.py (5)
812-817: Scalar duplicate detection may miss multiple duplicates.This was noted in a previous review. For scalar polynomials with triple roots or multiple duplicate pairs, the current logic breaks after detecting the first duplicate. If this is intentional (e.g., scalar polynomials are expected to have at most one duplicate pair), consider adding a comment to clarify this assumption.
253-287: State recomputation pattern is acceptable but consider Ruff's suggestion.The approach of using a temporary
Polynomialto compute invariants is reasonable. As a minor style improvement, consider using tuple unpacking as suggested by Ruff:- new_values = np.zeros(self._shape + (max_order+1,)) + new_values = np.zeros((*self._shape, max_order+1))
420-424: Minor style: prefer tuple unpacking for index construction.The indexing logic is correct. As a readability improvement per Ruff's RUF005 suggestion:
- self_indx = (Ellipsis, i) + suffix - arg_indx = (Ellipsis, j) + suffix - result_indx = (Ellipsis, k) + suffix + self_indx = (Ellipsis, i, *suffix) + arg_indx = (Ellipsis, j, *suffix) + result_indx = (Ellipsis, k, *suffix)
630-631: Replace assert with explicit error handling in production code.The
assert deriv.order == 0at line 631 could cause anAssertionErrorin production if a polynomial with non-zero order derivatives is passed. This was flagged in a previous review.- assert deriv.order == 0 + if deriv.order != 0: + raise ValueError('Derivative of constant polynomial must be constant')
666-668: Rename unused loop variablekto_k.The loop variable
kis not used within the loop body, as flagged by Ruff (B007).- for k in range(1, self.order): + for _k in range(1, self.order): x_power = x_power * x # Create new object, don't modify in place x_powers.append(x_power)tests/test_polynomial_basic.py (1)
102-103: Comment inconsistency with test polynomial.The comment mentions "y = 2x + 3" but the test constructs
Polynomial([3., 2.])which represents3x + 2. This was noted in a previous review.- # Derivative of inverse: if y = 2x + 3, then x = 0.5y - 1.5 - # If dy/dt = 2, then dx/dt = 0.5 * 2 = 1 + # Derivative of inverse: if y = 3x + 2, then x = (1/3)y - 2/3 # But we need to check the actual derivative structuretests/test_pair.py (1)
12-16: Consider replacing a singlerunTestwith focusedtest_*methodsThis mirrors earlier feedback: packing the entire Pair API coverage into one
runTestmakes failures harder to localize and limits pytest’s ability to select individual scenarios. Splitting into logically groupedtest_*methods (construction,as_pair,from_scalars,swapxy/rot90,angle,clip2d, etc.) would improve isolation and reporting, while keeping the actual assertions the same.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
polymath/pair.py(3 hunks)polymath/polynomial.py(16 hunks)polymath/vector3.py(12 hunks)tests/test_pair.py(1 hunks)tests/test_polynomial_arithmetic.py(1 hunks)tests/test_polynomial_basic.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
polymath/vector3.py (3)
polymath/extensions/math_ops.py (2)
len(75-78)zero(1791-1818)polymath/scalar.py (2)
Scalar(19-1892)as_scalar(77-103)polymath/qube.py (1)
Qube(11-3144)
polymath/pair.py (1)
polymath/qube.py (2)
Qube(11-3144)insert_deriv(1506-1572)
🪛 Ruff (0.14.7)
tests/test_pair.py
20-20: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
21-21: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
22-22: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
23-23: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
27-27: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
31-31: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
35-35: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
39-39: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
40-40: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
41-41: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
45-45: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
46-46: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
47-47: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
50-50: Use pytest.raises instead of unittest-style assertRaises
(PT027)
51-51: Use pytest.raises instead of unittest-style assertRaises
(PT027)
52-52: Use pytest.raises instead of unittest-style assertRaises
(PT027)
53-53: Use pytest.raises instead of unittest-style assertRaises
(PT027)
57-57: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
58-58: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
59-59: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
60-60: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
63-63: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
64-64: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
65-65: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
66-66: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
69-69: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
70-70: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
71-71: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
72-72: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
75-75: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
76-76: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
77-77: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
79-79: Use pytest.raises instead of unittest-style assertRaises
(PT027)
83-83: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
84-84: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
85-85: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
86-86: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
89-89: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
90-90: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
91-91: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
92-92: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
96-96: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
97-97: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
98-98: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
101-101: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
102-102: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
103-103: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
104-104: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
109-109: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
110-110: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
115-115: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
116-116: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
120-120: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
121-121: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
125-125: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
127-127: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
128-128: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
132-132: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
134-134: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
135-135: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
139-139: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
140-140: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
142-142: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
143-143: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
144-144: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
145-145: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
150-150: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
151-151: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
152-152: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
153-153: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
155-155: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
158-158: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
159-159: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
160-160: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
161-161: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
165-165: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
166-166: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
172-172: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
173-173: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
174-174: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
180-180: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
181-181: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
182-182: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
188-188: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
189-189: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
190-190: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
194-194: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
198-198: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
201-201: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
206-206: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
207-207: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
209-209: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
213-213: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
214-214: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
215-215: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
222-222: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
223-223: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
225-225: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
226-226: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
227-227: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
228-228: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
233-233: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
239-239: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
240-240: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
245-245: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
246-246: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
247-247: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
253-253: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
254-254: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
255-255: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
261-261: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
262-262: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
263-263: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
264-264: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
269-269: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
271-271: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
277-277: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
282-282: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
283-283: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
284-284: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
290-290: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
291-291: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
292-292: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
298-298: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
299-299: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
300-300: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
302-302: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
307-307: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
308-308: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
312-312: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
317-317: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
318-318: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
319-319: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
324-324: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
325-325: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
327-327: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
333-333: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
334-334: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
341-341: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
343-343: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
349-349: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
351-351: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
357-357: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
359-359: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
366-366: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
368-368: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
369-369: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
377-377: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
379-379: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
386-386: Use pytest.raises instead of unittest-style assertRaises
(PT027)
392-392: Use pytest.raises instead of unittest-style assertRaises
(PT027)
399-399: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
401-401: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
408-408: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
410-410: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
417-417: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
419-419: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
424-424: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
425-425: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
429-429: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
430-430: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
431-431: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
437-437: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
439-439: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
446-446: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
451-451: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
453-453: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
458-458: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
463-463: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
465-465: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
466-466: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
471-471: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
474-474: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
475-475: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
476-476: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
478-478: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
479-479: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
480-480: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
482-482: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
483-483: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
484-484: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
486-486: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
487-487: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
488-488: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
490-490: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
491-491: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
492-492: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
494-494: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
495-495: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
496-496: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
498-498: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
499-499: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
500-500: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
502-502: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
503-503: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
504-504: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
505-505: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
506-506: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
508-508: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
509-509: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
510-510: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
512-512: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
513-513: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
514-514: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
518-518: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
521-521: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
525-525: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
528-528: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
532-532: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
533-533: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
534-534: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
540-540: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
543-543: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
548-548: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
553-553: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
564-564: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
polymath/polynomial.py
259-259: Consider (*self._shape, max_order + 1) instead of concatenation
Replace with (*self._shape, max_order + 1)
(RUF005)
333-333: Consider (*self._shape, max_order + 1) instead of concatenation
Replace with (*self._shape, max_order + 1)
(RUF005)
420-420: Consider (Ellipsis, i, *suffix) instead of concatenation
Replace with (Ellipsis, i, *suffix)
(RUF005)
421-421: Consider (Ellipsis, j, *suffix) instead of concatenation
Replace with (Ellipsis, j, *suffix)
(RUF005)
422-422: Consider (Ellipsis, k, *suffix) instead of concatenation
Replace with (Ellipsis, k, *suffix)
(RUF005)
634-634: Consider (Ellipsis, 0, *deriv_tail) instead of concatenation
Replace with (Ellipsis, 0, *deriv_tail)
(RUF005)
644-645: Consider (Ellipsis, 0, *dvalue_tail) instead of concatenation
Replace with (Ellipsis, 0, *dvalue_tail)
(RUF005)
666-666: Loop control variable k not used within loop body
Rename unused k to _k
(B007)
797-797: Consider (k, *mask_indices) instead of concatenation
Replace with (k, *mask_indices)
(RUF005)
tests/test_polynomial_arithmetic.py
21-21: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
22-22: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
29-29: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
30-30: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
32-32: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
33-33: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
34-34: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
39-39: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
40-40: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
41-41: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
46-46: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
47-47: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
53-53: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
54-54: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
56-56: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
57-57: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
58-58: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
63-63: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
64-64: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
65-65: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
70-70: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
71-71: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
78-78: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
79-79: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
81-81: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
82-82: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
84-84: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
85-85: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
86-86: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
91-91: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
92-92: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
97-97: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
98-98: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
104-104: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
105-105: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
107-107: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
108-108: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
109-109: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
113-113: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
114-114: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
115-115: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
116-116: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
117-117: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
122-122: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
123-123: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
124-124: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
127-127: Use pytest.raises instead of unittest-style assertRaises
(PT027)
128-128: Use pytest.raises instead of unittest-style assertRaises
(PT027)
134-134: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
135-135: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
136-136: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
137-137: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
148-148: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
155-155: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
156-156: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
157-157: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
162-162: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
163-163: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
164-164: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
173-173: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
181-181: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
187-187: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
188-188: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
189-189: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
195-195: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
196-196: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
197-197: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
202-202: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
203-203: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
204-204: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
211-211: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
214-214: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
222-222: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
228-228: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
237-237: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
243-243: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
251-251: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
261-261: Use pytest.raises instead of unittest-style assertRaises
(PT027)
267-267: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
268-268: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
274-274: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
278-278: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
279-279: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
289-289: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
291-291: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
292-292: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
302-302: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
303-303: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
tests/test_polynomial_basic.py
22-22: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
23-23: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
24-24: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
29-29: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
30-30: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
34-34: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
37-37: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
40-40: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
44-44: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
45-45: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
50-50: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
51-51: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
56-56: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
57-57: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
62-62: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
63-63: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
65-65: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
66-66: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
68-68: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
69-69: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
74-74: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
75-75: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
80-80: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
81-81: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
85-85: Use pytest.raises instead of unittest-style assertRaises
(PT027)
91-91: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
93-93: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
94-94: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
101-101: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
105-105: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
109-109: Use pytest.raises instead of unittest-style assertRaises
(PT027)
115-115: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
121-121: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
122-122: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
123-123: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
125-125: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
127-127: Use a regular assert instead of unittest-style assertAlmostEqual
(PT009)
141-141: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
143-143: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
149-149: Use a regular assert instead of unittest-style assertFalse
Replace assertFalse(...) with assert ...
(PT009)
152-152: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
159-159: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
165-165: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
171-171: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
172-172: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
178-178: Use a regular assert instead of unittest-style assertTrue
Replace assertTrue(...) with assert ...
(PT009)
180-180: Use a regular assert instead of unittest-style assertEqual
Replace assertEqual(...) with assert ...
(PT009)
⏰ 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). (4)
- GitHub Check: Test polymath (windows-latest, 3.10)
- GitHub Check: Test polymath (macos-latest, 3.8)
- GitHub Check: Test polymath (windows-latest, 3.8)
- GitHub Check: Test polymath (macos-latest, 3.11)
🔇 Additional comments (6)
polymath/vector3.py (2)
41-47: LGTM! Excellent documentation improvements.The expanded docstrings significantly improve API clarity by specifying:
- Conversion behaviors and supported input forms
- Coordinate system conventions and angle ranges
- Return value semantics and units
- None-handling behavior
These enhancements align well with the PR's goal of improving documentation alongside test coverage.
Also applies to: 85-88, 133-146, 171-174, 191-205, 224-227, 245-246, 260-263, 303-307, 339-343
91-122: The unit compatibility concern in this review is incorrect. The implementation properly preserves units through theexampleparameter in thezero()method. Whenzero()callsobj.__init__(new_value, False, derivs={}, example=self), theQube.__init__method copies the unit from the example object (seeqube.pylines 202-203:if unit is None and self._UNITS_OK: unit = example._unit). Existing tests intest_vector3_basic.py(lines 187-194) confirm the implementation correctly handles complex cases like mixed None with Scalars that have denominators, which is more complex than unit preservation alone.polymath/polynomial.py (1)
528-542: LGTM!The repeated squaring algorithm is correctly implemented and provides efficient O(log n) multiplication operations for computing polynomial powers.
polymath/pair.py (2)
181-185: Correct fix for keyword-onlyrecursiveinrot90derivativesSwitching to
deriv.rot90(recursive=False)is necessary and sufficient here: the method’s signature is keyword‑only, and this now cleanly reuses the same rotation logic for derivatives without accidentally recursing their own derivs.
214-215:clip2dremaskdocstring now matches intentThe updated wording (“True to keep the mask; False to replace the values but make them unmasked”) is clearer and lines up with forwarding
remaskthrough toclip_componentwithout changing behavior.tests/test_pair.py (1)
203-215: Good coverage offrom_scalarswithNoneand n‑D denominatorsThese tests nicely pin down the intended behavior for
Pair.from_scalarswhen mixingScalarinputs with denominators andNone(including the all‑Nonecase). They should catch regressions in denominator propagation and zero‑filling semantics going forward.
There was a problem hiding this comment.
Actionable comments posted: 32
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (13)
polymath/extensions/pickler.py (1)
743-774: Lossiness note mentions impossiblereference == "double"valueThe new notes in
__getstate__/__setstate__say lossy compression occurs “e.g., whendigits < 16orreference != "double"”, but"double"is not a validreferenceoption (allowed values are e.g."fpzip","smallest", etc.). This is likely meant to refer to:
digits != "double"(or integer digits below full precision), and/orreference != "fpzip".Please correct the wording so it matches the actual
digits/referenceAPI and when fpzip is lossless vs lossy.Also applies to: 888-902
polymath/unit.py (2)
99-122:as_unitbehavior and errors unchanged but still returnKeyErrorSwitching to
Unit._NAME_TO_UNIT[arg]keeps behavior the same (still raisesKeyErrorfor unknown names even though the docstring saysValueError). If you want the docstring to be accurate, consider wrapping the lookup and raisingValueErrorinstead; otherwise, update the docstring to mentionKeyError.
529-553:mul_units/div_unitsignore thenameparameter and always clear namesThe new
Nonehandling is reasonable, butnameis now unused andresult.nameis always set toNone, so callers cannot assign a custom name even though the signature and docstring still advertise it.Either:
- Document that
nameis ignored and names are always derived automatically, or- Restore honoring
name(e.g., by callingresult.set_name(name)when provided).Right now the API surface is misleading.
Also applies to: 569-579
polymath/vector.py (2)
27-41: Minor docstring typo inVector.__init__
"arguments passd to the Qube constructor"should be"arguments passed to the Qube constructor".
619-645: Fix incorrect attribute access incross_product_as_matrix: use.shapeinstead of._shapeAt lines 630 and 644, the code incorrectly accesses
._shapeon NumPy arrays. Sinceself._valuesandnew_valuesare NumPy ndarrays, the correct attribute is.shape:Line 630:
old_values = np.rollaxis(self._values, -self._drank - 1, len(self._values.shape))Line 644:
new_values = np.rollaxis(new_values, -3, len(new_values.shape))This bug will raise
AttributeErrorwheneverself._drank > 0.polymath/extensions/vector_ops.py (1)
156-168: Simplify_zero_sized_resultloop/else structureThe
for-elseblockif isinstance(axis, (list, tuple)): for i in axis: indx[i] = 0 else: indx[i] = 0 else: indx[axis] = 0executes
indx[i] = 0twice for the lastiand makes the control flow harder to read. It’s equivalent to:if isinstance(axis, (list, tuple)): for i in axis: indx[i] = 0 else: indx[axis] = 0Consider removing the
for ... elseto avoid confusion.polymath/polynomial.py (4)
243-287:__iadd__bypasses unit checks and assumes_drank == 0for paddingThe in-place add currently:
- Pads
selfby allocatingnew_values = np.zeros(self._shape + (max_order+1,))and assigningnew_values[..., -self.order-1:] = self._values, which ignores any denominator axes; this only works safely when_drank == 0.- Combines units via
self._unit = self._unit or arg._unitwithout checking for compatibility, whereas__add__goes throughVector.__add__/Qube.__add__which enforce unit compatibility.To avoid silent inconsistencies:
- Either restrict
__iadd__to_drank == 0with an explicit check, or include_denomwhen formingnew_valuesand its indices.- Validate units as
Qube.__iadd__does, e.g. by performing the operation on the underlying Vectors and copying the result back, or by calling a helper that wraps the standard add logic instead of reimplementing it.As-is, you can add polynomials with incompatible units and (if denominators are ever non-zero) risk shape/indexing errors.
317-361:__isub__has the same unit and denominator-shape issues as__iadd__The in-place subtraction mirrors
__iadd__:
- Uses
new_values = np.zeros(self._shape + (max_order+1,))andnew_values[..., -self.order-1:] = self._values, ignoring denominator axes when_drank > 0.- Sets
self._unit = self._unit or arg._unitwithout checking compatibility.- Rebuilds derivatives via
_sub_derivs(self, arg)but bypasses any higher-level checks present inQube.__isub__.It should be refactored in tandem with
__iadd__to reuse a single helper that:
- Pads coefficients while respecting
_denomlayout, and- Delegates to the standard add/sub machinery (or at least reproduces its unit checks) before mutating
self.
363-428: Polynomial__mul__assumes no denominators in the result arrayThe convolution logic correctly identifies the coefficient axis on the inputs via:
coef_axis = -self._drank - 1 nself = self._values.shape[coef_axis_pos] narg = arg._values.shape[coef_axis_pos]but it builds
new_valuesas:new_values = np.zeros(new_shape + (new_order + 1,)) ... suffix = self._drank * (slice(None),) ... result_indx = (Ellipsis, k) + suffix new_values[result_indx] += self._values[self_indx] * arg._values[arg_indx]If
_drank > 0,suffixadds denominator slices thatnew_valuesdoesn’t have, so indexingnew_values[result_indx]will be inconsistent with its shape. You also only check_drankequality, not that denominator shapes match.If polynomials with denominators are supported,
new_valuesmust include_denomin its shape (and the indices adjusted accordingly). If they are not, consider asserting_drank == 0early to fail fast with a clear error instead of relying on incidental IndexErrors.
602-675: Zero-orderevalnow works but ignores broadcasting withxThe new
self.order == 0branch correctly extracts the constant coefficient and builds aScalarwith derivatives, fixing the old failure for constant polynomials.However, the result’s shape is determined solely from
self._values(viaconst_valuesandexample=self/self.wod) and does not depend onxat all. The docstring now states thatselfandxare broadcast together; that is true for higher-order polynomials (the dot-product path), but not for the constant case.If you want shape behavior to be uniform, consider broadcasting
const_valuesagainstx(e.g., viaScalar.as_scalar(x).broadcast_to(...)) or at least clarifying in the docstring that for order-zero polynomials the output shape is that of the polynomial, independent ofx.polymath/extensions/mask_ops.py (1)
43-47: Consider passingrecursivethroughas_this_type()for replacement values
mask_wherenow honors the caller’srecursivechoice for copies and remasking, but the replacement is still normalized via:replace = self.as_this_type(replace, recursive=True)Even though the final object is created with
copy(recursive=recursive), this forces the replacement value to carry all of its derivatives, regardless of the caller’s intent. Depending on how__setitem__is implemented, derivatives onreplacecould still influence behavior whenrecursive=False.To keep semantics fully consistent and easier to reason about, consider:
- if replace is not None: - replace = self.as_this_type(replace, recursive=True) + if replace is not None: + replace = self.as_this_type(replace, recursive=recursive)This way, a caller who explicitly opts out of recursive derivative handling gets a result built entirely from non‑recursive inputs.
Also applies to: 72-76
polymath/extensions/math_ops.py (1)
1211-1226: Fix__ipow__unit update: wrong arguments passed intoset_unit
__ipow__currently does:result = self ** arg self._set_values(result._values, result._mask) self.set_unit(self, result._unit)Given
Qube.set_unit(self, unit, *, override=False)and the snippet fromqube.py, this is problematic:
- The bound call
self.set_unit(self, result._unit)passes the instance as theunitargument andresult._unitasoverride, sounitis aQube, not aUnit/str/None.- Inside
set_unit,Unit.as_unit(unit)will see aQubeand raiseValueError("not a recognized unit: ..."), breaking in-place power for callers relying on this generic implementation.You likely just want to adopt the unit from
result. A minimal fix:- result = self ** arg - self._set_values(result._values, result._mask) - self.set_unit(self, result._unit) + result = self ** arg + self._set_values(result._values, result._mask) + self.set_unit(result._unit) return selfOptionally, you may also want to update the docstring “Returns: … after the modulus operation.” to say “after the exponentiation operation.”
polymath/quaternion.py (1)
254-273: Consider simplifying scalar pnorm handling.The handling of scalar vs array pnorm can be simplified using
np.atleast_1dor by always treating it as an array.- # Scale by sqrt(2) to eliminate need to keep multiplying by 2 - # Handle scalar pnorm case - if np.shape(pnorm) == (): - pnorm_array = np.array(pnorm) - else: - pnorm_array = pnorm - qvals = np.sqrt(2) / pnorm_array[..., np.newaxis] * pvals + # Scale by sqrt(2) to eliminate need to keep multiplying by 2 + qvals = np.sqrt(2) / np.atleast_1d(pnorm)[..., np.newaxis] * pvalsAlternatively,
np.asarray(pnorm)would also work since it handles both scalar and array inputs.
♻️ Duplicate comments (3)
polymath/vector3.py (1)
69-91:Vector3.from_scalarsNone-handling aligns with docs and denominator semanticsThe new logic:
- Treats all-None
(x, y, z)by creating threeScalar(0.)components.- For mixed-None, converts non-None args to Scalars, broadcasts them to a common denominator via
Qube.broadcast, and usesexample_scalar.zero()to generate matching zero-valued replacements.This matches the updated docstring and cleanly handles denominator shape inference.
Also applies to: 93-125
polymath/polynomial.py (1)
169-203:invert_linedouble-handles derivatives and applies the wrong transformThe coefficients
a_invand-b*a_invare built as Scalars with derivatives, soresult = Polynomial(Vector.from_scalars(a_inv, -b * a_inv))already carries the correct derivatives via chain rule.The subsequent block:
if recursive and self._derivs: for key, deriv in self._derivs.items(): result.insert_deriv(key, deriv.invert_line(recursive=False))overwrites those correct derivatives with
deriv.invert_line(...), which is not the derivative of the inverse map; it is the inverse of the derivative polynomial, a different operation.Recommendation: drop this loop and rely on the Scalar-based propagation:
- result = Polynomial(Vector.from_scalars(a_inv, -b * a_inv)) - - # Handle derivatives if recursive - if recursive and self._derivs: - for key, deriv in self._derivs.items(): - result.insert_deriv(key, deriv.invert_line(recursive=False)) - - return result + return Polynomial(Vector.from_scalars(a_inv, -b * a_inv))This keeps
invert_linemathematically correct and avoids conflicting derivative definitions.tests/test_polynomial_basic.py (1)
96-106:invert_linederivative test doesn’t validate numerical behaviorThis test only asserts that
p_inv_with_deriv.d_dtexists and is aPolynomial, but not that its coefficients are correct. Given the complexity ofinvert_line’s derivative handling, it would be safer to assert expected coefficients explicitly (e.g., via a hand-derived chain-rule expression) and fix the inline comment to describe the actual polynomial (3x + 2).Stronger assertions here would have caught the current derivative bug in
invert_line.
There was a problem hiding this comment.
Actionable comments posted: 21
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
polymath/matrix.py (2)
34-58: Matrix.as_matrix ignoresrecursivefor Vector inputs
Matrix.as_matrix(v, recursive=False)currently callsv.join_items([Matrix])without usingrecursive, so derivatives on aVectorwithdrank == 1will still be present on the resultingMatrix. New tests intests/test_matrix_misc.pyexpect derivatives to be dropped whenrecursive=False.To align behavior with the docstring and tests, consider:
@staticmethod def as_matrix(arg, *, recursive=True): @@ - if isinstance(arg, Qube): - - # Convert a Vector with drank=1 to a Matrix - if isinstance(arg, Vector) and arg._drank == 1: - return arg.join_items([Matrix]) - - arg = Matrix(arg._values, arg._mask, example=arg) - return arg if recursive else arg.wod + if isinstance(arg, Qube): + + # Convert a Vector with drank=1 to a Matrix + if isinstance(arg, Vector) and arg._drank == 1: + result = arg.join_items([Matrix]) + return result if recursive else result.wod + + arg = Matrix(arg._values, arg._mask, example=arg) + return arg if recursive else arg.wod
177-232: from_scalars shape/size validation andrecursivehandling look correctThe updated
from_scalarslogic (usingshape[0] * shape[1]and passingrecursivethrough toreshape_numer) is consistent withQube.reshape_numersemantics and the new tests. One small style tweak that addresses the Ruff hint would be:- return vector.reshape_numer(shape, list(classes) + [Matrix], recursive=recursive) + return vector.reshape_numer(shape, [*list(classes), Matrix], recursive=recursive)Functionally, though, this block is solid as-is.
polymath/extensions/vector_ops.py (2)
148-169: Clarify axis validation contract for_zero_sized_result
_zero_sized_resultassumesaxis(int or sequence) indexesself._ndims * [slice(None)]directly, including negative indices. That’s safe as long as callers always run_check_axis(or equivalent) first, but this is not enforced here. It would help future maintainers if the docstring explicitly stated thataxismust already be validated (e.g., via_check_axis), or, alternatively, if_zero_sized_resultcalled_check_axisitself for the non-Nonecase.
524-575: Consider adding return type hints and tightening error reporting in_cross_3x3/_cross_2x2The new private helpers are clear and nicely documented. Two small polish items you might consider:
- Add return type annotations (
-> np.ndarray) to_cross_3x3and_cross_2x2to help static analysis and IDEs.- The
ValueErrormessages are fine, but if you ever wrap them, useraise ... from Noneto avoid noisy tracebacks from internal broadcasting/shape logic.Both are non-functional, optional cleanups that align with the Ruff ANN202/TRY003 hints.
♻️ Duplicate comments (9)
polymath/matrix3.py (1)
837-837: Experimental methods appropriately marked.These experimental
__getstate__and__setstate__methods are correctly marked withpragma: no cover. The static analysis hint about missing return type annotations (ANN202) can be deferred since these are experimental and not part of the public API.Also applies to: 879-879
polymath/extensions/math_ops.py (1)
380-383: Docstring correctly documentsas_scalar()coercion for multiplication.The docstring accurately reflects the implementation at line 398 which uses
Qube._SCALAR_CLASS.as_scalar(arg)for non-Qube arguments.tests/test_qube_unit.py (1)
277-315: The derivative conversion comments could be clearer.At lines 304-307, the comments describe the derivative conversions. The test at line 305 expects
(400000, 500000, 600000)forda_dtwhich hasunit=Unit.CM/Unit.S. The internal values are in standard units (km/s), so converting to cm/s involves multiplying by 100000. This matches the expected values.However, the comment "CM/S to M/S" at line 304 is slightly confusing since the unit is
CM/S, not converting fromCM/StoM/S. Consider clarifying that this is converting from standard units (km/s) to the declared unit (cm/s).tests/test_polynomial_basic.py (1)
96-105: Invert-line derivative helper polynomial/comment are inconsistent with the linear polynomialHere
p_linear_with_derivisPolynomial([3., 2.])(3x + 2), butp_linear_deriv = Polynomial([1., 0.])and the comment claim a derivative of 2. For 3x + 2, the derivative should be the constant 3 (e.g.,Polynomial([3.])under your coefficient convention).Tests currently only check that a derivative Polynomial exists, so behavior is unaffected, but this mismatch is confusing. Consider updating either the polynomial or the comment (and ideally adding a small numeric check) so they describe the same derivative.
tests/test_qube_ext_item_ops.py (1)
491-529: Strengthenchaintests with numeric assertionsThe
chaincoverage currently verifies shape,numer, anddenom, but never checks the actual numeric result of the dot-product-like operation. That leaves the core math logic unverified.Consider adding at least one small example where you assert
c.values(or a slice) equals a hand-computed result, so changes to the chaining multiplication can’t silently pass as long as shapes stay the same.polymath/extensions/pickler.py (1)
295-321: Simplify_validate_pickle_referenceerror handling and align with_validate_pickle_digitsThe function still does an inner
raise ValueError(...)inside the loop and then catchesValueErrorin the outerexceptjust to raise a secondValueErrorbased onoriginal_references. That indirection isn’t buying much and makes the control flow harder to follow, especially now that you preserve the original input in the outer message.You can keep behavior and satisfy Ruff’s TRY/B904 hints by removing the inner raise and letting invalid values fall through to the outer
except, e.g.:def _validate_pickle_reference(references): @@ - try: - references = references[:2] - for reference in references[:2]: - if isinstance(reference, numbers.Real): - pass - elif reference not in {'smallest', 'largest', 'mean', 'median', 'logmean', - 'fpzip'}: - raise ValueError(f'invalid pickle reference {reference!r}') - - except (ValueError, IndexError, TypeError): - raise ValueError(f'invalid pickle reference {original_references!r}') + try: + references = references[:2] + for reference in references: + if isinstance(reference, numbers.Real): + continue + if reference not in {'smallest', 'largest', 'mean', 'median', 'logmean', + 'fpzip'}: + raise TypeError # trigger outer handler + except (IndexError, TypeError): + raise ValueError( + f'invalid pickle reference {original_references!r}' + ) from None(or similar, e.g., by factoring the loop into a small helper). This keeps the external exception and message while simplifying the control flow.
tests/test_qube_coverage.py (1)
679-687: Prefer-builtin toggles now correctly guarded with try/finallyThe
Qube.prefer_builtins()state is saved and restored viatry/finallyin both theas_bool(Lines 679–687) andas_int(Lines 1420–1428) tests, so failures in the body no longer leak the global preference into later tests. This addresses the earlier global-state concern around these toggles.Also applies to: 1420-1428
tests/test_qube_ext_vector_ops.py (1)
13-318: Unittest-centric style is fine; handle assertion-style linting via configuration insteadThis module does a thorough job exercising vector ops (dot/norm/norm_sq/cross/outer/as_diagonal, reductions, and derivative propagation). Given it’s explicitly written as a
unittest.TestCasewith a largerunTest, I’d keep theself.assert*/assertRaisesstyle rather than rewriting to plainassert/pytest.raisesjust to satisfy assertion-style lint rules. If those rules are noisy here, it’s cleaner to relax or silence them for this file (or for unittest-based tests in general) instead of mixing styles.Also applies to: 323-842
tests/test_qube_ext_pickler.py (1)
13-1219: Consider splitting this monolithicrunTestinto smaller, focused testsThis
runTestmethod covers a huge number of distinct behaviors: per-instance vs default pickle digits, reference handling, float/int/bool encodings, fpzip paths, constant/items encodings, mask encodings (ALL_MASKED/CORNERS/ANTIMASKED/etc.), derivative round-trips, readonly flags, invalid encodings, and more. It’s great for coverage, but any failure will be hard to localize, and evolving pickler internals will make this method increasingly brittle.You’d get more maintainable signal by splitting into multiple test methods or even multiple
TestCaseclasses grouped by concern (e.g., configuration/digits, float encodings, mask encodings, fpzip paths, invalid encodings). The logic won’t change, but failures will be easier to diagnose and future contributors will find it easier to extend.
There was a problem hiding this comment.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
polymath/extensions/vector_ops.py (1)
525-551: LGTM!The rename to
_cross_3x3correctly signals this is an internal helper, and the updated docstring clearly documents its purpose.For consistency with type-annotated codebases, consider adding return type:
-def _cross_3x3(a, b): +def _cross_3x3(a, b) -> np.ndarray:
♻️ Duplicate comments (6)
polymath/polynomial.py (2)
813-813: Apply tuple unpacking for index construction (style consistency).Per Ruff RUF005, use tuple unpacking instead of concatenation:
- root_mask[(k,) + mask_indices] = True + root_mask[(k, *mask_indices)] = True
192-203: Remove incorrect derivative handling—Scalar arithmetic already propagates derivatives correctly.The loop at lines 199-201 that calls
deriv.invert_line(recursive=False)is mathematically incorrect and redundant:
Automatic propagation:
to_scalars(recursive=recursive)returnsaandbwith their derivatives attached, and the Scalar operations1./aand-b * a_invat lines 194-195 already apply the chain rule to propagate derivatives into the inverted coefficients.Incorrect transformation: Calling
invert_line()on the derivative polynomial is not the correct derivative of the inverse. For the inverse transformation x = (y - b)/a, the derivative is dx/dt = (dy/dt · a - (y-b) · da/dt) / a², notinvert_line(dy/dt).Overwrites correct result: The loop overwrites the automatically-propagated (correct) derivatives with an incorrect transformation.
Remove the derivative loop entirely:
(a, b) = self.to_scalars(recursive=recursive) a_inv = 1. / a result = Polynomial(Vector.from_scalars(a_inv, -b * a_inv)) - # Handle derivatives if recursive - # XXX Code Rabbit claims that this math is not correct - check it - if recursive and self._derivs: - for key, deriv in self._derivs.items(): - result.insert_deriv(key, deriv.invert_line(recursive=False)) - return resultThe
recursiveparameter into_scalarsalready ensures derivatives are handled correctly through Scalar arithmetic.tests/test_qube_ext_shrinker.py (1)
13-754: Break up the monolithicrunTestand avoid line‑number‑based comments.This single
runTestmixes many independent behaviors (basic shrink/unshrink round‑trips, cache flags, all‑masked cases, broadcast paths, derivative propagation, internal_is_array/_is_scalartricks). It’s very hard to localize a failure and some comments still refer to specific lines inshrinker.py(e.g., “lines 63–65”, “lines 173–174”), which will go stale when that file changes.Consider:
- Splitting this into focused test methods (e.g.,
test_basic_shrink,test_unshrink_cache_flags,test_broadcasting_paths,test_all_masked,test_derivatives_and_nested_derivatives), and- Rephrasing implementation‑detail comments to describe semantic conditions (“antimask has more dimensions than self and triggers broadcast_to”, “all selected mask is True so shrink returns masked_single”) and asserting those behaviors directly (shapes, masks, readonly flags), instead of relying on line numbers for coverage mapping.
This will keep the coverage intent but make the suite more maintainable as
shrinker.pyevolves.tests/test_qube_coverage.py (1)
93-139: Tighten private‑helper tests that currently “may or may not raise”.Blocks like:
_as_mask(object(), opstr='test'),_as_mask([1,2,3], opstr='test') # Not boolean,_suitable_mask([True, False], shape=(2,), opstr='test'),_suitable_numer('invalid', opstr='test'),are wrapped in
try/exceptwith comments such as “may or may not raise” and no assertion beyondpassin theexcept. This means they don’t fail even if behavior flips (e.g., from raising to silently accepting bad input).Where the intent is to verify an error path, assert the specific exception with
with self.assertRaises(...). If behavior is genuinely undefined and you only want coverage, consider deleting the block or documenting and asserting the behavior you actually support instead of “may or may not raise”.Also applies to: 149-172
tests/test_qube_ext_pickler.py (2)
679-693: Duplicate test block - consider removing.This block (lines 679-693) is identical to lines 422-439, testing the same
_PICKLE_DEBUGfunctionality. A third similar test exists at lines 1060-1078 using direct module access.Consider keeping only one comprehensive test for
_PICKLE_DEBUGfunctionality and removing the duplicates to improve maintainability.
15-17: Consider splitting the monolithic test method in a follow-up.The single
runTestmethod spans ~1200 lines and mixes many concerns. While this provides good coverage for the PR's goals, splitting into focused test methods (e.g.,test_pickle_digits_config,test_float_encodings,test_mask_encodings,test_error_paths) would improve failure diagnostics and maintainability.This is a recommended refactor for a follow-up, not a blocker for this PR.
|
@CodeRabbit summary |
✅ Actions performedSummary regeneration triggered. |
|
@CodeRabbit summary |
✅ Actions performedSummary regeneration triggered. |
polymath/extensions/vector_ops.py: - Drop the dead "# obj = arg" comment from the unreachable branch. - Chain the re-raised IndexError in _check_axis with "from e" so the original traceback is preserved. tests/test_qube_coverage.py: - Define NoDerivsQube once at module scope instead of duplicating it in two tests. tests/test_scalar_comprehensive.py: - Assert the full mask and values of int(top=3, remask=True) rather than a weak "mask[3] or mask[4]", and cover inclusive=False as well. tests/test_scalar_coverage.py: - Replace naked "try/except: pass" blocks with assertRaises so a missing exception fails the test, and convert the existing try/self.fail blocks to the same form. - Four blocks asserted nothing because their expectation was wrong; they now assert verified behavior: argmax/argmin/median on an empty Scalar return shape (0,) rather than raising, sort() does raise IndexError, 0 ** -1 masks rather than raising, and an overflowing ** masks elementwise. - as_scalar() on a Vector always raises, so its success branch was dead. tests/test_vector_reciprocal.py: - Loosen the round-trip tolerance from 1e-13 to 1e-12. np.linalg.inv() gives a bit-identical error on the same seeded data, so the assertion was measuring float64 round-off on an ill-conditioned draw. Full suite: 115 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/test_scalar_coverage.py`:
- Around line 327-330: Update Scalar.exp() to catch RuntimeWarning from NumPy
overflow and convert it to ValueError, matching the behavior of other scalar
math methods and its documented contract. Then change the overflow test in
test_scalar_coverage.py to assert ValueError only.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a396e76a-bd31-49fe-82af-8328583f61a6
📒 Files selected for processing (5)
polymath/extensions/vector_ops.pytests/test_qube_coverage.pytests/test_scalar_comprehensive.pytests/test_scalar_coverage.pytests/test_vector_reciprocal.py
| # The overflow surfaces as the RuntimeWarning raised by np.exp, unless it is | ||
| # first converted to a ValueError by Scalar.exp() itself | ||
| with self.assertRaises((ValueError, RuntimeWarning)): | ||
| _ = a.exp(check=False) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Compare the except clauses in the check=False branches of Scalar math methods.
rg -n -B 6 -A 2 'raise ValueError\(.Scalar\.(exp|sqrt|log|arcsin|arccos)\(\)' polymath/scalar.pyRepository: SETI/rms-polymath
Length of output: 3861
🏁 Script executed:
#!/bin/bash
# Inspect the Scalar.exp() implementation and the related test assertions around the reported lines.
set -euo pipefail
printf '--- scalar.py exp/docstring lines ---\n'
sed -n '698,732p' polymath/scalar.py | cat -n -v
printf '\n--- test_scalar_coverage.py relevant lines ---\n'
sed -n '318,335p' tests/test_scalar_coverage.py | cat -n -v
sed -n '912,924p' tests/test_scalar_coverage.py | cat -n -v
printf '\n--- deterministic probe of NumPy warning semantics (without running repo code) ---\n'
python3 - <<'PY'
import warnings
try:
import numpy as np
except Exception as e:
print('numpy_unavailable:', type(e).__name__, e)
else:
with warnings.catch_warnings():
warnings.filterwarnings('error')
try:
x = np.exp(np.asarray([1e400]))
print('result:', x, x.dtype)
except Exception as exc:
print('exception_type:', type(exc).__name__, 'message:', str(exc))
PYRepository: SETI/rms-polymath
Length of output: 246
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- scalar.py exp/docstring lines ---'
sed -n '698,732p' polymath/scalar.py | cat -n -v
printf '%s\n' ''
printf '%s\n' '--- test_scalar_coverage.py relevant lines ---'
sed -n '318,335p' tests/test_scalar_coverage.py | cat -n -v
sed -n '912,924p' tests/test_scalar_coverage.py | cat -n -v
printf '%s\n' ''
printf '%s\n' '--- deterministic probe of NumPy warning semantics ---'
python3 - <<'PY'
try:
import numpy as np
except Exception as e:
print('numpy_unavailable:', type(e).__name__, e)
else:
with warnings.catch_warnings():
warnings.filterwarnings('error')
try:
x = np.exp(np.asarray([1e400]))
print('result:', x, x.dtype)
except Exception as exc:
print('exception_type:', type(exc).__name__, 'message:', str(exc))
PYRepository: SETI/rms-polymath
Length of output: 3381
Catch RuntimeWarning in Scalar.exp() so overflow raises ValueError.
Scalar.exp(check=False) documents that overflow raises ValueError, but NumPy emits RuntimeWarning on overflow and warnings.filterwarnings('error') converts that to RuntimeWarning because Scalar.exp() only catches (ValueError, TypeError). Catch RuntimeWarning there and raise ValueError like the other scalar math methods do, then update the test to assert ValueError only.
🧰 Tools
🪛 Ruff (0.16.1)
[warning] 329-329: Use pytest.raises instead of unittest-style assertRaises
Replace assertRaises with pytest.raises
(PT027)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/test_scalar_coverage.py` around lines 327 - 330, Update Scalar.exp() to
catch RuntimeWarning from NumPy overflow and convert it to ValueError, matching
the behavior of other scalar math methods and its documented contract. Then
change the overflow test in test_scalar_coverage.py to assert ValueError only.
markshowalter
left a comment
There was a problem hiding this comment.
I addressed a couple of final CodeRabbit issues. Approved.
Overview
This PR makes a massive improvement to test coverage (from 73% to 97%), clarifies docstrings, and fixes a number of minor bugs that were found along the way.
The new test coverage is:
All of the changes need to be carefully reviewed, especially the changes to the code to fix apparent bugs. In some cases the intent of the code was not clear, and in other cases it just appeared to be incorrect. It is entirely possible that some of the fixes are not correct!
Per-File Change Summary
extensions/__init__.py__matmul__was missing from the copying operators, meaning that the@operator could never work.extensions/item_ops.pyextensions/mask_ops.pymask_where, the docstring description ofrecursivedoes not agree with the normal meaning throughout the rest of the code. Please verify the new meaning and the code changes to make it work.extensions/math_ops.pyas_this_typeand a group that usesas_scalar. This code hasn't changed (although the docstrings have been clarified). Please make sure this is the desired behavior.extensions/pickler.pyf. This happened several time in the code base.extensions/shrinker.pyextensions/tvl.pytvl_andandtvl_ordid not fully document the truth table. The actual code seemed to have some subtle errors in it with masks. Please check the rewritten versions carefully.extensions/vector_ops.pycross_2x2andcross_3x3internal functions.matrix.pyfrom_scalar.matrix3.pypoly_rotationhad a bad zero argument tonp.stack.__imul__called_set_valueswith a badexampleargument.from_eulerandto_eulerdid not work with a tuple of axes becauselowerwas called on the tuple before it was detected.pair.pyfrom_scalarsclaimed to supportNonearguments but didn't.rot90needed to passrecursiveas a named argument.polynomial.pyinvert_lineis highly questionable and needs to be validated.__iadd__and__isub__this is not valid Python:self.super().__iadd__(arg.super()). Cursor wrote a fix to handle polynomials of different order, but it needs to be validated and there's probably a way to simplify it.__sub__and__rsub__this is not valid Python:return Polynomial(self.super() - arg.super())and was replaced withPolynomial(self.as_vector() - arg.as_vector()).__mul__had some problems and was rewritten.__pow__did not work at all and was rewritten.__eval__androotshad a lot of issues and were significantly changed.quaternion.pyto_matrix3didn't support scalar pnorms.from_eulerdid not work with a tuple of axes becauselowerwas called on the tuple before it was detected.qube.py_suitable_dtypemissingfstring prefix.delete_derivesmodified a dict that was being iterated over.without_unitdidn't remove units from derivatives.as_floatcalled__copy__with arecursiveparameter but that parameter is not supported by__copy__.as_size_zerowas not operating properly with scalars.scalar.pysortdid not properly replace masked values with the maximum.unit.pymul_unitsanddiv_units. I really did not understand these methods. There is an argumentnamethat was ignored entirely. If a new unit was created, its name was set toNone, but if one of the original units was returned, it kept its name. I cleaned up the logic and made it set the new unit's name toname, but the overall intent of this function needs to be verified.name_to_dictwraps parsing in at 99,999 characters in a way that can't possibly work. I don't understand the purpose of the wrap. If it's a limit, we should just throw an exception. This code needs to be verified.vector.pyvector3.pyfrom_scalarsclaimed to supportNonearguments but didn't. Same aspair.py.pyproject.tomlNew Test Files
Summary by CodeRabbit
Python Version Update
New Features
Public API
into_unitnow requires keyword-only options.Bug Fixes / Behavior
Documentation
Tests